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