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