Import of tcpdump 3.8.3
[dragonfly.git] / contrib / tcpdump-3.8.3 / print-icmp6.c
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
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 #ifndef lint
23 static const char rcsid[] _U_ =
24     "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.72.2.4 2004/03/24 00:14:09 guy Exp $";
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #ifdef INET6
32
33 #include <tcpdump-stdinc.h>
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "ip6.h"
39 #include "icmp6.h"
40 #include "ipproto.h"
41
42 #include "interface.h"
43 #include "addrtoname.h"
44 #include "extract.h"
45
46 #include "udp.h"
47 #include "ah.h"
48
49 static const char *get_rtpref(u_int);
50 static const char *get_lifetime(u_int32_t);
51 static void print_lladdr(const u_char *, size_t);
52 static void icmp6_opt_print(const u_char *, int);
53 static void mld6_print(const u_char *);
54 static struct udphdr *get_upperlayer(u_char *, u_int *);
55 static void dnsname_print(const u_char *, const u_char *);
56 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
57 static void icmp6_rrenum_print(const u_char *, const u_char *);
58
59 #ifndef abs
60 #define abs(a)  ((0 < (a)) ? (a) : -(a))
61 #endif
62
63 static const char *
64 get_rtpref(u_int v)
65 {
66         static const char *rtpref_str[] = {
67                 "medium",               /* 00 */
68                 "high",                 /* 01 */
69                 "rsv",                  /* 10 */
70                 "low"                   /* 11 */
71         };
72
73         return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
74 }
75
76 static const char *
77 get_lifetime(u_int32_t v)
78 {
79         static char buf[20];
80
81         if (v == (u_int32_t)~0UL)
82                 return "infinity";
83         else {
84                 snprintf(buf, sizeof(buf), "%u", v);
85                 return buf;
86         }
87 }
88
89 static void
90 print_lladdr(const u_int8_t *p, size_t l)
91 {
92         const u_int8_t *ep, *q;
93
94         q = p;
95         ep = p + l;
96         while (l > 0 && q < ep) {
97                 if (q > p)
98                         printf(":");
99                 printf("%02x", *q++);
100                 l--;
101         }
102 }
103
104 static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
105         u_int len)
106 {
107         size_t i;
108         register const u_int16_t *sp;
109         u_int32_t sum;
110         union {
111                 struct {
112                         struct in6_addr ph_src;
113                         struct in6_addr ph_dst;
114                         u_int32_t       ph_len;
115                         u_int8_t        ph_zero[3];
116                         u_int8_t        ph_nxt;
117                 } ph;
118                 u_int16_t pa[20];
119         } phu;
120
121         /* pseudo-header */
122         memset(&phu, 0, sizeof(phu));
123         phu.ph.ph_src = ip6->ip6_src;
124         phu.ph.ph_dst = ip6->ip6_dst;
125         phu.ph.ph_len = htonl(len);
126         phu.ph.ph_nxt = IPPROTO_ICMPV6;
127
128         sum = 0;
129         for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
130                 sum += phu.pa[i];
131
132         sp = (const u_int16_t *)icp;
133
134         for (i = 0; i < (len & ~1); i += 2)
135                 sum += *sp++;
136
137         if (len & 1)
138                 sum += htons((*(const u_int8_t *)sp) << 8);
139
140         while (sum > 0xffff)
141                 sum = (sum & 0xffff) + (sum >> 16);
142         sum = ~sum & 0xffff;
143
144         return (sum);
145 }
146
147 void
148 icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
149 {
150         const struct icmp6_hdr *dp;
151         const struct ip6_hdr *ip;
152         const char *str;
153         const struct ip6_hdr *oip;
154         const struct udphdr *ouh;
155         int dport;
156         const u_char *ep;
157         char buf[256];
158         u_int prot;
159
160         dp = (struct icmp6_hdr *)bp;
161         ip = (struct ip6_hdr *)bp2;
162         oip = (struct ip6_hdr *)(dp + 1);
163         str = buf;
164         /* 'ep' points to the end of available data. */
165         ep = snapend;
166
167         TCHECK(dp->icmp6_cksum);
168
169         if (vflag && !fragmented) {
170                 int sum = dp->icmp6_cksum;
171
172                 if (TTEST2(bp[0], length)) {
173                         sum = icmp6_cksum(ip, dp, length);
174                         if (sum != 0)
175                                 (void)printf("[bad icmp6 cksum %x!] ", sum);
176                         else
177                                 (void)printf("[icmp6 sum ok] ");
178                 }
179         }
180
181         switch (dp->icmp6_type) {
182         case ICMP6_DST_UNREACH:
183                 TCHECK(oip->ip6_dst);
184                 switch (dp->icmp6_code) {
185                 case ICMP6_DST_UNREACH_NOROUTE:
186                         printf("icmp6: %s unreachable route",
187                                ip6addr_string(&oip->ip6_dst));
188                         break;
189                 case ICMP6_DST_UNREACH_ADMIN:
190                         printf("icmp6: %s unreachable prohibited",
191                                ip6addr_string(&oip->ip6_dst));
192                         break;
193                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
194                         printf("icmp6: %s beyond scope of source address %s",
195                                ip6addr_string(&oip->ip6_dst),
196                                ip6addr_string(&oip->ip6_src));
197                         break;
198                 case ICMP6_DST_UNREACH_ADDR:
199                         printf("icmp6: %s unreachable address",
200                                ip6addr_string(&oip->ip6_dst));
201                         break;
202                 case ICMP6_DST_UNREACH_NOPORT:
203                         if ((ouh = get_upperlayer((u_char *)oip, &prot))
204                             == NULL)
205                                 goto trunc;
206
207                         dport = EXTRACT_16BITS(&ouh->uh_dport);
208                         switch (prot) {
209                         case IPPROTO_TCP:
210                                 printf("icmp6: %s tcp port %s unreachable",
211                                         ip6addr_string(&oip->ip6_dst),
212                                         tcpport_string(dport));
213                                 break;
214                         case IPPROTO_UDP:
215                                 printf("icmp6: %s udp port %s unreachable",
216                                         ip6addr_string(&oip->ip6_dst),
217                                         udpport_string(dport));
218                                 break;
219                         default:
220                                 printf("icmp6: %s protocol %d port %d unreachable",
221                                         ip6addr_string(&oip->ip6_dst),
222                                         oip->ip6_nxt, dport);
223                                 break;
224                         }
225                         break;
226                 default:
227                         printf("icmp6: %s unreachable code-#%d",
228                                 ip6addr_string(&oip->ip6_dst),
229                                 dp->icmp6_code);
230                         break;
231                 }
232                 break;
233         case ICMP6_PACKET_TOO_BIG:
234                 TCHECK(dp->icmp6_mtu);
235                 printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu));
236                 break;
237         case ICMP6_TIME_EXCEEDED:
238                 TCHECK(oip->ip6_dst);
239                 switch (dp->icmp6_code) {
240                 case ICMP6_TIME_EXCEED_TRANSIT:
241                         printf("icmp6: time exceeded in-transit for %s",
242                                 ip6addr_string(&oip->ip6_dst));
243                         break;
244                 case ICMP6_TIME_EXCEED_REASSEMBLY:
245                         printf("icmp6: ip6 reassembly time exceeded");
246                         break;
247                 default:
248                         printf("icmp6: time exceeded code-#%d",
249                                 dp->icmp6_code);
250                         break;
251                 }
252                 break;
253         case ICMP6_PARAM_PROB:
254                 TCHECK(oip->ip6_dst);
255                 switch (dp->icmp6_code) {
256                 case ICMP6_PARAMPROB_HEADER:
257                         printf("icmp6: parameter problem errorneous - octet %u",
258                                 EXTRACT_32BITS(&dp->icmp6_pptr));
259                         break;
260                 case ICMP6_PARAMPROB_NEXTHEADER:
261                         printf("icmp6: parameter problem next header - octet %u",
262                                 EXTRACT_32BITS(&dp->icmp6_pptr));
263                         break;
264                 case ICMP6_PARAMPROB_OPTION:
265                         printf("icmp6: parameter problem option - octet %u",
266                                 EXTRACT_32BITS(&dp->icmp6_pptr));
267                         break;
268                 default:
269                         printf("icmp6: parameter problem code-#%d",
270                                dp->icmp6_code);
271                         break;
272                 }
273                 break;
274         case ICMP6_ECHO_REQUEST:
275         case ICMP6_ECHO_REPLY:
276                 TCHECK(dp->icmp6_seq);
277                 printf("icmp6: echo %s seq %u",
278                         dp->icmp6_type == ICMP6_ECHO_REQUEST ?
279                         "request" : "reply",
280                         EXTRACT_16BITS(&dp->icmp6_seq));
281                 break;
282         case ICMP6_MEMBERSHIP_QUERY:
283                 printf("icmp6: multicast listener query ");
284                 mld6_print((const u_char *)dp);
285                 break;
286         case ICMP6_MEMBERSHIP_REPORT:
287                 printf("icmp6: multicast listener report ");
288                 mld6_print((const u_char *)dp);
289                 break;
290         case ICMP6_MEMBERSHIP_REDUCTION:
291                 printf("icmp6: multicast listener done ");
292                 mld6_print((const u_char *)dp);
293                 break;
294         case ND_ROUTER_SOLICIT:
295                 printf("icmp6: router solicitation ");
296                 if (vflag) {
297 #define RTSOLLEN 8
298                         icmp6_opt_print((const u_char *)dp + RTSOLLEN,
299                                         length - RTSOLLEN);
300                 }
301                 break;
302         case ND_ROUTER_ADVERT:
303                 printf("icmp6: router advertisement");
304                 if (vflag) {
305                         struct nd_router_advert *p;
306
307                         p = (struct nd_router_advert *)dp;
308                         TCHECK(p->nd_ra_retransmit);
309                         printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
310                         if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
311                                 printf("M");
312                         if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
313                                 printf("O");
314                         if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
315                                 printf("H");
316
317                         if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
318                             != 0)
319                                 printf(" ");
320
321                         printf("pref=%s, ",
322                             get_rtpref(p->nd_ra_flags_reserved));
323
324                         printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime));
325                         printf("reachable_time=%u, ",
326                                 EXTRACT_32BITS(&p->nd_ra_reachable));
327                         printf("retrans_time=%u)",
328                                 EXTRACT_32BITS(&p->nd_ra_retransmit));
329 #define RTADVLEN 16
330                         icmp6_opt_print((const u_char *)dp + RTADVLEN,
331                                         length - RTADVLEN);
332                 }
333                 break;
334         case ND_NEIGHBOR_SOLICIT:
335             {
336                 struct nd_neighbor_solicit *p;
337                 p = (struct nd_neighbor_solicit *)dp;
338                 TCHECK(p->nd_ns_target);
339                 printf("icmp6: neighbor sol: who has %s",
340                         ip6addr_string(&p->nd_ns_target));
341                 if (vflag) {
342 #define NDSOLLEN 24
343                         icmp6_opt_print((const u_char *)dp + NDSOLLEN,
344                                         length - NDSOLLEN);
345                 }
346             }
347                 break;
348         case ND_NEIGHBOR_ADVERT:
349             {
350                 struct nd_neighbor_advert *p;
351
352                 p = (struct nd_neighbor_advert *)dp;
353                 TCHECK(p->nd_na_target);
354                 printf("icmp6: neighbor adv: tgt is %s",
355                         ip6addr_string(&p->nd_na_target));
356                 if (vflag) {
357 #define ND_NA_FLAG_ALL  \
358         (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
359                         /* we don't need ntohl() here.  see advanced-api-04. */
360                         if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
361 #undef ND_NA_FLAG_ALL
362                                 u_int32_t flags;
363
364                                 flags = p->nd_na_flags_reserved;
365                                 printf("(");
366                                 if (flags & ND_NA_FLAG_ROUTER)
367                                         printf("R");
368                                 if (flags & ND_NA_FLAG_SOLICITED)
369                                         printf("S");
370                                 if (flags & ND_NA_FLAG_OVERRIDE)
371                                         printf("O");
372                                 printf(")");
373                         }
374 #define NDADVLEN 24
375                         icmp6_opt_print((const u_char *)dp + NDADVLEN,
376                                         length - NDADVLEN);
377 #undef NDADVLEN
378                 }
379             }
380                 break;
381         case ND_REDIRECT:
382 #define RDR(i) ((struct nd_redirect *)(i))
383                 TCHECK(RDR(dp)->nd_rd_dst);
384                 printf("icmp6: redirect %s",
385                     getname6((const u_char *)&RDR(dp)->nd_rd_dst));
386                 TCHECK(RDR(dp)->nd_rd_target);
387                 printf(" to %s",
388                     getname6((const u_char*)&RDR(dp)->nd_rd_target));
389 #define REDIRECTLEN 40
390                 if (vflag) {
391                         icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
392                                         length - REDIRECTLEN);
393                 }
394                 break;
395 #undef REDIRECTLEN
396 #undef RDR
397         case ICMP6_ROUTER_RENUMBERING:
398                 icmp6_rrenum_print(bp, ep);
399                 break;
400         case ICMP6_NI_QUERY:
401         case ICMP6_NI_REPLY:
402                 icmp6_nodeinfo_print(length, bp, ep);
403                 break;
404         case ICMP6_HADISCOV_REQUEST:
405                 printf("icmp6: ha discovery request");
406                 if (vflag) {
407                         TCHECK(dp->icmp6_data16[0]);
408                         printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
409                 }
410                 break;
411         case ICMP6_HADISCOV_REPLY:
412                 printf("icmp6: ha discovery reply");
413                 if (vflag) {
414                         struct in6_addr *in6;
415                         u_char *cp;
416
417                         TCHECK(dp->icmp6_data16[0]);
418                         printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
419                         cp = (u_char *)dp + length;
420                         in6 = (struct in6_addr *)(dp + 1);
421                         for (; (u_char *)in6 < cp; in6++) {
422                                 TCHECK(*in6);
423                                 printf(", %s", ip6addr_string(in6));
424                         }
425                         printf(")");
426                 }
427                 break;
428         case ICMP6_MOBILEPREFIX_SOLICIT:
429                 printf("icmp6: mobile router solicitation");
430                 if (vflag) {
431                         TCHECK(dp->icmp6_data16[0]);
432                         printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
433                 }
434                 break;
435         case ICMP6_MOBILEPREFIX_ADVERT:
436                 printf("icmp6: mobile router advertisement");
437                 if (vflag) {
438                         TCHECK(dp->icmp6_data16[0]);
439                         printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
440                         if (dp->icmp6_data16[1] & 0xc0)
441                                 printf(" ");
442                         if (dp->icmp6_data16[1] & 0x80)
443                                 printf("M");
444                         if (dp->icmp6_data16[1] & 0x40)
445                                 printf("O");
446                         printf(")");
447 #define MPADVLEN 8
448                         icmp6_opt_print((const u_char *)dp + MPADVLEN,
449                                         length - MPADVLEN);
450                 }
451                 break;
452         default:
453                 printf("icmp6: type-#%d", dp->icmp6_type);
454                 break;
455         }
456         return;
457 trunc:
458         fputs("[|icmp6]", stdout);
459 }
460
461 static struct udphdr *
462 get_upperlayer(u_char *bp, u_int *prot)
463 {
464         const u_char *ep;
465         struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
466         struct udphdr *uh;
467         struct ip6_hbh *hbh;
468         struct ip6_frag *fragh;
469         struct ah *ah;
470         u_int nh;
471         int hlen;
472
473         /* 'ep' points to the end of available data. */
474         ep = snapend;
475
476         if (!TTEST(ip6->ip6_nxt))
477                 return NULL;
478
479         nh = ip6->ip6_nxt;
480         hlen = sizeof(struct ip6_hdr);
481
482         while (bp < snapend) {
483                 bp += hlen;
484
485                 switch(nh) {
486                 case IPPROTO_UDP:
487                 case IPPROTO_TCP:
488                         uh = (struct udphdr *)bp;
489                         if (TTEST(uh->uh_dport)) {
490                                 *prot = nh;
491                                 return(uh);
492                         }
493                         else
494                                 return(NULL);
495                         /* NOTREACHED */
496
497                 case IPPROTO_HOPOPTS:
498                 case IPPROTO_DSTOPTS:
499                 case IPPROTO_ROUTING:
500                         hbh = (struct ip6_hbh *)bp;
501                         if (!TTEST(hbh->ip6h_len))
502                                 return(NULL);
503                         nh = hbh->ip6h_nxt;
504                         hlen = (hbh->ip6h_len + 1) << 3;
505                         break;
506
507                 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
508                         fragh = (struct ip6_frag *)bp;
509                         if (!TTEST(fragh->ip6f_offlg))
510                                 return(NULL);
511                         /* fragments with non-zero offset are meaningless */
512                         if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
513                                 return(NULL);
514                         nh = fragh->ip6f_nxt;
515                         hlen = sizeof(struct ip6_frag);
516                         break;
517
518                 case IPPROTO_AH:
519                         ah = (struct ah *)bp;
520                         if (!TTEST(ah->ah_len))
521                                 return(NULL);
522                         nh = ah->ah_nxt;
523                         hlen = (ah->ah_len + 2) << 2;
524                         break;
525
526                 default:        /* unknown or undecodable header */
527                         *prot = nh; /* meaningless, but set here anyway */
528                         return(NULL);
529                 }
530         }
531
532         return(NULL);           /* should be notreached, though */
533 }
534
535 static void
536 icmp6_opt_print(const u_char *bp, int resid)
537 {
538         const struct nd_opt_hdr *op;
539         const struct nd_opt_hdr *opl;   /* why there's no struct? */
540         const struct nd_opt_prefix_info *opp;
541         const struct icmp6_opts_redirect *opr;
542         const struct nd_opt_mtu *opm;
543         const struct nd_opt_advinterval *opa;
544         const struct nd_opt_homeagent_info *oph;
545         const struct nd_opt_route_info *opri;
546         const u_char *cp, *ep;
547         struct in6_addr in6, *in6p;
548         size_t l;
549
550 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
551
552         cp = bp;
553         /* 'ep' points to the end of available data. */
554         ep = snapend;
555
556         while (cp < ep) {
557                 op = (struct nd_opt_hdr *)cp;
558
559                 ECHECK(op->nd_opt_len);
560                 if (resid <= 0)
561                         return;
562                 if (op->nd_opt_len == 0)
563                         goto trunc;
564                 if (cp + (op->nd_opt_len << 3) > ep)
565                         goto trunc;
566
567                 switch (op->nd_opt_type) {
568                 case ND_OPT_SOURCE_LINKADDR:
569                         opl = (struct nd_opt_hdr *)op;
570                         printf("(src lladdr: ");
571                         l = (op->nd_opt_len << 3) - 2;
572                         print_lladdr(cp + 2, l);
573                         /*(*/
574                         printf(")");
575                         break;
576                 case ND_OPT_TARGET_LINKADDR:
577                         opl = (struct nd_opt_hdr *)op;
578                         printf("(tgt lladdr: ");
579                         l = (op->nd_opt_len << 3) - 2;
580                         print_lladdr(cp + 2, l);
581                         /*(*/
582                         printf(")");
583                         break;
584                 case ND_OPT_PREFIX_INFORMATION:
585                         opp = (struct nd_opt_prefix_info *)op;
586                         TCHECK(opp->nd_opt_pi_prefix);
587                         printf("(prefix info: ");       /*)*/
588                         if (op->nd_opt_len != 4) {
589                                 printf("badlen");
590                                 /*(*/
591                                 printf(")");
592                                 break;
593                         }
594                         if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
595                                 printf("L");
596                         if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
597                                 printf("A");
598                         if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
599                                 printf("R");
600                         if (opp->nd_opt_pi_flags_reserved)
601                                 printf(" ");
602                         printf("valid_ltime=%s,",
603                             get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
604                         printf("preferred_ltime=%s,",
605                             get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
606                         printf("prefix=%s/%d",
607                             ip6addr_string(&opp->nd_opt_pi_prefix),
608                             opp->nd_opt_pi_prefix_len);
609                         if (opp->nd_opt_pi_len != 4)
610                                 printf("!");
611                         /*(*/
612                         printf(")");
613                         break;
614                 case ND_OPT_REDIRECTED_HEADER:
615                         opr = (struct icmp6_opts_redirect *)op;
616                         printf("(redirect)");
617                         /* xxx */
618                         break;
619                 case ND_OPT_MTU:
620                         opm = (struct nd_opt_mtu *)op;
621                         TCHECK(opm->nd_opt_mtu_mtu);
622                         printf("(mtu:");        /*)*/
623                         if (op->nd_opt_len != 1) {
624                                 printf("badlen");
625                                 /*(*/
626                                 printf(")");
627                                 break;
628                         }
629                         printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
630                         if (opm->nd_opt_mtu_len != 1)
631                                 printf("!");
632                         printf(")");
633                         break;
634                 case ND_OPT_ADVINTERVAL:
635                         opa = (struct nd_opt_advinterval *)op;
636                         TCHECK(opa->nd_opt_adv_interval);
637                         printf("(advint:");     /*)*/
638                         printf(" advint=%u",
639                             EXTRACT_32BITS(&opa->nd_opt_adv_interval));
640                         /*(*/
641                         printf(")");
642                         break;
643                 case ND_OPT_HOMEAGENT_INFO:
644                         oph = (struct nd_opt_homeagent_info *)op;
645                         TCHECK(oph->nd_opt_hai_lifetime);
646                         printf("(ha info:");    /*)*/
647                         printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
648                         printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
649                         printf(")");
650                         break;
651                 case ND_OPT_ROUTE_INFO:
652                         opri = (struct nd_opt_route_info *)op;
653                         TCHECK(opri->nd_opt_rti_lifetime);
654                         memset(&in6, 0, sizeof(in6));
655                         in6p = (struct in6_addr *)(opri + 1);
656                         switch (op->nd_opt_len) {
657                         case 1:
658                                 break;
659                         case 2:
660                                 TCHECK2(*in6p, 8);
661                                 memcpy(&in6, opri + 1, 8);
662                                 break;
663                         case 3:
664                                 TCHECK(*in6p);
665                                 memcpy(&in6, opri + 1, sizeof(in6));
666                                 break;
667                         default:
668                                 goto trunc;
669                         }
670                         printf("(rtinfo:");     /*)*/
671                         printf(" %s/%u", ip6addr_string(&in6),
672                             opri->nd_opt_rti_prefixlen);
673                         printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
674                         printf(", lifetime=%s",
675                             get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
676                         /*(*/
677                         printf(")");
678                         break;
679                 default:
680                         printf("(unknown opt_type=%d, opt_len=%d)",
681                                op->nd_opt_type, op->nd_opt_len);
682                         break;
683                 }
684
685                 cp += op->nd_opt_len << 3;
686                 resid -= op->nd_opt_len << 3;
687         }
688         return;
689
690  trunc:
691         fputs("[ndp opt]", stdout);
692         return;
693 #undef ECHECK
694 }
695
696 static void
697 mld6_print(const u_char *bp)
698 {
699         struct mld6_hdr *mp = (struct mld6_hdr *)bp;
700         const u_char *ep;
701
702         /* 'ep' points to the end of available data. */
703         ep = snapend;
704
705         if ((u_char *)mp + sizeof(*mp) > ep)
706                 return;
707
708         printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
709         printf("addr: %s", ip6addr_string(&mp->mld6_addr));
710 }
711
712 static void
713 dnsname_print(const u_char *cp, const u_char *ep)
714 {
715         int i;
716
717         /* DNS name decoding - no decompression */
718         printf(", \"");
719         while (cp < ep) {
720                 i = *cp++;
721                 if (i) {
722                         if (i > ep - cp) {
723                                 printf("???");
724                                 break;
725                         }
726                         while (i-- && cp < ep) {
727                                 safeputchar(*cp);
728                                 cp++;
729                         }
730                         if (cp + 1 < ep && *cp)
731                                 printf(".");
732                 } else {
733                         if (cp == ep) {
734                                 /* FQDN */
735                                 printf(".");
736                         } else if (cp + 1 == ep && *cp == '\0') {
737                                 /* truncated */
738                         } else {
739                                 /* invalid */
740                                 printf("???");
741                         }
742                         break;
743                 }
744         }
745         printf("\"");
746 }
747
748 static void
749 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
750 {
751         struct icmp6_nodeinfo *ni6;
752         struct icmp6_hdr *dp;
753         const u_char *cp;
754         size_t siz, i;
755         int needcomma;
756
757         if (ep < bp)
758                 return;
759         dp = (struct icmp6_hdr *)bp;
760         ni6 = (struct icmp6_nodeinfo *)bp;
761         siz = ep - bp;
762
763         switch (ni6->ni_type) {
764         case ICMP6_NI_QUERY:
765                 if (siz == sizeof(*dp) + 4) {
766                         /* KAME who-are-you */
767                         printf("icmp6: who-are-you request");
768                         break;
769                 }
770                 printf("icmp6: node information query");
771
772                 TCHECK2(*dp, sizeof(*ni6));
773                 ni6 = (struct icmp6_nodeinfo *)dp;
774                 printf(" (");   /*)*/
775                 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
776                 case NI_QTYPE_NOOP:
777                         printf("noop");
778                         break;
779                 case NI_QTYPE_SUPTYPES:
780                         printf("supported qtypes");
781                         i = EXTRACT_16BITS(&ni6->ni_flags);
782                         if (i)
783                                 printf(" [%s]", (i & 0x01) ? "C" : "");
784                         break;
785                         break;
786                 case NI_QTYPE_FQDN:
787                         printf("DNS name");
788                         break;
789                 case NI_QTYPE_NODEADDR:
790                         printf("node addresses");
791                         i = ni6->ni_flags;
792                         if (!i)
793                                 break;
794                         /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
795                         printf(" [%s%s%s%s%s%s]",
796                             (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
797                             (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
798                             (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
799                             (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
800                             (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
801                             (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
802                         break;
803                 default:
804                         printf("unknown");
805                         break;
806                 }
807
808                 if (ni6->ni_qtype == NI_QTYPE_NOOP ||
809                     ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
810                         if (siz != sizeof(*ni6))
811                                 if (vflag)
812                                         printf(", invalid len");
813                         /*(*/
814                         printf(")");
815                         break;
816                 }
817
818
819                 /* XXX backward compat, icmp-name-lookup-03 */
820                 if (siz == sizeof(*ni6)) {
821                         printf(", 03 draft");
822                         /*(*/
823                         printf(")");
824                         break;
825                 }
826
827                 switch (ni6->ni_code) {
828                 case ICMP6_NI_SUBJ_IPV6:
829                         if (!TTEST2(*dp,
830                             sizeof(*ni6) + sizeof(struct in6_addr)))
831                                 break;
832                         if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
833                                 if (vflag)
834                                         printf(", invalid subject len");
835                                 break;
836                         }
837                         printf(", subject=%s",
838                             getname6((const u_char *)(ni6 + 1)));
839                         break;
840                 case ICMP6_NI_SUBJ_FQDN:
841                         printf(", subject=DNS name");
842                         cp = (const u_char *)(ni6 + 1);
843                         if (cp[0] == ep - cp - 1) {
844                                 /* icmp-name-lookup-03, pascal string */
845                                 if (vflag)
846                                         printf(", 03 draft");
847                                 cp++;
848                                 printf(", \"");
849                                 while (cp < ep) {
850                                         safeputchar(*cp);
851                                         cp++;
852                                 }
853                                 printf("\"");
854                         } else
855                                 dnsname_print(cp, ep);
856                         break;
857                 case ICMP6_NI_SUBJ_IPV4:
858                         if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
859                                 break;
860                         if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
861                                 if (vflag)
862                                         printf(", invalid subject len");
863                                 break;
864                         }
865                         printf(", subject=%s",
866                             getname((const u_char *)(ni6 + 1)));
867                         break;
868                 default:
869                         printf(", unknown subject");
870                         break;
871                 }
872
873                 /*(*/
874                 printf(")");
875                 break;
876
877         case ICMP6_NI_REPLY:
878                 if (icmp6len > siz) {
879                         printf("[|icmp6: node information reply]");
880                         break;
881                 }
882
883                 needcomma = 0;
884
885                 ni6 = (struct icmp6_nodeinfo *)dp;
886                 printf("icmp6: node information reply");
887                 printf(" (");   /*)*/
888                 switch (ni6->ni_code) {
889                 case ICMP6_NI_SUCCESS:
890                         if (vflag) {
891                                 printf("success");
892                                 needcomma++;
893                         }
894                         break;
895                 case ICMP6_NI_REFUSED:
896                         printf("refused");
897                         needcomma++;
898                         if (siz != sizeof(*ni6))
899                                 if (vflag)
900                                         printf(", invalid length");
901                         break;
902                 case ICMP6_NI_UNKNOWN:
903                         printf("unknown");
904                         needcomma++;
905                         if (siz != sizeof(*ni6))
906                                 if (vflag)
907                                         printf(", invalid length");
908                         break;
909                 }
910
911                 if (ni6->ni_code != ICMP6_NI_SUCCESS) {
912                         /*(*/
913                         printf(")");
914                         break;
915                 }
916
917                 switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
918                 case NI_QTYPE_NOOP:
919                         if (needcomma)
920                                 printf(", ");
921                         printf("noop");
922                         if (siz != sizeof(*ni6))
923                                 if (vflag)
924                                         printf(", invalid length");
925                         break;
926                 case NI_QTYPE_SUPTYPES:
927                         if (needcomma)
928                                 printf(", ");
929                         printf("supported qtypes");
930                         i = EXTRACT_16BITS(&ni6->ni_flags);
931                         if (i)
932                                 printf(" [%s]", (i & 0x01) ? "C" : "");
933                         break;
934                 case NI_QTYPE_FQDN:
935                         if (needcomma)
936                                 printf(", ");
937                         printf("DNS name");
938                         cp = (const u_char *)(ni6 + 1) + 4;
939                         if (cp[0] == ep - cp - 1) {
940                                 /* icmp-name-lookup-03, pascal string */
941                                 if (vflag)
942                                         printf(", 03 draft");
943                                 cp++;
944                                 printf(", \"");
945                                 while (cp < ep) {
946                                         safeputchar(*cp);
947                                         cp++;
948                                 }
949                                 printf("\"");
950                         } else
951                                 dnsname_print(cp, ep);
952                         if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
953                                 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
954                         break;
955                 case NI_QTYPE_NODEADDR:
956                         if (needcomma)
957                                 printf(", ");
958                         printf("node addresses");
959                         i = sizeof(*ni6);
960                         while (i < siz) {
961                                 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
962                                         break;
963                                 printf(" %s", getname6(bp + i));
964                                 i += sizeof(struct in6_addr);
965                                 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
966                                 i += sizeof(int32_t);
967                         }
968                         i = ni6->ni_flags;
969                         if (!i)
970                                 break;
971                         printf(" [%s%s%s%s%s%s%s]",
972                             (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
973                             (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
974                             (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
975                             (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
976                             (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
977                             (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
978                             (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
979                         break;
980                 default:
981                         if (needcomma)
982                                 printf(", ");
983                         printf("unknown");
984                         break;
985                 }
986
987                 /*(*/
988                 printf(")");
989                 break;
990         }
991         return;
992
993 trunc:
994         fputs("[|icmp6]", stdout);
995 }
996
997 static void
998 icmp6_rrenum_print(const u_char *bp, const u_char *ep)
999 {
1000         struct icmp6_router_renum *rr6;
1001         struct icmp6_hdr *dp;
1002         size_t siz;
1003         const char *cp;
1004         struct rr_pco_match *match;
1005         struct rr_pco_use *use;
1006         char hbuf[NI_MAXHOST];
1007         int n;
1008
1009         if (ep < bp)
1010                 return;
1011         dp = (struct icmp6_hdr *)bp;
1012         rr6 = (struct icmp6_router_renum *)bp;
1013         siz = ep - bp;
1014         cp = (const char *)(rr6 + 1);
1015
1016         TCHECK(rr6->rr_reserved);
1017         switch (rr6->rr_code) {
1018         case ICMP6_ROUTER_RENUMBERING_COMMAND:
1019                 printf("router renum: command");
1020                 break;
1021         case ICMP6_ROUTER_RENUMBERING_RESULT:
1022                 printf("router renum: result");
1023                 break;
1024         case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1025                 printf("router renum: sequence number reset");
1026                 break;
1027         default:
1028                 printf("router renum: code-#%d", rr6->rr_code);
1029                 break;
1030         }
1031
1032         printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
1033
1034         if (vflag) {
1035 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
1036                 printf("[");    /*]*/
1037                 if (rr6->rr_flags) {
1038                         printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1039                             F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1040                             F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1041                             F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1042                             F(ICMP6_RR_FLAGS_PREVDONE, "P"));
1043                 }
1044                 printf("seg=%u,", rr6->rr_segnum);
1045                 printf("maxdelay=%u", rr6->rr_maxdelay);
1046                 if (rr6->rr_reserved)
1047                         printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
1048                 /*[*/
1049                 printf("]");
1050 #undef F
1051         }
1052
1053         if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1054                 match = (struct rr_pco_match *)cp;
1055                 cp = (const char *)(match + 1);
1056
1057                 TCHECK(match->rpm_prefix);
1058
1059                 if (vflag > 1)
1060                         printf("\n\t");
1061                 else
1062                         printf(" ");
1063                 printf("match(");       /*)*/
1064                 switch (match->rpm_code) {
1065                 case RPM_PCO_ADD:       printf("add"); break;
1066                 case RPM_PCO_CHANGE:    printf("change"); break;
1067                 case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
1068                 default:                printf("#%u", match->rpm_code); break;
1069                 }
1070
1071                 if (vflag) {
1072                         printf(",ord=%u", match->rpm_ordinal);
1073                         printf(",min=%u", match->rpm_minlen);
1074                         printf(",max=%u", match->rpm_maxlen);
1075                 }
1076                 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
1077                         printf(",%s/%u", hbuf, match->rpm_matchlen);
1078                 else
1079                         printf(",?/%u", match->rpm_matchlen);
1080                 /*(*/
1081                 printf(")");
1082
1083                 n = match->rpm_len - 3;
1084                 if (n % 4)
1085                         goto trunc;
1086                 n /= 4;
1087                 while (n-- > 0) {
1088                         use = (struct rr_pco_use *)cp;
1089                         cp = (const char *)(use + 1);
1090
1091                         TCHECK(use->rpu_prefix);
1092
1093                         if (vflag > 1)
1094                                 printf("\n\t");
1095                         else
1096                                 printf(" ");
1097                         printf("use("); /*)*/
1098                         if (use->rpu_flags) {
1099 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
1100                                 printf("%s%s,",
1101                                     F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
1102                                     F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
1103 #undef F
1104                         }
1105                         if (vflag) {
1106                                 printf("mask=0x%x,", use->rpu_ramask);
1107                                 printf("raflags=0x%x,", use->rpu_raflags);
1108                                 if (~use->rpu_vltime == 0)
1109                                         printf("vltime=infty,");
1110                                 else
1111                                         printf("vltime=%u,",
1112                                             EXTRACT_32BITS(&use->rpu_vltime));
1113                                 if (~use->rpu_pltime == 0)
1114                                         printf("pltime=infty,");
1115                                 else
1116                                         printf("pltime=%u,",
1117                                             EXTRACT_32BITS(&use->rpu_pltime));
1118                         }
1119                         if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1120                             sizeof(hbuf)))
1121                                 printf("%s/%u/%u", hbuf, use->rpu_uselen,
1122                                     use->rpu_keeplen);
1123                         else
1124                                 printf("?/%u/%u", use->rpu_uselen,
1125                                     use->rpu_keeplen);
1126                         /*(*/
1127                         printf(")");
1128                 }
1129         }
1130
1131         return;
1132
1133 trunc:
1134         fputs("[|icmp6]", stdout);
1135 }
1136
1137 #endif /* INET6 */