Home | History | Annotate | Download | only in tcpdump
      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.86 2008-02-05 19:36:13 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 "interface.h"
     39 #include "addrtoname.h"
     40 #include "extract.h"
     41 
     42 #include "ip6.h"
     43 #include "icmp6.h"
     44 #include "ipproto.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 void mldv2_report_print(const u_char *, u_int);
     55 static void mldv2_query_print(const u_char *, u_int);
     56 static struct udphdr *get_upperlayer(u_char *, u_int *);
     57 static void dnsname_print(const u_char *, const u_char *);
     58 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
     59 static void icmp6_rrenum_print(const u_char *, const u_char *);
     60 
     61 #ifndef abs
     62 #define abs(a)	((0 < (a)) ? (a) : -(a))
     63 #endif
     64 
     65 /* inline the various RPL definitions */
     66 #define ND_RPL_MESSAGE 0x9B
     67 
     68 static const struct tok icmp6_type_values[] = {
     69     { ICMP6_DST_UNREACH, "destination unreachable"},
     70     { ICMP6_PACKET_TOO_BIG, "packet too big"},
     71     { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
     72     { ICMP6_PARAM_PROB, "parameter problem"},
     73     { ICMP6_ECHO_REQUEST, "echo request"},
     74     { ICMP6_ECHO_REPLY, "echo reply"},
     75     { MLD6_LISTENER_QUERY, "multicast listener query"},
     76     { MLD6_LISTENER_REPORT, "multicast listener report"},
     77     { MLD6_LISTENER_DONE, "multicast listener done"},
     78     { ND_ROUTER_SOLICIT, "router solicitation"},
     79     { ND_ROUTER_ADVERT, "router advertisement"},
     80     { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
     81     { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
     82     { ND_REDIRECT, "redirect"},
     83     { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
     84     { IND_SOLICIT, "inverse neighbor solicitation"},
     85     { IND_ADVERT, "inverse neighbor advertisement"},
     86     { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
     87     { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
     88     { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
     89     { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
     90     { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
     91     { ICMP6_WRUREQUEST, "who-are-you request"},
     92     { ICMP6_WRUREPLY, "who-are-you reply"},
     93     { ICMP6_NI_QUERY, "node information query"},
     94     { ICMP6_NI_REPLY, "node information reply"},
     95     { MLD6_MTRACE, "mtrace message"},
     96     { MLD6_MTRACE_RESP, "mtrace response"},
     97     { ND_RPL_MESSAGE,   "RPL"},
     98     { 0,	NULL }
     99 };
    100 
    101 static const struct tok icmp6_dst_unreach_code_values[] = {
    102     { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
    103     { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
    104     { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
    105     { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
    106     { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
    107     { 0,	NULL }
    108 };
    109 
    110 static const struct tok icmp6_opt_pi_flag_values[] = {
    111     { ND_OPT_PI_FLAG_ONLINK, "onlink" },
    112     { ND_OPT_PI_FLAG_AUTO, "auto" },
    113     { ND_OPT_PI_FLAG_ROUTER, "router" },
    114     { 0,	NULL }
    115 };
    116 
    117 static const struct tok icmp6_opt_ra_flag_values[] = {
    118     { ND_RA_FLAG_MANAGED, "managed" },
    119     { ND_RA_FLAG_OTHER, "other stateful"},
    120     { ND_RA_FLAG_HOME_AGENT, "home agent"},
    121     { 0,	NULL }
    122 };
    123 
    124 static const struct tok icmp6_nd_na_flag_values[] = {
    125     { ND_NA_FLAG_ROUTER, "router" },
    126     { ND_NA_FLAG_SOLICITED, "solicited" },
    127     { ND_NA_FLAG_OVERRIDE, "override" },
    128     { 0,	NULL }
    129 };
    130 
    131 
    132 static const struct tok icmp6_opt_values[] = {
    133    { ND_OPT_SOURCE_LINKADDR, "source link-address"},
    134    { ND_OPT_TARGET_LINKADDR, "destination link-address"},
    135    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
    136    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
    137    { ND_OPT_MTU, "mtu"},
    138    { ND_OPT_RDNSS, "rdnss"},
    139    { ND_OPT_DNSSL, "dnssl"},
    140    { ND_OPT_ADVINTERVAL, "advertisement interval"},
    141    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
    142    { ND_OPT_ROUTE_INFO, "route info"},
    143    { 0,	NULL }
    144 };
    145 
    146 /* mldv2 report types */
    147 static const struct tok mldv2report2str[] = {
    148 	{ 1,	"is_in" },
    149 	{ 2,	"is_ex" },
    150 	{ 3,	"to_in" },
    151 	{ 4,	"to_ex" },
    152 	{ 5,	"allow" },
    153 	{ 6,	"block" },
    154 	{ 0,	NULL }
    155 };
    156 
    157 static const char *
    158 get_rtpref(u_int v)
    159 {
    160 	static const char *rtpref_str[] = {
    161 		"medium",		/* 00 */
    162 		"high",			/* 01 */
    163 		"rsv",			/* 10 */
    164 		"low"			/* 11 */
    165 	};
    166 
    167 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
    168 }
    169 
    170 static const char *
    171 get_lifetime(u_int32_t v)
    172 {
    173 	static char buf[20];
    174 
    175 	if (v == (u_int32_t)~0UL)
    176 		return "infinity";
    177 	else {
    178 		snprintf(buf, sizeof(buf), "%us", v);
    179 		return buf;
    180 	}
    181 }
    182 
    183 static void
    184 print_lladdr(const u_int8_t *p, size_t l)
    185 {
    186 	const u_int8_t *ep, *q;
    187 
    188 	q = p;
    189 	ep = p + l;
    190 	while (l > 0 && q < ep) {
    191 		if (q > p)
    192 			printf(":");
    193 		printf("%02x", *q++);
    194 		l--;
    195 	}
    196 }
    197 
    198 static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
    199 	u_int len)
    200 {
    201 	return (nextproto6_cksum(ip6, (const u_int8_t *)(void *)icp, len,
    202 	    IPPROTO_ICMPV6));
    203 }
    204 
    205 enum ND_RPL_CODE {
    206         ND_RPL_DIS   =0x00,
    207         ND_RPL_DIO   =0x01,
    208         ND_RPL_DAO   =0x02,
    209         ND_RPL_DAO_ACK=0x03,
    210         ND_RPL_SDIS  =0x80,
    211         ND_RPL_SDIO  =0x81,
    212         ND_RPL_SDAO  =0x82,
    213         ND_RPL_SDAO_ACK=0x83,
    214         ND_RPL_SCC   =0x8A,
    215 };
    216 
    217 enum ND_RPL_DIO_FLAGS {
    218         ND_RPL_DIO_GROUNDED = 0x80,
    219         ND_RPL_DIO_DATRIG   = 0x40,
    220         ND_RPL_DIO_DASUPPORT= 0x20,
    221         ND_RPL_DIO_RES4     = 0x10,
    222         ND_RPL_DIO_RES3     = 0x08,
    223         ND_RPL_DIO_PRF_MASK = 0x07,  /* 3-bit preference */
    224 };
    225 
    226 struct nd_rpl_dio {
    227         u_int8_t rpl_flags;
    228         u_int8_t rpl_seq;
    229         u_int8_t rpl_instanceid;
    230         u_int8_t rpl_dagrank;
    231         u_int8_t rpl_dagid[16];
    232 };
    233 
    234 static void
    235 rpl_print(netdissect_options *ndo,
    236           const struct icmp6_hdr *hdr,
    237           const u_char *bp, u_int length _U_)
    238 {
    239         struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp;
    240         int secured = hdr->icmp6_code & 0x80;
    241         int basecode= hdr->icmp6_code & 0x7f;
    242 
    243         ND_TCHECK(dio->rpl_dagid);
    244 
    245         if(secured) {
    246                 ND_PRINT((ndo, ", (SEC)"));
    247         } else {
    248                 ND_PRINT((ndo, ", (CLR)"));
    249         }
    250 
    251         switch(basecode) {
    252         case ND_RPL_DIS:
    253                 ND_PRINT((ndo, "DODAG Information Solicitation"));
    254                 if(ndo->ndo_vflag) {
    255                 }
    256                 break;
    257         case ND_RPL_DIO:
    258                 ND_PRINT((ndo, "DODAG Information Object"));
    259                 if(ndo->ndo_vflag) {
    260                         char dagid[65];
    261                         char *d = dagid;
    262                         int  i;
    263                         for(i=0;i<16;i++) {
    264                                 if(isprint(dio->rpl_dagid[i])) {
    265                                         *d++ = dio->rpl_dagid[i];
    266                                 } else {
    267                                         int cnt=snprintf(d,4,"0x%02x",
    268                                                          dio->rpl_dagid[i]);
    269                                         d += cnt;
    270                                 }
    271                         }
    272                         *d++ = '\0';
    273                         ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]",
    274                                   dio->rpl_seq,
    275                                   dio->rpl_instanceid,
    276                                   dio->rpl_dagrank,
    277                                   dagid));
    278                 }
    279                 break;
    280         case ND_RPL_DAO:
    281                 ND_PRINT((ndo, "Destination Advertisement Object"));
    282                 if(ndo->ndo_vflag) {
    283                 }
    284                 break;
    285         case ND_RPL_DAO_ACK:
    286                 ND_PRINT((ndo, "Destination Advertisement Object Ack"));
    287                 if(ndo->ndo_vflag) {
    288                 }
    289                 break;
    290         default:
    291                 ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
    292                 break;
    293         }
    294 	return;
    295 trunc:
    296 	ND_PRINT((ndo," [|truncated]"));
    297 	return;
    298 
    299 }
    300 
    301 
    302 void
    303 icmp6_print(netdissect_options *ndo,
    304             const u_char *bp, u_int length, const u_char *bp2, int fragmented)
    305 {
    306 	const struct icmp6_hdr *dp;
    307 	const struct ip6_hdr *ip;
    308 	const struct ip6_hdr *oip;
    309 	const struct udphdr *ouh;
    310 	int dport;
    311 	const u_char *ep;
    312 	u_int prot;
    313 
    314 	dp = (struct icmp6_hdr *)bp;
    315 	ip = (struct ip6_hdr *)bp2;
    316 	oip = (struct ip6_hdr *)(dp + 1);
    317 	/* 'ep' points to the end of available data. */
    318 	ep = snapend;
    319 
    320 	TCHECK(dp->icmp6_cksum);
    321 
    322 	if (vflag && !fragmented) {
    323 		u_int16_t sum, udp_sum;
    324 
    325 		if (TTEST2(bp[0], length)) {
    326 			udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
    327 			sum = icmp6_cksum(ip, dp, length);
    328 			if (sum != 0)
    329 				(void)printf("[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
    330 				    udp_sum,
    331 				    in_cksum_shouldbe(udp_sum, sum));
    332 			else
    333 				(void)printf("[icmp6 sum ok] ");
    334 		}
    335 	}
    336 
    337         printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
    338 
    339         /* display cosmetics: print the packet length for printer that use the vflag now */
    340         if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT ||
    341                       dp->icmp6_type == ND_ROUTER_ADVERT ||
    342                       dp->icmp6_type == ND_NEIGHBOR_ADVERT ||
    343                       dp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
    344                       dp->icmp6_type == ND_REDIRECT ||
    345                       dp->icmp6_type == ICMP6_HADISCOV_REPLY ||
    346                       dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
    347             printf(", length %u", length);
    348 
    349 	switch (dp->icmp6_type) {
    350 	case ICMP6_DST_UNREACH:
    351 		TCHECK(oip->ip6_dst);
    352                 printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
    353 		switch (dp->icmp6_code) {
    354 
    355 		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
    356 		case ICMP6_DST_UNREACH_ADMIN:
    357 		case ICMP6_DST_UNREACH_ADDR:
    358                         printf(" %s",ip6addr_string(&oip->ip6_dst));
    359                         break;
    360 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
    361 			printf(" %s, source address %s",
    362 			       ip6addr_string(&oip->ip6_dst),
    363 			       ip6addr_string(&oip->ip6_src));
    364 			break;
    365 		case ICMP6_DST_UNREACH_NOPORT:
    366 			if ((ouh = get_upperlayer((u_char *)oip, &prot))
    367 			    == NULL)
    368 				goto trunc;
    369 
    370 			dport = EXTRACT_16BITS(&ouh->uh_dport);
    371 			switch (prot) {
    372 			case IPPROTO_TCP:
    373 				printf(", %s tcp port %s",
    374 					ip6addr_string(&oip->ip6_dst),
    375 					tcpport_string(dport));
    376 				break;
    377 			case IPPROTO_UDP:
    378 				printf(", %s udp port %s",
    379 					ip6addr_string(&oip->ip6_dst),
    380 					udpport_string(dport));
    381 				break;
    382 			default:
    383 				printf(", %s protocol %d port %d unreachable",
    384 					ip6addr_string(&oip->ip6_dst),
    385 					oip->ip6_nxt, dport);
    386 				break;
    387 			}
    388 			break;
    389 		default:
    390                     if (vflag <= 1) {
    391                             print_unknown_data(bp,"\n\t",length);
    392                             return;
    393                     }
    394                     break;
    395 		}
    396 		break;
    397 	case ICMP6_PACKET_TOO_BIG:
    398 		TCHECK(dp->icmp6_mtu);
    399 		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
    400 		break;
    401 	case ICMP6_TIME_EXCEEDED:
    402 		TCHECK(oip->ip6_dst);
    403 		switch (dp->icmp6_code) {
    404 		case ICMP6_TIME_EXCEED_TRANSIT:
    405 			printf(" for %s",
    406 				ip6addr_string(&oip->ip6_dst));
    407 			break;
    408 		case ICMP6_TIME_EXCEED_REASSEMBLY:
    409 			printf(" (reassembly)");
    410 			break;
    411 		default:
    412 			printf(", unknown code (%u)", dp->icmp6_code);
    413 			break;
    414 		}
    415 		break;
    416 	case ICMP6_PARAM_PROB:
    417 		TCHECK(oip->ip6_dst);
    418 		switch (dp->icmp6_code) {
    419 		case ICMP6_PARAMPROB_HEADER:
    420 			printf(", erroneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
    421 			break;
    422 		case ICMP6_PARAMPROB_NEXTHEADER:
    423 			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
    424 			break;
    425 		case ICMP6_PARAMPROB_OPTION:
    426 			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
    427 			break;
    428 		default:
    429 			printf(", code-#%d",
    430 			       dp->icmp6_code);
    431 			break;
    432 		}
    433 		break;
    434 	case ICMP6_ECHO_REQUEST:
    435 	case ICMP6_ECHO_REPLY:
    436 		TCHECK(dp->icmp6_seq);
    437 		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
    438 		break;
    439 	case ICMP6_MEMBERSHIP_QUERY:
    440 		if (length == MLD_MINLEN) {
    441 			mld6_print((const u_char *)dp);
    442 		} else if (length >= MLDV2_MINLEN) {
    443 			printf(" v2");
    444 			mldv2_query_print((const u_char *)dp, length);
    445 		} else {
    446 			printf(" unknown-version (len %u) ", length);
    447 		}
    448 		break;
    449 	case ICMP6_MEMBERSHIP_REPORT:
    450 		mld6_print((const u_char *)dp);
    451 		break;
    452 	case ICMP6_MEMBERSHIP_REDUCTION:
    453 		mld6_print((const u_char *)dp);
    454 		break;
    455 	case ND_ROUTER_SOLICIT:
    456 #define RTSOLLEN 8
    457 		if (vflag) {
    458 			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
    459 					length - RTSOLLEN);
    460 		}
    461 		break;
    462 	case ND_ROUTER_ADVERT:
    463 #define RTADVLEN 16
    464 		if (vflag) {
    465 			struct nd_router_advert *p;
    466 
    467 			p = (struct nd_router_advert *)dp;
    468 			TCHECK(p->nd_ra_retransmit);
    469 			printf("\n\thop limit %u, Flags [%s]" \
    470                                ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
    471                                (u_int)p->nd_ra_curhoplimit,
    472                                bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
    473                                get_rtpref(p->nd_ra_flags_reserved),
    474                                EXTRACT_16BITS(&p->nd_ra_router_lifetime),
    475                                EXTRACT_32BITS(&p->nd_ra_reachable),
    476                                EXTRACT_32BITS(&p->nd_ra_retransmit));
    477 
    478 			icmp6_opt_print((const u_char *)dp + RTADVLEN,
    479 					length - RTADVLEN);
    480 		}
    481 		break;
    482 	case ND_NEIGHBOR_SOLICIT:
    483 	    {
    484 		struct nd_neighbor_solicit *p;
    485 		p = (struct nd_neighbor_solicit *)dp;
    486 		TCHECK(p->nd_ns_target);
    487 		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
    488 		if (vflag) {
    489 #define NDSOLLEN 24
    490 			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
    491 					length - NDSOLLEN);
    492 		}
    493 	    }
    494 		break;
    495 	case ND_NEIGHBOR_ADVERT:
    496 	    {
    497 		struct nd_neighbor_advert *p;
    498 
    499 		p = (struct nd_neighbor_advert *)dp;
    500 		TCHECK(p->nd_na_target);
    501 		printf(", tgt is %s",
    502 			ip6addr_string(&p->nd_na_target));
    503 		if (vflag) {
    504                         printf(", Flags [%s]",
    505                                bittok2str(icmp6_nd_na_flag_values,
    506                                           "none",
    507                                           EXTRACT_32BITS(&p->nd_na_flags_reserved)));
    508 #define NDADVLEN 24
    509 			icmp6_opt_print((const u_char *)dp + NDADVLEN,
    510 					length - NDADVLEN);
    511 #undef NDADVLEN
    512 		}
    513 	    }
    514 		break;
    515 	case ND_REDIRECT:
    516 #define RDR(i) ((struct nd_redirect *)(i))
    517 		TCHECK(RDR(dp)->nd_rd_dst);
    518 		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
    519 		TCHECK(RDR(dp)->nd_rd_target);
    520 		printf(" to %s",
    521 		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
    522 #define REDIRECTLEN 40
    523 		if (vflag) {
    524 			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
    525 					length - REDIRECTLEN);
    526 		}
    527 		break;
    528 #undef REDIRECTLEN
    529 #undef RDR
    530 	case ICMP6_ROUTER_RENUMBERING:
    531 		icmp6_rrenum_print(bp, ep);
    532 		break;
    533 	case ICMP6_NI_QUERY:
    534 	case ICMP6_NI_REPLY:
    535 		icmp6_nodeinfo_print(length, bp, ep);
    536 		break;
    537 	case IND_SOLICIT:
    538 	case IND_ADVERT:
    539 		break;
    540 	case ICMP6_V2_MEMBERSHIP_REPORT:
    541 		mldv2_report_print((const u_char *) dp, length);
    542 		break;
    543 	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
    544 	case ICMP6_HADISCOV_REQUEST:
    545                 TCHECK(dp->icmp6_data16[0]);
    546                 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
    547                 break;
    548 	case ICMP6_HADISCOV_REPLY:
    549 		if (vflag) {
    550 			struct in6_addr *in6;
    551 			u_char *cp;
    552 
    553 			TCHECK(dp->icmp6_data16[0]);
    554 			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
    555 			cp = (u_char *)dp + length;
    556 			in6 = (struct in6_addr *)(dp + 1);
    557 			for (; (u_char *)in6 < cp; in6++) {
    558 				TCHECK(*in6);
    559 				printf(", %s", ip6addr_string(in6));
    560 			}
    561 		}
    562 		break;
    563 	case ICMP6_MOBILEPREFIX_ADVERT:
    564 		if (vflag) {
    565 			TCHECK(dp->icmp6_data16[0]);
    566 			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
    567 			if (dp->icmp6_data16[1] & 0xc0)
    568 				printf(" ");
    569 			if (dp->icmp6_data16[1] & 0x80)
    570 				printf("M");
    571 			if (dp->icmp6_data16[1] & 0x40)
    572 				printf("O");
    573 #define MPADVLEN 8
    574 			icmp6_opt_print((const u_char *)dp + MPADVLEN,
    575 					length - MPADVLEN);
    576 		}
    577 		break;
    578         case ND_RPL_MESSAGE:
    579                 rpl_print(ndo, dp, &dp->icmp6_data8[0], length);
    580                 break;
    581 	default:
    582                 printf(", length %u", length);
    583                 if (vflag <= 1)
    584                     print_unknown_data(bp,"\n\t", length);
    585                 return;
    586         }
    587         if (!vflag)
    588             printf(", length %u", length);
    589 	return;
    590 trunc:
    591 	fputs("[|icmp6]", stdout);
    592 }
    593 
    594 static struct udphdr *
    595 get_upperlayer(u_char *bp, u_int *prot)
    596 {
    597 	const u_char *ep;
    598 	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
    599 	struct udphdr *uh;
    600 	struct ip6_hbh *hbh;
    601 	struct ip6_frag *fragh;
    602 	struct ah *ah;
    603 	u_int nh;
    604 	int hlen;
    605 
    606 	/* 'ep' points to the end of available data. */
    607 	ep = snapend;
    608 
    609 	if (!TTEST(ip6->ip6_nxt))
    610 		return NULL;
    611 
    612 	nh = ip6->ip6_nxt;
    613 	hlen = sizeof(struct ip6_hdr);
    614 
    615 	while (bp < ep) {
    616 		bp += hlen;
    617 
    618 		switch(nh) {
    619 		case IPPROTO_UDP:
    620 		case IPPROTO_TCP:
    621 			uh = (struct udphdr *)bp;
    622 			if (TTEST(uh->uh_dport)) {
    623 				*prot = nh;
    624 				return(uh);
    625 			}
    626 			else
    627 				return(NULL);
    628 			/* NOTREACHED */
    629 
    630 		case IPPROTO_HOPOPTS:
    631 		case IPPROTO_DSTOPTS:
    632 		case IPPROTO_ROUTING:
    633 			hbh = (struct ip6_hbh *)bp;
    634 			if (!TTEST(hbh->ip6h_len))
    635 				return(NULL);
    636 			nh = hbh->ip6h_nxt;
    637 			hlen = (hbh->ip6h_len + 1) << 3;
    638 			break;
    639 
    640 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
    641 			fragh = (struct ip6_frag *)bp;
    642 			if (!TTEST(fragh->ip6f_offlg))
    643 				return(NULL);
    644 			/* fragments with non-zero offset are meaningless */
    645 			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
    646 				return(NULL);
    647 			nh = fragh->ip6f_nxt;
    648 			hlen = sizeof(struct ip6_frag);
    649 			break;
    650 
    651 		case IPPROTO_AH:
    652 			ah = (struct ah *)bp;
    653 			if (!TTEST(ah->ah_len))
    654 				return(NULL);
    655 			nh = ah->ah_nxt;
    656 			hlen = (ah->ah_len + 2) << 2;
    657 			break;
    658 
    659 		default:	/* unknown or undecodable header */
    660 			*prot = nh; /* meaningless, but set here anyway */
    661 			return(NULL);
    662 		}
    663 	}
    664 
    665 	return(NULL);		/* should be notreached, though */
    666 }
    667 
    668 static void
    669 icmp6_opt_print(const u_char *bp, int resid)
    670 {
    671 	const struct nd_opt_hdr *op;
    672 	const struct nd_opt_prefix_info *opp;
    673 	const struct nd_opt_mtu *opm;
    674 	const struct nd_opt_rdnss *oprd;
    675 	const struct nd_opt_dnssl *opds;
    676 	const struct nd_opt_advinterval *opa;
    677 	const struct nd_opt_homeagent_info *oph;
    678 	const struct nd_opt_route_info *opri;
    679 	const u_char *cp, *ep, *domp;
    680 	struct in6_addr in6, *in6p;
    681 	size_t l;
    682 	u_int i;
    683 
    684 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
    685 
    686 	cp = bp;
    687 	/* 'ep' points to the end of available data. */
    688 	ep = snapend;
    689 
    690 	while (cp < ep) {
    691 		op = (struct nd_opt_hdr *)cp;
    692 
    693 		ECHECK(op->nd_opt_len);
    694 		if (resid <= 0)
    695 			return;
    696 		if (op->nd_opt_len == 0)
    697 			goto trunc;
    698 		if (cp + (op->nd_opt_len << 3) > ep)
    699 			goto trunc;
    700 
    701                 printf("\n\t  %s option (%u), length %u (%u): ",
    702                        tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
    703                        op->nd_opt_type,
    704                        op->nd_opt_len << 3,
    705                        op->nd_opt_len);
    706 
    707 		switch (op->nd_opt_type) {
    708 		case ND_OPT_SOURCE_LINKADDR:
    709 			l = (op->nd_opt_len << 3) - 2;
    710 			print_lladdr(cp + 2, l);
    711 			break;
    712 		case ND_OPT_TARGET_LINKADDR:
    713 			l = (op->nd_opt_len << 3) - 2;
    714 			print_lladdr(cp + 2, l);
    715 			break;
    716 		case ND_OPT_PREFIX_INFORMATION:
    717 			opp = (struct nd_opt_prefix_info *)op;
    718 			TCHECK(opp->nd_opt_pi_prefix);
    719                         printf("%s/%u%s, Flags [%s], valid time %s",
    720                                ip6addr_string(&opp->nd_opt_pi_prefix),
    721                                opp->nd_opt_pi_prefix_len,
    722                                (op->nd_opt_len != 4) ? "badlen" : "",
    723                                bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
    724                                get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
    725                         printf(", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
    726 			break;
    727 		case ND_OPT_REDIRECTED_HEADER:
    728                         print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
    729 			/* xxx */
    730 			break;
    731 		case ND_OPT_MTU:
    732 			opm = (struct nd_opt_mtu *)op;
    733 			TCHECK(opm->nd_opt_mtu_mtu);
    734 			printf(" %u%s",
    735                                EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
    736                                (op->nd_opt_len != 1) ? "bad option length" : "" );
    737                         break;
    738 		case ND_OPT_RDNSS:
    739 			oprd = (struct nd_opt_rdnss *)op;
    740 			l = (op->nd_opt_len - 1) / 2;
    741 			printf(" lifetime %us,",
    742 				EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime));
    743 			for (i = 0; i < l; i++) {
    744 				TCHECK(oprd->nd_opt_rdnss_addr[i]);
    745 				printf(" addr: %s",
    746 				    ip6addr_string(&oprd->nd_opt_rdnss_addr[i]));
    747 			}
    748 			break;
    749 		case ND_OPT_DNSSL:
    750 			opds = (struct nd_opt_dnssl *)op;
    751 			printf(" lifetime %us, domain(s):",
    752 				EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime));
    753 			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
    754 			while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0')
    755 			{
    756 				printf (" ");
    757 				if ((domp = ns_nprint (domp, bp)) == NULL)
    758 					goto trunc;
    759 			}
    760 			break;
    761 		case ND_OPT_ADVINTERVAL:
    762 			opa = (struct nd_opt_advinterval *)op;
    763 			TCHECK(opa->nd_opt_adv_interval);
    764 			printf(" %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
    765 			break;
    766 		case ND_OPT_HOMEAGENT_INFO:
    767 			oph = (struct nd_opt_homeagent_info *)op;
    768 			TCHECK(oph->nd_opt_hai_lifetime);
    769 			printf(" preference %u, lifetime %u",
    770                                EXTRACT_16BITS(&oph->nd_opt_hai_preference),
    771                                EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
    772 			break;
    773 		case ND_OPT_ROUTE_INFO:
    774 			opri = (struct nd_opt_route_info *)op;
    775 			TCHECK(opri->nd_opt_rti_lifetime);
    776 			memset(&in6, 0, sizeof(in6));
    777 			in6p = (struct in6_addr *)(opri + 1);
    778 			switch (op->nd_opt_len) {
    779 			case 1:
    780 				break;
    781 			case 2:
    782 				TCHECK2(*in6p, 8);
    783 				memcpy(&in6, opri + 1, 8);
    784 				break;
    785 			case 3:
    786 				TCHECK(*in6p);
    787 				memcpy(&in6, opri + 1, sizeof(in6));
    788 				break;
    789 			default:
    790 				goto trunc;
    791 			}
    792 			printf(" %s/%u", ip6addr_string(&in6),
    793 			    opri->nd_opt_rti_prefixlen);
    794 			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
    795 			printf(", lifetime=%s",
    796 			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
    797 			break;
    798 		default:
    799                         if (vflag <= 1) {
    800                             print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
    801                             return;
    802                         }
    803                         break;
    804 		}
    805                 /* do we want to see an additional hexdump ? */
    806                 if (vflag> 1)
    807                     print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
    808 
    809 		cp += op->nd_opt_len << 3;
    810 		resid -= op->nd_opt_len << 3;
    811 	}
    812 	return;
    813 
    814  trunc:
    815 	fputs("[ndp opt]", stdout);
    816 	return;
    817 #undef ECHECK
    818 }
    819 
    820 static void
    821 mld6_print(const u_char *bp)
    822 {
    823 	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
    824 	const u_char *ep;
    825 
    826 	/* 'ep' points to the end of available data. */
    827 	ep = snapend;
    828 
    829 	if ((u_char *)mp + sizeof(*mp) > ep)
    830 		return;
    831 
    832 	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
    833 	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
    834 }
    835 
    836 static void
    837 mldv2_report_print(const u_char *bp, u_int len)
    838 {
    839     struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
    840     u_int group, nsrcs, ngroups;
    841     u_int i, j;
    842 
    843     /* Minimum len is 8 */
    844     if (len < 8) {
    845 	printf(" [invalid len %d]", len);
    846 	return;
    847     }
    848 
    849     TCHECK(icp->icmp6_data16[1]);
    850     ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
    851     printf(", %d group record(s)", ngroups);
    852     if (vflag > 0) {
    853 	/* Print the group records */
    854 	group = 8;
    855         for (i = 0; i < ngroups; i++) {
    856 	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
    857 	    if (len < group + 20) {
    858 		printf(" [invalid number of groups]");
    859 		return;
    860 	    }
    861             TCHECK2(bp[group + 4], sizeof(struct in6_addr));
    862             printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
    863 	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
    864 								bp[group]));
    865             nsrcs = (bp[group + 2] << 8) + bp[group + 3];
    866 	    /* Check the number of sources and print them */
    867 	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
    868 		printf(" [invalid number of sources %d]", nsrcs);
    869 		return;
    870 	    }
    871             if (vflag == 1)
    872                 printf(", %d source(s)", nsrcs);
    873             else {
    874 		/* Print the sources */
    875                 (void)printf(" {");
    876                 for (j = 0; j < nsrcs; j++) {
    877                     TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
    878                             sizeof(struct in6_addr));
    879 		    printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)]));
    880 		}
    881                 (void)printf(" }");
    882             }
    883 	    /* Next group record */
    884             group += 20 + nsrcs * sizeof(struct in6_addr);
    885 	    printf("]");
    886         }
    887     }
    888     return;
    889 trunc:
    890     (void)printf("[|icmp6]");
    891     return;
    892 }
    893 
    894 static void
    895 mldv2_query_print(const u_char *bp, u_int len)
    896 {
    897     struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
    898     u_int mrc;
    899     int mrt, qqi;
    900     u_int nsrcs;
    901     register u_int i;
    902 
    903     /* Minimum len is 28 */
    904     if (len < 28) {
    905 	printf(" [invalid len %d]", len);
    906 	return;
    907     }
    908     TCHECK(icp->icmp6_data16[0]);
    909     mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
    910     if (mrc < 32768) {
    911 	mrt = mrc;
    912     } else {
    913         mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
    914     }
    915     if (vflag) {
    916 	(void)printf(" [max resp delay=%d]", mrt);
    917     }
    918     TCHECK2(bp[8], sizeof(struct in6_addr));
    919     printf(" [gaddr %s", ip6addr_string(&bp[8]));
    920 
    921     if (vflag) {
    922         TCHECK(bp[25]);
    923 	if (bp[24] & 0x08) {
    924 		printf(" sflag");
    925 	}
    926 	if (bp[24] & 0x07) {
    927 		printf(" robustness=%d", bp[24] & 0x07);
    928 	}
    929 	if (bp[25] < 128) {
    930 		qqi = bp[25];
    931 	} else {
    932 		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
    933 	}
    934 	printf(" qqi=%d", qqi);
    935     }
    936 
    937     TCHECK2(bp[26], 2);
    938     nsrcs = EXTRACT_16BITS(&bp[26]);
    939     if (nsrcs > 0) {
    940 	if (len < 28 + nsrcs * sizeof(struct in6_addr))
    941 	    printf(" [invalid number of sources]");
    942 	else if (vflag > 1) {
    943 	    printf(" {");
    944 	    for (i = 0; i < nsrcs; i++) {
    945 		TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
    946                         sizeof(struct in6_addr));
    947 		printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)]));
    948 	    }
    949 	    printf(" }");
    950 	} else
    951 	    printf(", %d source(s)", nsrcs);
    952     }
    953     printf("]");
    954     return;
    955 trunc:
    956     (void)printf("[|icmp6]");
    957     return;
    958 }
    959 
    960 static void
    961 dnsname_print(const u_char *cp, const u_char *ep)
    962 {
    963 	int i;
    964 
    965 	/* DNS name decoding - no decompression */
    966 	printf(", \"");
    967 	while (cp < ep) {
    968 		i = *cp++;
    969 		if (i) {
    970 			if (i > ep - cp) {
    971 				printf("???");
    972 				break;
    973 			}
    974 			while (i-- && cp < ep) {
    975 				safeputchar(*cp);
    976 				cp++;
    977 			}
    978 			if (cp + 1 < ep && *cp)
    979 				printf(".");
    980 		} else {
    981 			if (cp == ep) {
    982 				/* FQDN */
    983 				printf(".");
    984 			} else if (cp + 1 == ep && *cp == '\0') {
    985 				/* truncated */
    986 			} else {
    987 				/* invalid */
    988 				printf("???");
    989 			}
    990 			break;
    991 		}
    992 	}
    993 	printf("\"");
    994 }
    995 
    996 static void
    997 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
    998 {
    999 	struct icmp6_nodeinfo *ni6;
   1000 	struct icmp6_hdr *dp;
   1001 	const u_char *cp;
   1002 	size_t siz, i;
   1003 	int needcomma;
   1004 
   1005 	if (ep < bp)
   1006 		return;
   1007 	dp = (struct icmp6_hdr *)bp;
   1008 	ni6 = (struct icmp6_nodeinfo *)bp;
   1009 	siz = ep - bp;
   1010 
   1011 	switch (ni6->ni_type) {
   1012 	case ICMP6_NI_QUERY:
   1013 		if (siz == sizeof(*dp) + 4) {
   1014 			/* KAME who-are-you */
   1015 			printf(" who-are-you request");
   1016 			break;
   1017 		}
   1018 		printf(" node information query");
   1019 
   1020 		TCHECK2(*dp, sizeof(*ni6));
   1021 		ni6 = (struct icmp6_nodeinfo *)dp;
   1022 		printf(" (");	/*)*/
   1023 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
   1024 		case NI_QTYPE_NOOP:
   1025 			printf("noop");
   1026 			break;
   1027 		case NI_QTYPE_SUPTYPES:
   1028 			printf("supported qtypes");
   1029 			i = EXTRACT_16BITS(&ni6->ni_flags);
   1030 			if (i)
   1031 				printf(" [%s]", (i & 0x01) ? "C" : "");
   1032 			break;
   1033 			break;
   1034 		case NI_QTYPE_FQDN:
   1035 			printf("DNS name");
   1036 			break;
   1037 		case NI_QTYPE_NODEADDR:
   1038 			printf("node addresses");
   1039 			i = ni6->ni_flags;
   1040 			if (!i)
   1041 				break;
   1042 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
   1043 			printf(" [%s%s%s%s%s%s]",
   1044 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
   1045 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
   1046 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
   1047 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
   1048 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
   1049 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
   1050 			break;
   1051 		default:
   1052 			printf("unknown");
   1053 			break;
   1054 		}
   1055 
   1056 		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
   1057 		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
   1058 			if (siz != sizeof(*ni6))
   1059 				if (vflag)
   1060 					printf(", invalid len");
   1061 			/*(*/
   1062 			printf(")");
   1063 			break;
   1064 		}
   1065 
   1066 
   1067 		/* XXX backward compat, icmp-name-lookup-03 */
   1068 		if (siz == sizeof(*ni6)) {
   1069 			printf(", 03 draft");
   1070 			/*(*/
   1071 			printf(")");
   1072 			break;
   1073 		}
   1074 
   1075 		switch (ni6->ni_code) {
   1076 		case ICMP6_NI_SUBJ_IPV6:
   1077 			if (!TTEST2(*dp,
   1078 			    sizeof(*ni6) + sizeof(struct in6_addr)))
   1079 				break;
   1080 			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
   1081 				if (vflag)
   1082 					printf(", invalid subject len");
   1083 				break;
   1084 			}
   1085 			printf(", subject=%s",
   1086 			    getname6((const u_char *)(ni6 + 1)));
   1087 			break;
   1088 		case ICMP6_NI_SUBJ_FQDN:
   1089 			printf(", subject=DNS name");
   1090 			cp = (const u_char *)(ni6 + 1);
   1091 			if (cp[0] == ep - cp - 1) {
   1092 				/* icmp-name-lookup-03, pascal string */
   1093 				if (vflag)
   1094 					printf(", 03 draft");
   1095 				cp++;
   1096 				printf(", \"");
   1097 				while (cp < ep) {
   1098 					safeputchar(*cp);
   1099 					cp++;
   1100 				}
   1101 				printf("\"");
   1102 			} else
   1103 				dnsname_print(cp, ep);
   1104 			break;
   1105 		case ICMP6_NI_SUBJ_IPV4:
   1106 			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
   1107 				break;
   1108 			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
   1109 				if (vflag)
   1110 					printf(", invalid subject len");
   1111 				break;
   1112 			}
   1113 			printf(", subject=%s",
   1114 			    getname((const u_char *)(ni6 + 1)));
   1115 			break;
   1116 		default:
   1117 			printf(", unknown subject");
   1118 			break;
   1119 		}
   1120 
   1121 		/*(*/
   1122 		printf(")");
   1123 		break;
   1124 
   1125 	case ICMP6_NI_REPLY:
   1126 		if (icmp6len > siz) {
   1127 			printf("[|icmp6: node information reply]");
   1128 			break;
   1129 		}
   1130 
   1131 		needcomma = 0;
   1132 
   1133 		ni6 = (struct icmp6_nodeinfo *)dp;
   1134 		printf(" node information reply");
   1135 		printf(" (");	/*)*/
   1136 		switch (ni6->ni_code) {
   1137 		case ICMP6_NI_SUCCESS:
   1138 			if (vflag) {
   1139 				printf("success");
   1140 				needcomma++;
   1141 			}
   1142 			break;
   1143 		case ICMP6_NI_REFUSED:
   1144 			printf("refused");
   1145 			needcomma++;
   1146 			if (siz != sizeof(*ni6))
   1147 				if (vflag)
   1148 					printf(", invalid length");
   1149 			break;
   1150 		case ICMP6_NI_UNKNOWN:
   1151 			printf("unknown");
   1152 			needcomma++;
   1153 			if (siz != sizeof(*ni6))
   1154 				if (vflag)
   1155 					printf(", invalid length");
   1156 			break;
   1157 		}
   1158 
   1159 		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
   1160 			/*(*/
   1161 			printf(")");
   1162 			break;
   1163 		}
   1164 
   1165 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
   1166 		case NI_QTYPE_NOOP:
   1167 			if (needcomma)
   1168 				printf(", ");
   1169 			printf("noop");
   1170 			if (siz != sizeof(*ni6))
   1171 				if (vflag)
   1172 					printf(", invalid length");
   1173 			break;
   1174 		case NI_QTYPE_SUPTYPES:
   1175 			if (needcomma)
   1176 				printf(", ");
   1177 			printf("supported qtypes");
   1178 			i = EXTRACT_16BITS(&ni6->ni_flags);
   1179 			if (i)
   1180 				printf(" [%s]", (i & 0x01) ? "C" : "");
   1181 			break;
   1182 		case NI_QTYPE_FQDN:
   1183 			if (needcomma)
   1184 				printf(", ");
   1185 			printf("DNS name");
   1186 			cp = (const u_char *)(ni6 + 1) + 4;
   1187 			if (cp[0] == ep - cp - 1) {
   1188 				/* icmp-name-lookup-03, pascal string */
   1189 				if (vflag)
   1190 					printf(", 03 draft");
   1191 				cp++;
   1192 				printf(", \"");
   1193 				while (cp < ep) {
   1194 					safeputchar(*cp);
   1195 					cp++;
   1196 				}
   1197 				printf("\"");
   1198 			} else
   1199 				dnsname_print(cp, ep);
   1200 			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
   1201 				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
   1202 			break;
   1203 		case NI_QTYPE_NODEADDR:
   1204 			if (needcomma)
   1205 				printf(", ");
   1206 			printf("node addresses");
   1207 			i = sizeof(*ni6);
   1208 			while (i < siz) {
   1209 				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
   1210 					break;
   1211 				printf(" %s", getname6(bp + i));
   1212 				i += sizeof(struct in6_addr);
   1213 				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
   1214 				i += sizeof(int32_t);
   1215 			}
   1216 			i = ni6->ni_flags;
   1217 			if (!i)
   1218 				break;
   1219 			printf(" [%s%s%s%s%s%s%s]",
   1220 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
   1221 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
   1222 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
   1223 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
   1224 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
   1225 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
   1226 			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
   1227 			break;
   1228 		default:
   1229 			if (needcomma)
   1230 				printf(", ");
   1231 			printf("unknown");
   1232 			break;
   1233 		}
   1234 
   1235 		/*(*/
   1236 		printf(")");
   1237 		break;
   1238 	}
   1239 	return;
   1240 
   1241 trunc:
   1242 	fputs("[|icmp6]", stdout);
   1243 }
   1244 
   1245 static void
   1246 icmp6_rrenum_print(const u_char *bp, const u_char *ep)
   1247 {
   1248 	struct icmp6_router_renum *rr6;
   1249 	const char *cp;
   1250 	struct rr_pco_match *match;
   1251 	struct rr_pco_use *use;
   1252 	char hbuf[NI_MAXHOST];
   1253 	int n;
   1254 
   1255 	if (ep < bp)
   1256 		return;
   1257 	rr6 = (struct icmp6_router_renum *)bp;
   1258 	cp = (const char *)(rr6 + 1);
   1259 
   1260 	TCHECK(rr6->rr_reserved);
   1261 	switch (rr6->rr_code) {
   1262 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
   1263 		printf("router renum: command");
   1264 		break;
   1265 	case ICMP6_ROUTER_RENUMBERING_RESULT:
   1266 		printf("router renum: result");
   1267 		break;
   1268 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
   1269 		printf("router renum: sequence number reset");
   1270 		break;
   1271 	default:
   1272 		printf("router renum: code-#%d", rr6->rr_code);
   1273 		break;
   1274 	}
   1275 
   1276 	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
   1277 
   1278 	if (vflag) {
   1279 #define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
   1280 		printf("[");	/*]*/
   1281 		if (rr6->rr_flags) {
   1282 			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
   1283 			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
   1284 			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
   1285 			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
   1286 			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
   1287 		}
   1288 		printf("seg=%u,", rr6->rr_segnum);
   1289 		printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
   1290 		if (rr6->rr_reserved)
   1291 			printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
   1292 		/*[*/
   1293 		printf("]");
   1294 #undef F
   1295 	}
   1296 
   1297 	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
   1298 		match = (struct rr_pco_match *)cp;
   1299 		cp = (const char *)(match + 1);
   1300 
   1301 		TCHECK(match->rpm_prefix);
   1302 
   1303 		if (vflag > 1)
   1304 			printf("\n\t");
   1305 		else
   1306 			printf(" ");
   1307 		printf("match(");	/*)*/
   1308 		switch (match->rpm_code) {
   1309 		case RPM_PCO_ADD:	printf("add"); break;
   1310 		case RPM_PCO_CHANGE:	printf("change"); break;
   1311 		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
   1312 		default:		printf("#%u", match->rpm_code); break;
   1313 		}
   1314 
   1315 		if (vflag) {
   1316 			printf(",ord=%u", match->rpm_ordinal);
   1317 			printf(",min=%u", match->rpm_minlen);
   1318 			printf(",max=%u", match->rpm_maxlen);
   1319 		}
   1320 		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
   1321 			printf(",%s/%u", hbuf, match->rpm_matchlen);
   1322 		else
   1323 			printf(",?/%u", match->rpm_matchlen);
   1324 		/*(*/
   1325 		printf(")");
   1326 
   1327 		n = match->rpm_len - 3;
   1328 		if (n % 4)
   1329 			goto trunc;
   1330 		n /= 4;
   1331 		while (n-- > 0) {
   1332 			use = (struct rr_pco_use *)cp;
   1333 			cp = (const char *)(use + 1);
   1334 
   1335 			TCHECK(use->rpu_prefix);
   1336 
   1337 			if (vflag > 1)
   1338 				printf("\n\t");
   1339 			else
   1340 				printf(" ");
   1341 			printf("use(");	/*)*/
   1342 			if (use->rpu_flags) {
   1343 #define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
   1344 				printf("%s%s,",
   1345 				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
   1346 				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
   1347 #undef F
   1348 			}
   1349 			if (vflag) {
   1350 				printf("mask=0x%x,", use->rpu_ramask);
   1351 				printf("raflags=0x%x,", use->rpu_raflags);
   1352 				if (~use->rpu_vltime == 0)
   1353 					printf("vltime=infty,");
   1354 				else
   1355 					printf("vltime=%u,",
   1356 					    EXTRACT_32BITS(&use->rpu_vltime));
   1357 				if (~use->rpu_pltime == 0)
   1358 					printf("pltime=infty,");
   1359 				else
   1360 					printf("pltime=%u,",
   1361 					    EXTRACT_32BITS(&use->rpu_pltime));
   1362 			}
   1363 			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
   1364 			    sizeof(hbuf)))
   1365 				printf("%s/%u/%u", hbuf, use->rpu_uselen,
   1366 				    use->rpu_keeplen);
   1367 			else
   1368 				printf("?/%u/%u", use->rpu_uselen,
   1369 				    use->rpu_keeplen);
   1370 			/*(*/
   1371 			printf(")");
   1372 		}
   1373 	}
   1374 
   1375 	return;
   1376 
   1377 trunc:
   1378 	fputs("[|icmp6]", stdout);
   1379 }
   1380 
   1381 #endif /* INET6 */
   1382