]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-ip.c
Followup to r347996
[FreeBSD/FreeBSD.git] / contrib / tcpdump / print-ip.c
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