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