1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #define NETDISSECT_REWORKED
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <tcpdump-stdinc.h>
28 
29 #include <string.h>
30 
31 #include "interface.h"
32 #include "addrtoname.h"
33 #include "extract.h"			/* must come after interface.h */
34 
35 #include "ip.h"
36 #include "ipproto.h"
37 
38 static const char tstr[] = "[|ip]";
39 
40 static const struct tok ip_option_values[] = {
41     { IPOPT_EOL, "EOL" },
42     { IPOPT_NOP, "NOP" },
43     { IPOPT_TS, "timestamp" },
44     { IPOPT_SECURITY, "security" },
45     { IPOPT_RR, "RR" },
46     { IPOPT_SSRR, "SSRR" },
47     { IPOPT_LSRR, "LSRR" },
48     { IPOPT_RA, "RA" },
49     { IPOPT_RFC1393, "traceroute" },
50     { 0, NULL }
51 };
52 
53 /*
54  * print the recorded route in an IP RR, LSRR or SSRR option.
55  */
56 static void
ip_printroute(netdissect_options * ndo,register const u_char * cp,u_int length)57 ip_printroute(netdissect_options *ndo,
58               register const u_char *cp, u_int length)
59 {
60 	register u_int ptr;
61 	register u_int len;
62 
63 	if (length < 3) {
64 		ND_PRINT((ndo, " [bad length %u]", length));
65 		return;
66 	}
67 	if ((length + 1) & 3)
68 		ND_PRINT((ndo, " [bad length %u]", length));
69 	ptr = cp[2] - 1;
70 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
71 		ND_PRINT((ndo, " [bad ptr %u]", cp[2]));
72 
73 	for (len = 3; len < length; len += 4) {
74 		ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len])));
75 		if (ptr > len)
76 			ND_PRINT((ndo, ","));
77 	}
78 }
79 
80 /*
81  * If source-routing is present and valid, return the final destination.
82  * Otherwise, return IP destination.
83  *
84  * This is used for UDP and TCP pseudo-header in the checksum
85  * calculation.
86  */
87 static uint32_t
ip_finddst(netdissect_options * ndo,const struct ip * ip)88 ip_finddst(netdissect_options *ndo,
89            const struct ip *ip)
90 {
91 	int length;
92 	int len;
93 	const u_char *cp;
94 	uint32_t retval;
95 
96 	cp = (const u_char *)(ip + 1);
97 	length = (IP_HL(ip) << 2) - sizeof(struct ip);
98 
99 	for (; length > 0; cp += len, length -= len) {
100 		int tt;
101 
102 		ND_TCHECK(*cp);
103 		tt = *cp;
104 		if (tt == IPOPT_EOL)
105 			break;
106 		else if (tt == IPOPT_NOP)
107 			len = 1;
108 		else {
109 			ND_TCHECK(cp[1]);
110 			len = cp[1];
111 			if (len < 2)
112 				break;
113 		}
114 		ND_TCHECK2(*cp, len);
115 		switch (tt) {
116 
117 		case IPOPT_SSRR:
118 		case IPOPT_LSRR:
119 			if (len < 7)
120 				break;
121 			UNALIGNED_MEMCPY(&retval, cp + len - 4, 4);
122 			return retval;
123 		}
124 	}
125 trunc:
126 	UNALIGNED_MEMCPY(&retval, &ip->ip_dst.s_addr, sizeof(uint32_t));
127 	return retval;
128 }
129 
130 /*
131  * Compute a V4-style checksum by building a pseudoheader.
132  */
133 int
nextproto4_cksum(netdissect_options * ndo,const struct ip * ip,const uint8_t * data,u_int len,u_int covlen,u_int next_proto)134 nextproto4_cksum(netdissect_options *ndo,
135                  const struct ip *ip, const uint8_t *data,
136                  u_int len, u_int covlen, u_int next_proto)
137 {
138 	struct phdr {
139 		uint32_t src;
140 		uint32_t dst;
141 		u_char mbz;
142 		u_char proto;
143 		uint16_t len;
144 	} ph;
145 	struct cksum_vec vec[2];
146 
147 	/* pseudo-header.. */
148 	ph.len = htons((uint16_t)len);
149 	ph.mbz = 0;
150 	ph.proto = next_proto;
151 	UNALIGNED_MEMCPY(&ph.src, &ip->ip_src.s_addr, sizeof(uint32_t));
152 	if (IP_HL(ip) == 5)
153 		UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst.s_addr, sizeof(uint32_t));
154 	else
155 		ph.dst = ip_finddst(ndo, ip);
156 
157 	vec[0].ptr = (const uint8_t *)(void *)&ph;
158 	vec[0].len = sizeof(ph);
159 	vec[1].ptr = data;
160 	vec[1].len = covlen;
161 	return (in_cksum(vec, 2));
162 }
163 
164 static void
ip_printts(netdissect_options * ndo,register const u_char * cp,u_int length)165 ip_printts(netdissect_options *ndo,
166            register const u_char *cp, u_int length)
167 {
168 	register u_int ptr;
169 	register u_int len;
170 	int hoplen;
171 	const char *type;
172 
173 	if (length < 4) {
174 		ND_PRINT((ndo, "[bad length %u]", length));
175 		return;
176 	}
177 	ND_PRINT((ndo, " TS{"));
178 	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
179 	if ((length - 4) & (hoplen-1))
180 		ND_PRINT((ndo, "[bad length %u]", length));
181 	ptr = cp[2] - 1;
182 	len = 0;
183 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
184 		ND_PRINT((ndo, "[bad ptr %u]", cp[2]));
185 	switch (cp[3]&0xF) {
186 	case IPOPT_TS_TSONLY:
187 		ND_PRINT((ndo, "TSONLY"));
188 		break;
189 	case IPOPT_TS_TSANDADDR:
190 		ND_PRINT((ndo, "TS+ADDR"));
191 		break;
192 	/*
193 	 * prespecified should really be 3, but some ones might send 2
194 	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
195 	 * have both values, so we have to hard-code it here.
196 	 */
197 
198 	case 2:
199 		ND_PRINT((ndo, "PRESPEC2.0"));
200 		break;
201 	case 3:			/* IPOPT_TS_PRESPEC */
202 		ND_PRINT((ndo, "PRESPEC"));
203 		break;
204 	default:
205 		ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF));
206 		goto done;
207 	}
208 
209 	type = " ";
210 	for (len = 4; len < length; len += hoplen) {
211 		if (ptr == len)
212 			type = " ^ ";
213 		ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
214 		       hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len])));
215 		type = " ";
216 	}
217 
218 done:
219 	ND_PRINT((ndo, "%s", ptr == len ? " ^ " : ""));
220 
221 	if (cp[3]>>4)
222 		ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4));
223 	else
224 		ND_PRINT((ndo, "}"));
225 }
226 
227 /*
228  * print IP options.
229  */
230 static void
ip_optprint(netdissect_options * ndo,register const u_char * cp,u_int length)231 ip_optprint(netdissect_options *ndo,
232             register const u_char *cp, u_int length)
233 {
234 	register u_int option_len;
235 	const char *sep = "";
236 
237 	for (; length > 0; cp += option_len, length -= option_len) {
238 		u_int option_code;
239 
240 		ND_PRINT((ndo, "%s", sep));
241 		sep = ",";
242 
243 		ND_TCHECK(*cp);
244 		option_code = *cp;
245 
246 		ND_PRINT((ndo, "%s",
247 		          tok2str(ip_option_values,"unknown %u",option_code)));
248 
249 		if (option_code == IPOPT_NOP ||
250                     option_code == IPOPT_EOL)
251 			option_len = 1;
252 
253 		else {
254 			ND_TCHECK(cp[1]);
255 			option_len = cp[1];
256 			if (option_len < 2) {
257 				ND_PRINT((ndo, " [bad length %u]", option_len));
258 				return;
259 			}
260 		}
261 
262 		if (option_len > length) {
263 			ND_PRINT((ndo, " [bad length %u]", option_len));
264 			return;
265 		}
266 
267 		ND_TCHECK2(*cp, option_len);
268 
269 		switch (option_code) {
270 		case IPOPT_EOL:
271 			return;
272 
273 		case IPOPT_TS:
274 			ip_printts(ndo, cp, option_len);
275 			break;
276 
277 		case IPOPT_RR:       /* fall through */
278 		case IPOPT_SSRR:
279 		case IPOPT_LSRR:
280 			ip_printroute(ndo, cp, option_len);
281 			break;
282 
283 		case IPOPT_RA:
284 			if (option_len < 4) {
285 				ND_PRINT((ndo, " [bad length %u]", option_len));
286 				break;
287 			}
288 			ND_TCHECK(cp[3]);
289 			if (EXTRACT_16BITS(&cp[2]) != 0)
290 				ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2])));
291 			break;
292 
293 		case IPOPT_NOP:       /* nothing to print - fall through */
294 		case IPOPT_SECURITY:
295 		default:
296 			break;
297 		}
298 	}
299 	return;
300 
301 trunc:
302 	ND_PRINT((ndo, "%s", tstr));
303 }
304 
305 #define IP_RES 0x8000
306 
307 static const struct tok ip_frag_values[] = {
308         { IP_MF,        "+" },
309         { IP_DF,        "DF" },
310 	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
311         { 0,            NULL }
312 };
313 
314 struct ip_print_demux_state {
315 	const struct ip *ip;
316 	const u_char *cp;
317 	u_int   len, off;
318 	u_char  nh;
319 	int     advance;
320 };
321 
322 static void
ip_print_demux(netdissect_options * ndo,struct ip_print_demux_state * ipds)323 ip_print_demux(netdissect_options *ndo,
324 	       struct ip_print_demux_state *ipds)
325 {
326 	struct protoent *proto;
327 	struct cksum_vec vec[1];
328 
329 again:
330 	switch (ipds->nh) {
331 
332 	case IPPROTO_AH:
333 		ipds->nh = *ipds->cp;
334 		ipds->advance = ah_print(ndo, ipds->cp);
335 		if (ipds->advance <= 0)
336 			break;
337 		ipds->cp += ipds->advance;
338 		ipds->len -= ipds->advance;
339 		goto again;
340 
341 	case IPPROTO_ESP:
342 	{
343 		int enh, padlen;
344 		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
345 				    (const u_char *)ipds->ip,
346 				    &enh, &padlen);
347 		if (ipds->advance <= 0)
348 			break;
349 		ipds->cp += ipds->advance;
350 		ipds->len -= ipds->advance + padlen;
351 		ipds->nh = enh & 0xff;
352 		goto again;
353 	}
354 
355 	case IPPROTO_IPCOMP:
356 	{
357 		int enh;
358 		ipds->advance = ipcomp_print(ndo, ipds->cp, &enh);
359 		if (ipds->advance <= 0)
360 			break;
361 		ipds->cp += ipds->advance;
362 		ipds->len -= ipds->advance;
363 		ipds->nh = enh & 0xff;
364 		goto again;
365 	}
366 
367 	case IPPROTO_SCTP:
368 		sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
369 		break;
370 
371 	case IPPROTO_DCCP:
372 		dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
373 		break;
374 
375 	case IPPROTO_TCP:
376 		/* pass on the MF bit plus the offset to detect fragments */
377 		tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
378 			  ipds->off & (IP_MF|IP_OFFMASK));
379 		break;
380 
381 	case IPPROTO_UDP:
382 		/* pass on the MF bit plus the offset to detect fragments */
383 		udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
384 			  ipds->off & (IP_MF|IP_OFFMASK));
385 		break;
386 
387 	case IPPROTO_ICMP:
388 		/* pass on the MF bit plus the offset to detect fragments */
389 		icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
390 			   ipds->off & (IP_MF|IP_OFFMASK));
391 		break;
392 
393 	case IPPROTO_PIGP:
394 		/*
395 		 * XXX - the current IANA protocol number assignments
396 		 * page lists 9 as "any private interior gateway
397 		 * (used by Cisco for their IGRP)" and 88 as
398 		 * "EIGRP" from Cisco.
399 		 *
400 		 * Recent BSD <netinet/in.h> headers define
401 		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
402 		 * We define IP_PROTO_PIGP as 9 and
403 		 * IP_PROTO_EIGRP as 88; those names better
404 		 * match was the current protocol number
405 		 * assignments say.
406 		 */
407 		igrp_print(ndo, ipds->cp, ipds->len);
408 		break;
409 
410 	case IPPROTO_EIGRP:
411 		eigrp_print(ndo, ipds->cp, ipds->len);
412 		break;
413 
414 	case IPPROTO_ND:
415 		ND_PRINT((ndo, " nd %d", ipds->len));
416 		break;
417 
418 	case IPPROTO_EGP:
419 		egp_print(ndo, ipds->cp, ipds->len);
420 		break;
421 
422 	case IPPROTO_OSPF:
423 		ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
424 		break;
425 
426 	case IPPROTO_IGMP:
427 		igmp_print(ndo, ipds->cp, ipds->len);
428 		break;
429 
430 	case IPPROTO_IPV4:
431 		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
432 		ip_print(ndo, ipds->cp, ipds->len);
433 		if (! ndo->ndo_vflag) {
434 			ND_PRINT((ndo, " (ipip-proto-4)"));
435 			return;
436 		}
437 		break;
438 
439 	case IPPROTO_IPV6:
440 		/* ip6-in-ip encapsulation */
441 		ip6_print(ndo, ipds->cp, ipds->len);
442 		break;
443 
444 	case IPPROTO_RSVP:
445 		rsvp_print(ndo, ipds->cp, ipds->len);
446 		break;
447 
448 	case IPPROTO_GRE:
449 		/* do it */
450 		gre_print(ndo, ipds->cp, ipds->len);
451 		break;
452 
453 	case IPPROTO_MOBILE:
454 		mobile_print(ndo, ipds->cp, ipds->len);
455 		break;
456 
457 	case IPPROTO_PIM:
458 		vec[0].ptr = ipds->cp;
459 		vec[0].len = ipds->len;
460 		pim_print(ndo, ipds->cp, ipds->len, in_cksum(vec, 1));
461 		break;
462 
463 	case IPPROTO_VRRP:
464 		if (ndo->ndo_packettype == PT_CARP) {
465 			if (ndo->ndo_vflag)
466 				ND_PRINT((ndo, "carp %s > %s: ",
467 					     ipaddr_string(ndo, &ipds->ip->ip_src),
468 					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
469 			carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl);
470 		} else {
471 			if (ndo->ndo_vflag)
472 				ND_PRINT((ndo, "vrrp %s > %s: ",
473 					     ipaddr_string(ndo, &ipds->ip->ip_src),
474 					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
475 			vrrp_print(ndo, ipds->cp, ipds->len,
476 				(const u_char *)ipds->ip, ipds->ip->ip_ttl);
477 		}
478 		break;
479 
480 	case IPPROTO_PGM:
481 		pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
482 		break;
483 
484 	default:
485 		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
486 			ND_PRINT((ndo, " %s", proto->p_name));
487 		else
488 			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
489 		ND_PRINT((ndo, " %d", ipds->len));
490 		break;
491 	}
492 }
493 
494 void
ip_print_inner(netdissect_options * ndo,const u_char * bp,u_int length,u_int nh,const u_char * bp2)495 ip_print_inner(netdissect_options *ndo,
496 	       const u_char *bp,
497 	       u_int length, u_int nh,
498 	       const u_char *bp2)
499 {
500 	struct ip_print_demux_state  ipd;
501 
502 	ipd.ip = (const struct ip *)bp2;
503 	ipd.cp = bp;
504 	ipd.len  = length;
505 	ipd.off  = 0;
506 	ipd.nh   = nh;
507 	ipd.advance = 0;
508 
509 	ip_print_demux(ndo, &ipd);
510 }
511 
512 
513 /*
514  * print an IP datagram.
515  */
516 void
ip_print(netdissect_options * ndo,const u_char * bp,u_int length)517 ip_print(netdissect_options *ndo,
518 	 const u_char *bp,
519 	 u_int length)
520 {
521 	struct ip_print_demux_state  ipd;
522 	struct ip_print_demux_state *ipds=&ipd;
523 	const u_char *ipend;
524 	u_int hlen;
525 	struct cksum_vec vec[1];
526 	uint16_t sum, ip_sum;
527 	struct protoent *proto;
528 
529 	ipds->ip = (const struct ip *)bp;
530 	ND_TCHECK(ipds->ip->ip_vhl);
531 	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
532 	    if (IP_V(ipds->ip) == 6)
533 	      ND_PRINT((ndo, "IP6, wrong link-layer encapsulation "));
534 	    else
535 	      ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip)));
536 	}
537 	else if (!ndo->ndo_eflag)
538 		ND_PRINT((ndo, "IP "));
539 
540 	ND_TCHECK(*ipds->ip);
541 	if (length < sizeof (struct ip)) {
542 		ND_PRINT((ndo, "truncated-ip %u", length));
543 		return;
544 	}
545 	hlen = IP_HL(ipds->ip) * 4;
546 	if (hlen < sizeof (struct ip)) {
547 		ND_PRINT((ndo, "bad-hlen %u", hlen));
548 		return;
549 	}
550 
551 	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
552 	if (length < ipds->len)
553 		ND_PRINT((ndo, "truncated-ip - %u bytes missing! ",
554 			ipds->len - length));
555 	if (ipds->len < hlen) {
556 #ifdef GUESS_TSO
557             if (ipds->len) {
558                 ND_PRINT((ndo, "bad-len %u", ipds->len));
559                 return;
560             }
561             else {
562                 /* we guess that it is a TSO send */
563                 ipds->len = length;
564             }
565 #else
566             ND_PRINT((ndo, "bad-len %u", ipds->len));
567             return;
568 #endif /* GUESS_TSO */
569 	}
570 
571 	/*
572 	 * Cut off the snapshot length to the end of the IP payload.
573 	 */
574 	ipend = bp + ipds->len;
575 	if (ipend < ndo->ndo_snapend)
576 		ndo->ndo_snapend = ipend;
577 
578 	ipds->len -= hlen;
579 
580 	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
581 
582         if (ndo->ndo_vflag) {
583             ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos));
584             /* ECN bits */
585             if (ipds->ip->ip_tos & 0x03) {
586                 switch (ipds->ip->ip_tos & 0x03) {
587                 case 1:
588                     ND_PRINT((ndo, ",ECT(1)"));
589                     break;
590                 case 2:
591                     ND_PRINT((ndo, ",ECT(0)"));
592                     break;
593                 case 3:
594                     ND_PRINT((ndo, ",CE"));
595                 }
596             }
597 
598             if (ipds->ip->ip_ttl >= 1)
599                 ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl));
600 
601 	    /*
602 	     * for the firewall guys, print id, offset.
603              * On all but the last stick a "+" in the flags portion.
604 	     * For unfragmented datagrams, note the don't fragment flag.
605 	     */
606 
607 	    ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)",
608                          EXTRACT_16BITS(&ipds->ip->ip_id),
609                          (ipds->off & 0x1fff) * 8,
610                          bittok2str(ip_frag_values, "none", ipds->off&0xe000),
611                          tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
612                          ipds->ip->ip_p));
613 
614             ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len)));
615 
616             if ((hlen - sizeof(struct ip)) > 0) {
617                 ND_PRINT((ndo, ", options ("));
618                 ip_optprint(ndo, (u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
619                 ND_PRINT((ndo, ")"));
620             }
621 
622 	    if (!ndo->ndo_Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
623 	        vec[0].ptr = (const uint8_t *)(void *)ipds->ip;
624 	        vec[0].len = hlen;
625 	        sum = in_cksum(vec, 1);
626 		if (sum != 0) {
627 		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
628 		    ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum,
629 			     in_cksum_shouldbe(ip_sum, sum)));
630 		}
631 	    }
632 
633 		ND_PRINT((ndo, ")\n    "));
634 	}
635 
636 	/*
637 	 * If this is fragment zero, hand it to the next higher
638 	 * level protocol.
639 	 */
640 	if ((ipds->off & 0x1fff) == 0) {
641 		ipds->cp = (const u_char *)ipds->ip + hlen;
642 		ipds->nh = ipds->ip->ip_p;
643 
644 		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
645 		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
646 			ND_PRINT((ndo, "%s > %s: ",
647 				     ipaddr_string(ndo, &ipds->ip->ip_src),
648 				     ipaddr_string(ndo, &ipds->ip->ip_dst)));
649 		}
650 		ip_print_demux(ndo, ipds);
651 	} else {
652 	    /* Ultra quiet now means that all this stuff should be suppressed */
653 	    if (ndo->ndo_qflag > 1) return;
654 
655 	    /*
656 	     * if this isn't the first frag, we're missing the
657 	     * next level protocol header.  print the ip addr
658 	     * and the protocol.
659 	     */
660 		if (ipds->off & 0x1fff) {
661 			ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src),
662 			          ipaddr_string(ndo, &ipds->ip->ip_dst)));
663 			if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
664 				ND_PRINT((ndo, " %s", proto->p_name));
665 			else
666 				ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p));
667 		}
668 	}
669 	return;
670 
671 trunc:
672 	ND_PRINT((ndo, "%s", tstr));
673 	return;
674 }
675 
676 void
ipN_print(netdissect_options * ndo,register const u_char * bp,register u_int length)677 ipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length)
678 {
679 	struct ip hdr;
680 
681 	if (length < 4) {
682 		ND_PRINT((ndo, "truncated-ip %d", length));
683 		return;
684 	}
685 	memcpy (&hdr, bp, 4);
686 	switch (IP_V(&hdr)) {
687 	case 4:
688 		ip_print (ndo, bp, length);
689 		return;
690 	case 6:
691 		ip6_print (ndo, bp, length);
692 		return;
693 	default:
694 		ND_PRINT((ndo, "unknown ip %d", IP_V(&hdr)));
695 		return;
696 	}
697 }
698 
699 /*
700  * Local Variables:
701  * c-style: whitesmith
702  * c-basic-offset: 8
703  * End:
704  */
705 
706 
707