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