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