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