print-icmp6.c revision 147899
156893Sfenner/*
256893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
356893Sfenner *	The Regents of the University of California.  All rights reserved.
456893Sfenner *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that: (1) source code distributions
756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
856893Sfenner * distributions including binary code include the above copyright notice and
956893Sfenner * this paragraph in its entirety in the documentation or other materials
1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1156893Sfenner * features or use of this software display the following acknowledgement:
1256893Sfenner * ``This product includes software developed by the University of California,
1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1456893Sfenner * the University nor the names of its contributors may be used to endorse
1556893Sfenner * or promote products derived from this software without specific prior
1656893Sfenner * written permission.
1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056893Sfenner */
2156893Sfenner
2256893Sfenner#ifndef lint
23127668Sbmsstatic const char rcsid[] _U_ =
24147899Ssam    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79.2.4 2005/05/14 00:42:54 guy Exp $";
2556893Sfenner#endif
2656893Sfenner
2756893Sfenner#ifdef HAVE_CONFIG_H
2856893Sfenner#include "config.h"
2956893Sfenner#endif
3056893Sfenner
3156893Sfenner#ifdef INET6
3256893Sfenner
33127668Sbms#include <tcpdump-stdinc.h>
3456893Sfenner
3556893Sfenner#include <stdio.h>
3698524Sfenner#include <string.h>
3756893Sfenner
38147899Ssam#include "interface.h"
39147899Ssam#include "addrtoname.h"
40147899Ssam#include "extract.h"
41147899Ssam
4275115Sfenner#include "ip6.h"
4375115Sfenner#include "icmp6.h"
44127668Sbms#include "ipproto.h"
4556893Sfenner
4675115Sfenner#include "udp.h"
4775115Sfenner#include "ah.h"
4875115Sfenner
4998524Sfennerstatic const char *get_rtpref(u_int);
5098524Sfennerstatic const char *get_lifetime(u_int32_t);
5198524Sfennerstatic void print_lladdr(const u_char *, size_t);
52127668Sbmsstatic void icmp6_opt_print(const u_char *, int);
53127668Sbmsstatic void mld6_print(const u_char *);
54146773Ssamstatic void mldv2_report_print(const u_char *, u_int);
55146773Ssamstatic void mldv2_query_print(const u_char *, u_int);
56127668Sbmsstatic struct udphdr *get_upperlayer(u_char *, u_int *);
5775115Sfennerstatic void dnsname_print(const u_char *, const u_char *);
58127668Sbmsstatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
59127668Sbmsstatic void icmp6_rrenum_print(const u_char *, const u_char *);
6056893Sfenner
6175115Sfenner#ifndef abs
6275115Sfenner#define abs(a)	((0 < (a)) ? (a) : -(a))
6375115Sfenner#endif
6475115Sfenner
65146773Ssamstatic struct tok icmp6_type_values[] = {
66146773Ssam    { ICMP6_DST_UNREACH, "destination unreachable"},
67146773Ssam    { ICMP6_PACKET_TOO_BIG, "packet too big"},
68146773Ssam    { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
69146773Ssam    { ICMP6_PARAM_PROB, "parameter problem"},
70146773Ssam    { ICMP6_ECHO_REQUEST, "echo request"},
71146773Ssam    { ICMP6_ECHO_REPLY, "echo reply"},
72147899Ssam    { MLD6_LISTENER_QUERY, "multicast listener query"},
73147899Ssam    { MLD6_LISTENER_REPORT, "multicast listener report"},
74147899Ssam    { MLD6_LISTENER_DONE, "multicast listener done"},
75147899Ssam    { ND_ROUTER_SOLICIT, "router solicitation"},
76146773Ssam    { ND_ROUTER_ADVERT, "router advertisement"},
77146773Ssam    { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
78146773Ssam    { ND_NEIGHBOR_ADVERT, "neighbor advertisment"},
79146773Ssam    { ND_REDIRECT, "redirect"},
80146773Ssam    { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
81146773Ssam    { IND_SOLICIT, "inverse neighbor solicitation"},
82146773Ssam    { IND_ADVERT, "inverse neighbor advertisement"},
83147899Ssam    { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
84146773Ssam    { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
85146773Ssam    { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
86146773Ssam    { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
87146773Ssam    { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
88146773Ssam    { ICMP6_WRUREQUEST, "who-are-you request"},
89146773Ssam    { ICMP6_WRUREPLY, "who-are-you reply"},
90146773Ssam    { ICMP6_NI_QUERY, "node information query"},
91146773Ssam    { ICMP6_NI_REPLY, "node information reply"},
92146773Ssam    { MLD6_MTRACE, "mtrace message"},
93146773Ssam    { MLD6_MTRACE_RESP, "mtrace response"},
94146773Ssam    { 0,	NULL }
95146773Ssam};
96146773Ssam
97146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = {
98146773Ssam    { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
99146773Ssam    { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
100146773Ssam    { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
101146773Ssam    { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
102146773Ssam    { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
103146773Ssam    { 0,	NULL }
104146773Ssam};
105146773Ssam
106146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = {
107146773Ssam    { ND_OPT_PI_FLAG_ONLINK, "onlink" },
108146773Ssam    { ND_OPT_PI_FLAG_AUTO, "auto" },
109146773Ssam    { ND_OPT_PI_FLAG_ROUTER, "router" },
110146773Ssam    { 0,	NULL }
111146773Ssam};
112146773Ssam
113146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = {
114146773Ssam    { ND_RA_FLAG_MANAGED, "managed" },
115146773Ssam    { ND_RA_FLAG_OTHER, "other stateful"},
116146773Ssam    { ND_RA_FLAG_HOME_AGENT, "home agent"},
117146773Ssam    { 0,	NULL }
118146773Ssam};
119146773Ssam
120146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = {
121146773Ssam    { ND_NA_FLAG_ROUTER, "router" },
122146773Ssam    { ND_NA_FLAG_SOLICITED, "solicited" },
123146773Ssam    { ND_NA_FLAG_OVERRIDE, "override" },
124146773Ssam    { 0,	NULL }
125146773Ssam};
126146773Ssam
127146773Ssam
128146773Ssamstatic struct tok icmp6_opt_values[] = {
129146773Ssam   { ND_OPT_SOURCE_LINKADDR, "source link-address"},
130146773Ssam   { ND_OPT_TARGET_LINKADDR, "destination link-address"},
131146773Ssam   { ND_OPT_PREFIX_INFORMATION, "prefix info"},
132146773Ssam   { ND_OPT_REDIRECTED_HEADER, "redirected header"},
133146773Ssam   { ND_OPT_MTU, "mtu"},
134146773Ssam   { ND_OPT_ADVINTERVAL, "advertisment interval"},
135146773Ssam   { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
136146773Ssam   { ND_OPT_ROUTE_INFO, "route info"},
137146773Ssam   { 0,	NULL }
138146773Ssam};
139146773Ssam
140146773Ssam/* mldv2 report types */
141146773Ssamstatic struct tok mldv2report2str[] = {
142146773Ssam	{ 1,	"is_in" },
143146773Ssam	{ 2,	"is_ex" },
144146773Ssam	{ 3,	"to_in" },
145146773Ssam	{ 4,	"to_ex" },
146146773Ssam	{ 5,	"allow" },
147146773Ssam	{ 6,	"block" },
148146773Ssam	{ 0,	NULL }
149146773Ssam};
150146773Ssam
15198524Sfennerstatic const char *
15298524Sfennerget_rtpref(u_int v)
15398524Sfenner{
15498524Sfenner	static const char *rtpref_str[] = {
15598524Sfenner		"medium",		/* 00 */
15698524Sfenner		"high",			/* 01 */
15798524Sfenner		"rsv",			/* 10 */
15898524Sfenner		"low"			/* 11 */
15998524Sfenner	};
16098524Sfenner
16198524Sfenner	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
16298524Sfenner}
16398524Sfenner
16498524Sfennerstatic const char *
16598524Sfennerget_lifetime(u_int32_t v)
16698524Sfenner{
16798524Sfenner	static char buf[20];
16898524Sfenner
16998524Sfenner	if (v == (u_int32_t)~0UL)
17098524Sfenner		return "infinity";
17198524Sfenner	else {
17298524Sfenner		snprintf(buf, sizeof(buf), "%u", v);
17398524Sfenner		return buf;
17498524Sfenner	}
17598524Sfenner}
17698524Sfenner
17798524Sfennerstatic void
17898524Sfennerprint_lladdr(const u_int8_t *p, size_t l)
17998524Sfenner{
18098524Sfenner	const u_int8_t *ep, *q;
18198524Sfenner
18298524Sfenner	q = p;
18398524Sfenner	ep = p + l;
18498524Sfenner	while (l > 0 && q < ep) {
18598524Sfenner		if (q > p)
18698524Sfenner			printf(":");
18798524Sfenner		printf("%02x", *q++);
18898524Sfenner		l--;
18998524Sfenner	}
19098524Sfenner}
19198524Sfenner
192127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
193127668Sbms	u_int len)
194127668Sbms{
195127668Sbms	size_t i;
196127668Sbms	register const u_int16_t *sp;
197127668Sbms	u_int32_t sum;
198127668Sbms	union {
199127668Sbms		struct {
200127668Sbms			struct in6_addr ph_src;
201127668Sbms			struct in6_addr ph_dst;
202127668Sbms			u_int32_t	ph_len;
203127668Sbms			u_int8_t	ph_zero[3];
204127668Sbms			u_int8_t	ph_nxt;
205127668Sbms		} ph;
206127668Sbms		u_int16_t pa[20];
207127668Sbms	} phu;
208127668Sbms
209127668Sbms	/* pseudo-header */
210127668Sbms	memset(&phu, 0, sizeof(phu));
211127668Sbms	phu.ph.ph_src = ip6->ip6_src;
212127668Sbms	phu.ph.ph_dst = ip6->ip6_dst;
213127668Sbms	phu.ph.ph_len = htonl(len);
214127668Sbms	phu.ph.ph_nxt = IPPROTO_ICMPV6;
215127668Sbms
216127668Sbms	sum = 0;
217127668Sbms	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
218127668Sbms		sum += phu.pa[i];
219127668Sbms
220127668Sbms	sp = (const u_int16_t *)icp;
221127668Sbms
222127668Sbms	for (i = 0; i < (len & ~1); i += 2)
223127668Sbms		sum += *sp++;
224127668Sbms
225127668Sbms	if (len & 1)
226127668Sbms		sum += htons((*(const u_int8_t *)sp) << 8);
227127668Sbms
228127668Sbms	while (sum > 0xffff)
229127668Sbms		sum = (sum & 0xffff) + (sum >> 16);
230127668Sbms	sum = ~sum & 0xffff;
231127668Sbms
232127668Sbms	return (sum);
233127668Sbms}
234127668Sbms
23556893Sfennervoid
236127668Sbmsicmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
23756893Sfenner{
23875115Sfenner	const struct icmp6_hdr *dp;
23998524Sfenner	const struct ip6_hdr *ip;
24098524Sfenner	const struct ip6_hdr *oip;
24198524Sfenner	const struct udphdr *ouh;
24298524Sfenner	int dport;
24398524Sfenner	const u_char *ep;
244127668Sbms	u_int prot;
24556893Sfenner
24656893Sfenner	dp = (struct icmp6_hdr *)bp;
24756893Sfenner	ip = (struct ip6_hdr *)bp2;
24856893Sfenner	oip = (struct ip6_hdr *)(dp + 1);
24975115Sfenner	/* 'ep' points to the end of available data. */
25056893Sfenner	ep = snapend;
25156893Sfenner
252127668Sbms	TCHECK(dp->icmp6_cksum);
253127668Sbms
254127668Sbms	if (vflag && !fragmented) {
255127668Sbms		int sum = dp->icmp6_cksum;
256127668Sbms
257127668Sbms		if (TTEST2(bp[0], length)) {
258127668Sbms			sum = icmp6_cksum(ip, dp, length);
259127668Sbms			if (sum != 0)
260127668Sbms				(void)printf("[bad icmp6 cksum %x!] ", sum);
261127668Sbms			else
262127668Sbms				(void)printf("[icmp6 sum ok] ");
263127668Sbms		}
264127668Sbms	}
265127668Sbms
266146773Ssam        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
267146773Ssam
268146773Ssam        /* display cosmetics: print the packet length for printer that use the vflag now */
269146773Ssam        if (vflag && (dp->icmp6_type ==
270146773Ssam                      ND_ROUTER_SOLICIT ||
271146773Ssam                      ND_ROUTER_ADVERT ||
272146773Ssam                      ND_NEIGHBOR_ADVERT ||
273146773Ssam                      ND_NEIGHBOR_SOLICIT ||
274146773Ssam                      ND_REDIRECT ||
275146773Ssam                      ICMP6_HADISCOV_REPLY ||
276146773Ssam                      ICMP6_MOBILEPREFIX_ADVERT ))
277146773Ssam            printf(", length %u", length);
278146773Ssam
27975115Sfenner	switch (dp->icmp6_type) {
28056893Sfenner	case ICMP6_DST_UNREACH:
28156893Sfenner		TCHECK(oip->ip6_dst);
282146773Ssam                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
28356893Sfenner		switch (dp->icmp6_code) {
284146773Ssam
285146773Ssam		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
28656893Sfenner		case ICMP6_DST_UNREACH_ADMIN:
287146773Ssam		case ICMP6_DST_UNREACH_ADDR:
288146773Ssam                        printf(" %s",ip6addr_string(&oip->ip6_dst));
289146773Ssam                        break;
29056893Sfenner		case ICMP6_DST_UNREACH_BEYONDSCOPE:
291146773Ssam			printf(" %s, source address %s",
29256893Sfenner			       ip6addr_string(&oip->ip6_dst),
29356893Sfenner			       ip6addr_string(&oip->ip6_src));
29456893Sfenner			break;
29556893Sfenner		case ICMP6_DST_UNREACH_NOPORT:
29675115Sfenner			if ((ouh = get_upperlayer((u_char *)oip, &prot))
29775115Sfenner			    == NULL)
29875115Sfenner				goto trunc;
29975115Sfenner
300127668Sbms			dport = EXTRACT_16BITS(&ouh->uh_dport);
30175115Sfenner			switch (prot) {
30256893Sfenner			case IPPROTO_TCP:
303146773Ssam				printf(", %s tcp port %s",
30456893Sfenner					ip6addr_string(&oip->ip6_dst),
30556893Sfenner					tcpport_string(dport));
30656893Sfenner				break;
30756893Sfenner			case IPPROTO_UDP:
308146773Ssam				printf(", %s udp port %s",
30956893Sfenner					ip6addr_string(&oip->ip6_dst),
31056893Sfenner					udpport_string(dport));
31156893Sfenner				break;
31256893Sfenner			default:
313146773Ssam				printf(", %s protocol %d port %d unreachable",
31456893Sfenner					ip6addr_string(&oip->ip6_dst),
31556893Sfenner					oip->ip6_nxt, dport);
31656893Sfenner				break;
31756893Sfenner			}
31856893Sfenner			break;
31956893Sfenner		default:
320146773Ssam                    if (vflag <= 1) {
321146773Ssam                            print_unknown_data(bp,"\n\t",length);
322146773Ssam                            return;
323146773Ssam                    }
324146773Ssam                    break;
32556893Sfenner		}
32656893Sfenner		break;
32756893Sfenner	case ICMP6_PACKET_TOO_BIG:
32856893Sfenner		TCHECK(dp->icmp6_mtu);
329146773Ssam		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
33056893Sfenner		break;
33156893Sfenner	case ICMP6_TIME_EXCEEDED:
33256893Sfenner		TCHECK(oip->ip6_dst);
33356893Sfenner		switch (dp->icmp6_code) {
33456893Sfenner		case ICMP6_TIME_EXCEED_TRANSIT:
335146773Ssam			printf(" for %s",
33656893Sfenner				ip6addr_string(&oip->ip6_dst));
33756893Sfenner			break;
33856893Sfenner		case ICMP6_TIME_EXCEED_REASSEMBLY:
339146773Ssam			printf(" (reassembly)");
34056893Sfenner			break;
34156893Sfenner		default:
342146773Ssam			printf(", unknown code (%u)", dp->icmp6_code);
34356893Sfenner			break;
34456893Sfenner		}
34556893Sfenner		break;
34656893Sfenner	case ICMP6_PARAM_PROB:
34756893Sfenner		TCHECK(oip->ip6_dst);
34856893Sfenner		switch (dp->icmp6_code) {
34956893Sfenner		case ICMP6_PARAMPROB_HEADER:
350146773Ssam			printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
35156893Sfenner			break;
35256893Sfenner		case ICMP6_PARAMPROB_NEXTHEADER:
353146773Ssam			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
35456893Sfenner			break;
35556893Sfenner		case ICMP6_PARAMPROB_OPTION:
356146773Ssam			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
35756893Sfenner			break;
35856893Sfenner		default:
359146773Ssam			printf(", code-#%d",
36056893Sfenner			       dp->icmp6_code);
36156893Sfenner			break;
36256893Sfenner		}
36356893Sfenner		break;
36456893Sfenner	case ICMP6_ECHO_REQUEST:
36556893Sfenner	case ICMP6_ECHO_REPLY:
366127668Sbms		TCHECK(dp->icmp6_seq);
367146773Ssam		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
36856893Sfenner		break;
36956893Sfenner	case ICMP6_MEMBERSHIP_QUERY:
370146773Ssam		if (length == MLD_MINLEN) {
371146773Ssam			mld6_print((const u_char *)dp);
372146773Ssam		} else if (length >= MLDV2_MINLEN) {
373146773Ssam			printf("v2 ");
374146773Ssam			mldv2_query_print((const u_char *)dp, length);
375146773Ssam		} else {
376146773Ssam			printf(" unknown-version (len %u) ", length);
377146773Ssam		}
37856893Sfenner		break;
37956893Sfenner	case ICMP6_MEMBERSHIP_REPORT:
38056893Sfenner		mld6_print((const u_char *)dp);
38156893Sfenner		break;
38256893Sfenner	case ICMP6_MEMBERSHIP_REDUCTION:
38356893Sfenner		mld6_print((const u_char *)dp);
38456893Sfenner		break;
38556893Sfenner	case ND_ROUTER_SOLICIT:
386146773Ssam#define RTSOLLEN 8
38756893Sfenner		if (vflag) {
38875115Sfenner			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
389127668Sbms					length - RTSOLLEN);
39056893Sfenner		}
39156893Sfenner		break;
39256893Sfenner	case ND_ROUTER_ADVERT:
393146773Ssam#define RTADVLEN 16
39456893Sfenner		if (vflag) {
39556893Sfenner			struct nd_router_advert *p;
39656893Sfenner
39756893Sfenner			p = (struct nd_router_advert *)dp;
39856893Sfenner			TCHECK(p->nd_ra_retransmit);
399146773Ssam			printf("\n\thop limit %u, Flags [%s]" \
400146773Ssam                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
401146773Ssam                               (u_int)p->nd_ra_curhoplimit,
402146773Ssam                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
403146773Ssam                               get_rtpref(p->nd_ra_flags_reserved),
404146773Ssam                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
405146773Ssam                               EXTRACT_32BITS(&p->nd_ra_reachable),
406146773Ssam                               EXTRACT_32BITS(&p->nd_ra_retransmit));
40798524Sfenner
40875115Sfenner			icmp6_opt_print((const u_char *)dp + RTADVLEN,
409127668Sbms					length - RTADVLEN);
41056893Sfenner		}
41156893Sfenner		break;
41256893Sfenner	case ND_NEIGHBOR_SOLICIT:
41356893Sfenner	    {
41456893Sfenner		struct nd_neighbor_solicit *p;
41556893Sfenner		p = (struct nd_neighbor_solicit *)dp;
41656893Sfenner		TCHECK(p->nd_ns_target);
417146773Ssam		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
41856893Sfenner		if (vflag) {
41956893Sfenner#define NDSOLLEN 24
42075115Sfenner			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
421127668Sbms					length - NDSOLLEN);
42256893Sfenner		}
42356893Sfenner	    }
42456893Sfenner		break;
42556893Sfenner	case ND_NEIGHBOR_ADVERT:
42656893Sfenner	    {
42756893Sfenner		struct nd_neighbor_advert *p;
42856893Sfenner
42956893Sfenner		p = (struct nd_neighbor_advert *)dp;
43056893Sfenner		TCHECK(p->nd_na_target);
431146773Ssam		printf(", tgt is %s",
43256893Sfenner			ip6addr_string(&p->nd_na_target));
43375115Sfenner		if (vflag) {
434146773Ssam                        printf(", Flags [%s]",
435146773Ssam                               bittok2str(icmp6_nd_na_flag_values,
436146773Ssam                                          "none",
437146773Ssam                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
43856893Sfenner#define NDADVLEN 24
43975115Sfenner			icmp6_opt_print((const u_char *)dp + NDADVLEN,
440127668Sbms					length - NDADVLEN);
44175115Sfenner#undef NDADVLEN
44256893Sfenner		}
44356893Sfenner	    }
44456893Sfenner		break;
44556893Sfenner	case ND_REDIRECT:
44656893Sfenner#define RDR(i) ((struct nd_redirect *)(i))
44756893Sfenner		TCHECK(RDR(dp)->nd_rd_dst);
448146773Ssam		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
449127668Sbms		TCHECK(RDR(dp)->nd_rd_target);
45075115Sfenner		printf(" to %s",
45175115Sfenner		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
45256893Sfenner#define REDIRECTLEN 40
45356893Sfenner		if (vflag) {
45456893Sfenner			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
455127668Sbms					length - REDIRECTLEN);
45656893Sfenner		}
45756893Sfenner		break;
45875115Sfenner#undef REDIRECTLEN
45975115Sfenner#undef RDR
46056893Sfenner	case ICMP6_ROUTER_RENUMBERING:
461127668Sbms		icmp6_rrenum_print(bp, ep);
46256893Sfenner		break;
46375115Sfenner	case ICMP6_NI_QUERY:
46475115Sfenner	case ICMP6_NI_REPLY:
465127668Sbms		icmp6_nodeinfo_print(length, bp, ep);
46656893Sfenner		break;
467146773Ssam	case IND_SOLICIT:
468146773Ssam	case IND_ADVERT:
469146773Ssam		break;
470146773Ssam	case ICMP6_V2_MEMBERSHIP_REPORT:
471146773Ssam		mldv2_report_print((const u_char *) dp, length);
472146773Ssam		break;
473146773Ssam	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
474127668Sbms	case ICMP6_HADISCOV_REQUEST:
475146773Ssam                TCHECK(dp->icmp6_data16[0]);
476146773Ssam                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
477146773Ssam                break;
478127668Sbms	case ICMP6_HADISCOV_REPLY:
479127668Sbms		if (vflag) {
480127668Sbms			struct in6_addr *in6;
481127668Sbms			u_char *cp;
482127668Sbms
483127668Sbms			TCHECK(dp->icmp6_data16[0]);
484146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
485127668Sbms			cp = (u_char *)dp + length;
486127668Sbms			in6 = (struct in6_addr *)(dp + 1);
487127668Sbms			for (; (u_char *)in6 < cp; in6++) {
488127668Sbms				TCHECK(*in6);
489127668Sbms				printf(", %s", ip6addr_string(in6));
490127668Sbms			}
491127668Sbms		}
492127668Sbms		break;
493127668Sbms	case ICMP6_MOBILEPREFIX_ADVERT:
494127668Sbms		if (vflag) {
495127668Sbms			TCHECK(dp->icmp6_data16[0]);
496146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
497127668Sbms			if (dp->icmp6_data16[1] & 0xc0)
498127668Sbms				printf(" ");
499127668Sbms			if (dp->icmp6_data16[1] & 0x80)
500127668Sbms				printf("M");
501127668Sbms			if (dp->icmp6_data16[1] & 0x40)
502127668Sbms				printf("O");
503127668Sbms#define MPADVLEN 8
504127668Sbms			icmp6_opt_print((const u_char *)dp + MPADVLEN,
505127668Sbms					length - MPADVLEN);
506127668Sbms		}
507127668Sbms		break;
50856893Sfenner	default:
509146773Ssam                printf(", length %u", length);
510146773Ssam                if (vflag <= 1)
511146773Ssam                    print_unknown_data(bp,"\n\t", length);
512146773Ssam                return;
513146773Ssam        }
514146773Ssam        if (!vflag)
515146773Ssam            printf(", length %u", length);
51656893Sfenner	return;
51756893Sfennertrunc:
51856893Sfenner	fputs("[|icmp6]", stdout);
51956893Sfenner}
52056893Sfenner
52175115Sfennerstatic struct udphdr *
522127668Sbmsget_upperlayer(u_char *bp, u_int *prot)
52375115Sfenner{
52498524Sfenner	const u_char *ep;
52575115Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
52675115Sfenner	struct udphdr *uh;
52775115Sfenner	struct ip6_hbh *hbh;
52875115Sfenner	struct ip6_frag *fragh;
52975115Sfenner	struct ah *ah;
530127668Sbms	u_int nh;
531127668Sbms	int hlen;
53275115Sfenner
53375115Sfenner	/* 'ep' points to the end of available data. */
53475115Sfenner	ep = snapend;
53575115Sfenner
536127668Sbms	if (!TTEST(ip6->ip6_nxt))
53775115Sfenner		return NULL;
53875115Sfenner
53975115Sfenner	nh = ip6->ip6_nxt;
54075115Sfenner	hlen = sizeof(struct ip6_hdr);
54175115Sfenner
542147899Ssam	while (bp < ep) {
54375115Sfenner		bp += hlen;
54475115Sfenner
54575115Sfenner		switch(nh) {
54675115Sfenner		case IPPROTO_UDP:
54775115Sfenner		case IPPROTO_TCP:
54875115Sfenner			uh = (struct udphdr *)bp;
54975115Sfenner			if (TTEST(uh->uh_dport)) {
55075115Sfenner				*prot = nh;
55175115Sfenner				return(uh);
55275115Sfenner			}
55375115Sfenner			else
55475115Sfenner				return(NULL);
55575115Sfenner			/* NOTREACHED */
55675115Sfenner
55775115Sfenner		case IPPROTO_HOPOPTS:
55875115Sfenner		case IPPROTO_DSTOPTS:
55975115Sfenner		case IPPROTO_ROUTING:
56075115Sfenner			hbh = (struct ip6_hbh *)bp;
561127668Sbms			if (!TTEST(hbh->ip6h_len))
56275115Sfenner				return(NULL);
56375115Sfenner			nh = hbh->ip6h_nxt;
56475115Sfenner			hlen = (hbh->ip6h_len + 1) << 3;
56575115Sfenner			break;
56675115Sfenner
56775115Sfenner		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
56875115Sfenner			fragh = (struct ip6_frag *)bp;
569127668Sbms			if (!TTEST(fragh->ip6f_offlg))
57075115Sfenner				return(NULL);
57175115Sfenner			/* fragments with non-zero offset are meaningless */
572127668Sbms			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
57375115Sfenner				return(NULL);
57475115Sfenner			nh = fragh->ip6f_nxt;
57575115Sfenner			hlen = sizeof(struct ip6_frag);
57675115Sfenner			break;
57775115Sfenner
57875115Sfenner		case IPPROTO_AH:
57975115Sfenner			ah = (struct ah *)bp;
580127668Sbms			if (!TTEST(ah->ah_len))
58175115Sfenner				return(NULL);
58275115Sfenner			nh = ah->ah_nxt;
58375115Sfenner			hlen = (ah->ah_len + 2) << 2;
58475115Sfenner			break;
58575115Sfenner
58675115Sfenner		default:	/* unknown or undecodable header */
58775115Sfenner			*prot = nh; /* meaningless, but set here anyway */
58875115Sfenner			return(NULL);
58975115Sfenner		}
59075115Sfenner	}
59175115Sfenner
59275115Sfenner	return(NULL);		/* should be notreached, though */
59375115Sfenner}
59475115Sfenner
595127668Sbmsstatic void
59698524Sfennericmp6_opt_print(const u_char *bp, int resid)
59756893Sfenner{
59898524Sfenner	const struct nd_opt_hdr *op;
59998524Sfenner	const struct nd_opt_hdr *opl;	/* why there's no struct? */
60098524Sfenner	const struct nd_opt_prefix_info *opp;
60198524Sfenner	const struct icmp6_opts_redirect *opr;
60298524Sfenner	const struct nd_opt_mtu *opm;
60398524Sfenner	const struct nd_opt_advinterval *opa;
604127668Sbms	const struct nd_opt_homeagent_info *oph;
60598524Sfenner	const struct nd_opt_route_info *opri;
60698524Sfenner	const u_char *cp, *ep;
60798524Sfenner	struct in6_addr in6, *in6p;
60898524Sfenner	size_t l;
60956893Sfenner
61056893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
61156893Sfenner
61298524Sfenner	cp = bp;
61375115Sfenner	/* 'ep' points to the end of available data. */
61456893Sfenner	ep = snapend;
61556893Sfenner
61698524Sfenner	while (cp < ep) {
61798524Sfenner		op = (struct nd_opt_hdr *)cp;
61898524Sfenner
61998524Sfenner		ECHECK(op->nd_opt_len);
62098524Sfenner		if (resid <= 0)
62198524Sfenner			return;
62298524Sfenner		if (op->nd_opt_len == 0)
62356893Sfenner			goto trunc;
62498524Sfenner		if (cp + (op->nd_opt_len << 3) > ep)
62556893Sfenner			goto trunc;
62698524Sfenner
627146773Ssam                printf("\n\t  %s option (%u), length %u (%u): ",
628146773Ssam                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
629146773Ssam                       op->nd_opt_type,
630146773Ssam                       op->nd_opt_len << 3,
631146773Ssam                       op->nd_opt_len);
632146773Ssam
63398524Sfenner		switch (op->nd_opt_type) {
63498524Sfenner		case ND_OPT_SOURCE_LINKADDR:
63598524Sfenner			opl = (struct nd_opt_hdr *)op;
63698524Sfenner			l = (op->nd_opt_len << 3) - 2;
63798524Sfenner			print_lladdr(cp + 2, l);
63898524Sfenner			break;
63998524Sfenner		case ND_OPT_TARGET_LINKADDR:
64098524Sfenner			opl = (struct nd_opt_hdr *)op;
64198524Sfenner			l = (op->nd_opt_len << 3) - 2;
64298524Sfenner			print_lladdr(cp + 2, l);
64398524Sfenner			break;
64498524Sfenner		case ND_OPT_PREFIX_INFORMATION:
64598524Sfenner			opp = (struct nd_opt_prefix_info *)op;
64698524Sfenner			TCHECK(opp->nd_opt_pi_prefix);
647146773Ssam                        printf("%s/%u%s, Flags [%s], valid time %ss",
648146773Ssam                               ip6addr_string(&opp->nd_opt_pi_prefix),
649146773Ssam                               opp->nd_opt_pi_prefix_len,
650146773Ssam                               (op->nd_opt_len != 4) ? "badlen" : "",
651146773Ssam                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
652146773Ssam                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
653146773Ssam                        printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
65498524Sfenner			break;
65598524Sfenner		case ND_OPT_REDIRECTED_HEADER:
65698524Sfenner			opr = (struct icmp6_opts_redirect *)op;
657146773Ssam                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
65898524Sfenner			/* xxx */
65998524Sfenner			break;
66098524Sfenner		case ND_OPT_MTU:
66198524Sfenner			opm = (struct nd_opt_mtu *)op;
66298524Sfenner			TCHECK(opm->nd_opt_mtu_mtu);
663146773Ssam			printf(" %u%s",
664146773Ssam                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
665146773Ssam                               (op->nd_opt_len != 1) ? "bad option length" : "" );
666146773Ssam                        break;
66798524Sfenner		case ND_OPT_ADVINTERVAL:
66898524Sfenner			opa = (struct nd_opt_advinterval *)op;
66998524Sfenner			TCHECK(opa->nd_opt_adv_interval);
670146773Ssam			printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
671127668Sbms			break;
672127668Sbms		case ND_OPT_HOMEAGENT_INFO:
673127668Sbms			oph = (struct nd_opt_homeagent_info *)op;
674127668Sbms			TCHECK(oph->nd_opt_hai_lifetime);
675146773Ssam			printf(" preference %u, lifetime %u",
676146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
677146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
678127668Sbms			break;
67998524Sfenner		case ND_OPT_ROUTE_INFO:
68098524Sfenner			opri = (struct nd_opt_route_info *)op;
68198524Sfenner			TCHECK(opri->nd_opt_rti_lifetime);
68298524Sfenner			memset(&in6, 0, sizeof(in6));
68398524Sfenner			in6p = (struct in6_addr *)(opri + 1);
68498524Sfenner			switch (op->nd_opt_len) {
68598524Sfenner			case 1:
68698524Sfenner				break;
68798524Sfenner			case 2:
68898524Sfenner				TCHECK2(*in6p, 8);
68998524Sfenner				memcpy(&in6, opri + 1, 8);
69098524Sfenner				break;
69198524Sfenner			case 3:
69298524Sfenner				TCHECK(*in6p);
69398524Sfenner				memcpy(&in6, opri + 1, sizeof(in6));
69498524Sfenner				break;
69598524Sfenner			default:
69698524Sfenner				goto trunc;
69798524Sfenner			}
69898524Sfenner			printf(" %s/%u", ip6addr_string(&in6),
69998524Sfenner			    opri->nd_opt_rti_prefixlen);
70098524Sfenner			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
70198524Sfenner			printf(", lifetime=%s",
702127668Sbms			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
70398524Sfenner			break;
70498524Sfenner		default:
705146773Ssam                        if (vflag <= 1) {
706146773Ssam                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
707146773Ssam                            return;
708146773Ssam                        }
709146773Ssam                        break;
71056893Sfenner		}
711146773Ssam                /* do we want to see an additional hexdump ? */
712146773Ssam                if (vflag> 1)
713146773Ssam                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
71498524Sfenner
71598524Sfenner		cp += op->nd_opt_len << 3;
71698524Sfenner		resid -= op->nd_opt_len << 3;
71756893Sfenner	}
71856893Sfenner	return;
71998524Sfenner
72056893Sfenner trunc:
72156893Sfenner	fputs("[ndp opt]", stdout);
72256893Sfenner	return;
72356893Sfenner#undef ECHECK
72456893Sfenner}
72556893Sfenner
726127668Sbmsstatic void
72798524Sfennermld6_print(const u_char *bp)
72856893Sfenner{
72998524Sfenner	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
73098524Sfenner	const u_char *ep;
73156893Sfenner
73275115Sfenner	/* 'ep' points to the end of available data. */
73356893Sfenner	ep = snapend;
73456893Sfenner
73556893Sfenner	if ((u_char *)mp + sizeof(*mp) > ep)
73656893Sfenner		return;
73756893Sfenner
738127668Sbms	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
73956893Sfenner	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
74075115Sfenner}
74156893Sfenner
74275115Sfennerstatic void
743146773Ssammldv2_report_print(const u_char *bp, u_int len)
744146773Ssam{
745146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
746146773Ssam    u_int group, nsrcs, ngroups;
747146773Ssam    u_int i, j;
748146773Ssam
749146773Ssam    /* Minimum len is 8 */
750146773Ssam    if (len < 8) {
751146773Ssam	printf(" [invalid len %d]", len);
752146773Ssam	return;
753146773Ssam    }
754146773Ssam
755146773Ssam    TCHECK(icp->icmp6_data16[1]);
756146773Ssam    ngroups = ntohs(icp->icmp6_data16[1]);
757146773Ssam    printf(", %d group record(s)", ngroups);
758146773Ssam    if (vflag > 0) {
759146773Ssam	/* Print the group records */
760146773Ssam	group = 8;
761146773Ssam        for (i = 0; i < ngroups; i++) {
762146773Ssam	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
763146773Ssam	    if (len < group + 20) {
764146773Ssam		printf(" [invalid number of groups]");
765146773Ssam		return;
766146773Ssam	    }
767146773Ssam            TCHECK2(bp[group + 4], 16);
768146773Ssam            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
769146773Ssam	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
770146773Ssam								bp[group]));
771146773Ssam            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
772146773Ssam	    /* Check the number of sources and print them */
773146773Ssam	    if (len < group + 20 + (nsrcs * 16)) {
774146773Ssam		printf(" [invalid number of sources %d]", nsrcs);
775146773Ssam		return;
776146773Ssam	    }
777146773Ssam            if (vflag == 1)
778146773Ssam                printf(", %d source(s)", nsrcs);
779146773Ssam            else {
780146773Ssam		/* Print the sources */
781146773Ssam                (void)printf(" {");
782146773Ssam                for (j = 0; j < nsrcs; j++) {
783146773Ssam                    TCHECK2(bp[group + 20 + j * 16], 16);
784146773Ssam		    printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
785146773Ssam		}
786146773Ssam                (void)printf(" }");
787146773Ssam            }
788146773Ssam	    /* Next group record */
789146773Ssam            group += 20 + nsrcs * 16;
790146773Ssam	    printf("]");
791146773Ssam        }
792146773Ssam    }
793146773Ssam    return;
794146773Ssamtrunc:
795146773Ssam    (void)printf("[|icmp6]");
796146773Ssam    return;
797146773Ssam}
798146773Ssam
799146773Ssamstatic void
800146773Ssammldv2_query_print(const u_char *bp, u_int len)
801146773Ssam{
802146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
803146773Ssam    u_int mrc;
804146773Ssam    int mrt, qqi;
805146773Ssam    u_int nsrcs;
806146773Ssam    register u_int i;
807146773Ssam
808146773Ssam    /* Minimum len is 28 */
809146773Ssam    if (len < 28) {
810146773Ssam	printf(" [invalid len %d]", len);
811146773Ssam	return;
812146773Ssam    }
813146773Ssam    TCHECK(icp->icmp6_data16[0]);
814146773Ssam    mrc = ntohs(icp->icmp6_data16[0]);
815146773Ssam    if (mrc < 32768) {
816146773Ssam	mrt = mrc;
817146773Ssam    } else {
818146773Ssam        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
819146773Ssam    }
820146773Ssam    if (vflag) {
821146773Ssam	(void)printf(" [max resp delay=%d]", mrt);
822146773Ssam    }
823146773Ssam    TCHECK2(bp[8], 16);
824146773Ssam    printf(" [gaddr %s", ip6addr_string(&bp[8]));
825146773Ssam
826146773Ssam    if (vflag) {
827146773Ssam        TCHECK(bp[25]);
828146773Ssam	if (bp[24] & 0x08) {
829146773Ssam		printf(" sflag");
830146773Ssam	}
831146773Ssam	if (bp[24] & 0x07) {
832146773Ssam		printf(" robustness=%d", bp[24] & 0x07);
833146773Ssam	}
834146773Ssam	if (bp[25] < 128) {
835146773Ssam		qqi = bp[25];
836146773Ssam	} else {
837146773Ssam		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
838146773Ssam	}
839146773Ssam	printf(" qqi=%d", qqi);
840146773Ssam    }
841146773Ssam
842146773Ssam    TCHECK2(bp[26], 2);
843146773Ssam    nsrcs = ntohs(*(u_short *)&bp[26]);
844146773Ssam    if (nsrcs > 0) {
845146773Ssam	if (len < 28 + nsrcs * 16)
846146773Ssam	    printf(" [invalid number of sources]");
847146773Ssam	else if (vflag > 1) {
848146773Ssam	    printf(" {");
849146773Ssam	    for (i = 0; i < nsrcs; i++) {
850146773Ssam		TCHECK2(bp[28 + i * 16], 16);
851146773Ssam		printf(" %s", ip6addr_string(&bp[28 + i * 16]));
852146773Ssam	    }
853146773Ssam	    printf(" }");
854146773Ssam	} else
855146773Ssam	    printf(", %d source(s)", nsrcs);
856146773Ssam    }
857146773Ssam    printf("]");
858146773Ssam    return;
859146773Ssamtrunc:
860146773Ssam    (void)printf("[|icmp6]");
861146773Ssam    return;
862146773Ssam}
863146773Ssam
864146773Ssamvoid
86575115Sfennerdnsname_print(const u_char *cp, const u_char *ep)
86675115Sfenner{
86775115Sfenner	int i;
86875115Sfenner
86975115Sfenner	/* DNS name decoding - no decompression */
87075115Sfenner	printf(", \"");
87175115Sfenner	while (cp < ep) {
87275115Sfenner		i = *cp++;
87375115Sfenner		if (i) {
87475115Sfenner			if (i > ep - cp) {
87575115Sfenner				printf("???");
87675115Sfenner				break;
87775115Sfenner			}
87875115Sfenner			while (i-- && cp < ep) {
87975115Sfenner				safeputchar(*cp);
88075115Sfenner				cp++;
88175115Sfenner			}
88275115Sfenner			if (cp + 1 < ep && *cp)
88375115Sfenner				printf(".");
88475115Sfenner		} else {
88575115Sfenner			if (cp == ep) {
88675115Sfenner				/* FQDN */
88775115Sfenner				printf(".");
88875115Sfenner			} else if (cp + 1 == ep && *cp == '\0') {
88975115Sfenner				/* truncated */
89075115Sfenner			} else {
89175115Sfenner				/* invalid */
89275115Sfenner				printf("???");
89375115Sfenner			}
89475115Sfenner			break;
89575115Sfenner		}
89675115Sfenner	}
89775115Sfenner	printf("\"");
89875115Sfenner}
89975115Sfenner
900127668Sbmsstatic void
901127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
90275115Sfenner{
90375115Sfenner	struct icmp6_nodeinfo *ni6;
90475115Sfenner	struct icmp6_hdr *dp;
90575115Sfenner	const u_char *cp;
906127668Sbms	size_t siz, i;
90775115Sfenner	int needcomma;
90875115Sfenner
909127668Sbms	if (ep < bp)
910127668Sbms		return;
91175115Sfenner	dp = (struct icmp6_hdr *)bp;
91275115Sfenner	ni6 = (struct icmp6_nodeinfo *)bp;
91375115Sfenner	siz = ep - bp;
91475115Sfenner
91575115Sfenner	switch (ni6->ni_type) {
91675115Sfenner	case ICMP6_NI_QUERY:
91775115Sfenner		if (siz == sizeof(*dp) + 4) {
91875115Sfenner			/* KAME who-are-you */
919146773Ssam			printf(" who-are-you request");
92075115Sfenner			break;
92175115Sfenner		}
922146773Ssam		printf(" node information query");
92375115Sfenner
92475115Sfenner		TCHECK2(*dp, sizeof(*ni6));
92575115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
92675115Sfenner		printf(" (");	/*)*/
927127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
92875115Sfenner		case NI_QTYPE_NOOP:
92975115Sfenner			printf("noop");
93075115Sfenner			break;
93175115Sfenner		case NI_QTYPE_SUPTYPES:
93275115Sfenner			printf("supported qtypes");
933127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
93475115Sfenner			if (i)
93575115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
93675115Sfenner			break;
93775115Sfenner			break;
93875115Sfenner		case NI_QTYPE_FQDN:
93975115Sfenner			printf("DNS name");
94075115Sfenner			break;
94175115Sfenner		case NI_QTYPE_NODEADDR:
94275115Sfenner			printf("node addresses");
94375115Sfenner			i = ni6->ni_flags;
94475115Sfenner			if (!i)
94575115Sfenner				break;
94675115Sfenner			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
94775115Sfenner			printf(" [%s%s%s%s%s%s]",
94875115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
94975115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
95075115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
95175115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
95275115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
95375115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
95475115Sfenner			break;
95575115Sfenner		default:
95675115Sfenner			printf("unknown");
95775115Sfenner			break;
95875115Sfenner		}
95975115Sfenner
96075115Sfenner		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
96175115Sfenner		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
96275115Sfenner			if (siz != sizeof(*ni6))
96375115Sfenner				if (vflag)
96475115Sfenner					printf(", invalid len");
96575115Sfenner			/*(*/
96675115Sfenner			printf(")");
96775115Sfenner			break;
96875115Sfenner		}
96975115Sfenner
97075115Sfenner
97175115Sfenner		/* XXX backward compat, icmp-name-lookup-03 */
97275115Sfenner		if (siz == sizeof(*ni6)) {
97375115Sfenner			printf(", 03 draft");
97475115Sfenner			/*(*/
97575115Sfenner			printf(")");
97675115Sfenner			break;
97775115Sfenner		}
97875115Sfenner
97975115Sfenner		switch (ni6->ni_code) {
98075115Sfenner		case ICMP6_NI_SUBJ_IPV6:
98175115Sfenner			if (!TTEST2(*dp,
98275115Sfenner			    sizeof(*ni6) + sizeof(struct in6_addr)))
98375115Sfenner				break;
98475115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
98575115Sfenner				if (vflag)
98675115Sfenner					printf(", invalid subject len");
98775115Sfenner				break;
98875115Sfenner			}
98975115Sfenner			printf(", subject=%s",
99075115Sfenner			    getname6((const u_char *)(ni6 + 1)));
99175115Sfenner			break;
99275115Sfenner		case ICMP6_NI_SUBJ_FQDN:
99375115Sfenner			printf(", subject=DNS name");
99475115Sfenner			cp = (const u_char *)(ni6 + 1);
99575115Sfenner			if (cp[0] == ep - cp - 1) {
99675115Sfenner				/* icmp-name-lookup-03, pascal string */
99775115Sfenner				if (vflag)
99875115Sfenner					printf(", 03 draft");
99975115Sfenner				cp++;
100075115Sfenner				printf(", \"");
100175115Sfenner				while (cp < ep) {
100275115Sfenner					safeputchar(*cp);
100375115Sfenner					cp++;
100475115Sfenner				}
100575115Sfenner				printf("\"");
100675115Sfenner			} else
100775115Sfenner				dnsname_print(cp, ep);
100875115Sfenner			break;
100975115Sfenner		case ICMP6_NI_SUBJ_IPV4:
101075115Sfenner			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
101175115Sfenner				break;
101275115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
101375115Sfenner				if (vflag)
101475115Sfenner					printf(", invalid subject len");
101575115Sfenner				break;
101675115Sfenner			}
101775115Sfenner			printf(", subject=%s",
101875115Sfenner			    getname((const u_char *)(ni6 + 1)));
101975115Sfenner			break;
102075115Sfenner		default:
102175115Sfenner			printf(", unknown subject");
102275115Sfenner			break;
102375115Sfenner		}
102475115Sfenner
102575115Sfenner		/*(*/
102675115Sfenner		printf(")");
102775115Sfenner		break;
102875115Sfenner
102975115Sfenner	case ICMP6_NI_REPLY:
103075115Sfenner		if (icmp6len > siz) {
103175115Sfenner			printf("[|icmp6: node information reply]");
103275115Sfenner			break;
103375115Sfenner		}
103475115Sfenner
103575115Sfenner		needcomma = 0;
103675115Sfenner
103775115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
1038146773Ssam		printf(" node information reply");
103975115Sfenner		printf(" (");	/*)*/
104075115Sfenner		switch (ni6->ni_code) {
104175115Sfenner		case ICMP6_NI_SUCCESS:
104275115Sfenner			if (vflag) {
104375115Sfenner				printf("success");
104475115Sfenner				needcomma++;
104575115Sfenner			}
104675115Sfenner			break;
104775115Sfenner		case ICMP6_NI_REFUSED:
104875115Sfenner			printf("refused");
104975115Sfenner			needcomma++;
105075115Sfenner			if (siz != sizeof(*ni6))
105175115Sfenner				if (vflag)
105275115Sfenner					printf(", invalid length");
105375115Sfenner			break;
105475115Sfenner		case ICMP6_NI_UNKNOWN:
105575115Sfenner			printf("unknown");
105675115Sfenner			needcomma++;
105775115Sfenner			if (siz != sizeof(*ni6))
105875115Sfenner				if (vflag)
105975115Sfenner					printf(", invalid length");
106075115Sfenner			break;
106175115Sfenner		}
106275115Sfenner
106375115Sfenner		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
106475115Sfenner			/*(*/
106575115Sfenner			printf(")");
106675115Sfenner			break;
106775115Sfenner		}
106875115Sfenner
1069127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
107075115Sfenner		case NI_QTYPE_NOOP:
107175115Sfenner			if (needcomma)
107275115Sfenner				printf(", ");
107375115Sfenner			printf("noop");
107475115Sfenner			if (siz != sizeof(*ni6))
107575115Sfenner				if (vflag)
107675115Sfenner					printf(", invalid length");
107775115Sfenner			break;
107875115Sfenner		case NI_QTYPE_SUPTYPES:
107975115Sfenner			if (needcomma)
108075115Sfenner				printf(", ");
108175115Sfenner			printf("supported qtypes");
1082127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
108375115Sfenner			if (i)
108475115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
108575115Sfenner			break;
108675115Sfenner		case NI_QTYPE_FQDN:
108775115Sfenner			if (needcomma)
108875115Sfenner				printf(", ");
108975115Sfenner			printf("DNS name");
109075115Sfenner			cp = (const u_char *)(ni6 + 1) + 4;
109175115Sfenner			if (cp[0] == ep - cp - 1) {
109275115Sfenner				/* icmp-name-lookup-03, pascal string */
109375115Sfenner				if (vflag)
109475115Sfenner					printf(", 03 draft");
109575115Sfenner				cp++;
109675115Sfenner				printf(", \"");
109775115Sfenner				while (cp < ep) {
109875115Sfenner					safeputchar(*cp);
109975115Sfenner					cp++;
110075115Sfenner				}
110175115Sfenner				printf("\"");
110275115Sfenner			} else
110375115Sfenner				dnsname_print(cp, ep);
1104127668Sbms			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
110575115Sfenner				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
110675115Sfenner			break;
110775115Sfenner		case NI_QTYPE_NODEADDR:
110875115Sfenner			if (needcomma)
110975115Sfenner				printf(", ");
111075115Sfenner			printf("node addresses");
111175115Sfenner			i = sizeof(*ni6);
111275115Sfenner			while (i < siz) {
111375115Sfenner				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
111475115Sfenner					break;
111575115Sfenner				printf(" %s", getname6(bp + i));
111675115Sfenner				i += sizeof(struct in6_addr);
1117127668Sbms				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
111875115Sfenner				i += sizeof(int32_t);
111975115Sfenner			}
112075115Sfenner			i = ni6->ni_flags;
112175115Sfenner			if (!i)
112275115Sfenner				break;
112375115Sfenner			printf(" [%s%s%s%s%s%s%s]",
112475115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
112575115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
112675115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
112775115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
112875115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
112975115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
113075115Sfenner			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
113175115Sfenner			break;
113275115Sfenner		default:
113375115Sfenner			if (needcomma)
113475115Sfenner				printf(", ");
113575115Sfenner			printf("unknown");
113675115Sfenner			break;
113775115Sfenner		}
113875115Sfenner
113975115Sfenner		/*(*/
114075115Sfenner		printf(")");
114175115Sfenner		break;
114275115Sfenner	}
114356893Sfenner	return;
114475115Sfenner
114575115Sfennertrunc:
114675115Sfenner	fputs("[|icmp6]", stdout);
114756893Sfenner}
114875115Sfenner
1149127668Sbmsstatic void
1150127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep)
115175115Sfenner{
115275115Sfenner	struct icmp6_router_renum *rr6;
115375115Sfenner	const char *cp;
115475115Sfenner	struct rr_pco_match *match;
115575115Sfenner	struct rr_pco_use *use;
115675115Sfenner	char hbuf[NI_MAXHOST];
115775115Sfenner	int n;
115875115Sfenner
1159127668Sbms	if (ep < bp)
1160127668Sbms		return;
116175115Sfenner	rr6 = (struct icmp6_router_renum *)bp;
116275115Sfenner	cp = (const char *)(rr6 + 1);
116375115Sfenner
116475115Sfenner	TCHECK(rr6->rr_reserved);
116575115Sfenner	switch (rr6->rr_code) {
116675115Sfenner	case ICMP6_ROUTER_RENUMBERING_COMMAND:
116775115Sfenner		printf("router renum: command");
116875115Sfenner		break;
116975115Sfenner	case ICMP6_ROUTER_RENUMBERING_RESULT:
117075115Sfenner		printf("router renum: result");
117175115Sfenner		break;
117275115Sfenner	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
117375115Sfenner		printf("router renum: sequence number reset");
117475115Sfenner		break;
117575115Sfenner	default:
117675115Sfenner		printf("router renum: code-#%d", rr6->rr_code);
117775115Sfenner		break;
117875115Sfenner	}
117975115Sfenner
1180127668Sbms	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
118175115Sfenner
118275115Sfenner	if (vflag) {
118375115Sfenner#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
118475115Sfenner		printf("[");	/*]*/
118575115Sfenner		if (rr6->rr_flags) {
118675115Sfenner			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
118775115Sfenner			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
118898524Sfenner			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
118975115Sfenner			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
119075115Sfenner			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
119175115Sfenner		}
119275115Sfenner		printf("seg=%u,", rr6->rr_segnum);
119375115Sfenner		printf("maxdelay=%u", rr6->rr_maxdelay);
119475115Sfenner		if (rr6->rr_reserved)
1195127668Sbms			printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
119675115Sfenner		/*[*/
119775115Sfenner		printf("]");
119875115Sfenner#undef F
119975115Sfenner	}
120075115Sfenner
120175115Sfenner	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
120275115Sfenner		match = (struct rr_pco_match *)cp;
120375115Sfenner		cp = (const char *)(match + 1);
120475115Sfenner
120575115Sfenner		TCHECK(match->rpm_prefix);
120675115Sfenner
120798524Sfenner		if (vflag > 1)
120875115Sfenner			printf("\n\t");
120975115Sfenner		else
121075115Sfenner			printf(" ");
121175115Sfenner		printf("match(");	/*)*/
121275115Sfenner		switch (match->rpm_code) {
121375115Sfenner		case RPM_PCO_ADD:	printf("add"); break;
121475115Sfenner		case RPM_PCO_CHANGE:	printf("change"); break;
121575115Sfenner		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
121675115Sfenner		default:		printf("#%u", match->rpm_code); break;
121775115Sfenner		}
121875115Sfenner
121975115Sfenner		if (vflag) {
122075115Sfenner			printf(",ord=%u", match->rpm_ordinal);
122175115Sfenner			printf(",min=%u", match->rpm_minlen);
122275115Sfenner			printf(",max=%u", match->rpm_maxlen);
122375115Sfenner		}
122475115Sfenner		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
122575115Sfenner			printf(",%s/%u", hbuf, match->rpm_matchlen);
122675115Sfenner		else
122775115Sfenner			printf(",?/%u", match->rpm_matchlen);
122875115Sfenner		/*(*/
122975115Sfenner		printf(")");
123075115Sfenner
123175115Sfenner		n = match->rpm_len - 3;
123275115Sfenner		if (n % 4)
123375115Sfenner			goto trunc;
123475115Sfenner		n /= 4;
123575115Sfenner		while (n-- > 0) {
123675115Sfenner			use = (struct rr_pco_use *)cp;
123775115Sfenner			cp = (const char *)(use + 1);
123875115Sfenner
123975115Sfenner			TCHECK(use->rpu_prefix);
124075115Sfenner
124198524Sfenner			if (vflag > 1)
124275115Sfenner				printf("\n\t");
124375115Sfenner			else
124475115Sfenner				printf(" ");
124575115Sfenner			printf("use(");	/*)*/
124675115Sfenner			if (use->rpu_flags) {
124775115Sfenner#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
124875115Sfenner				printf("%s%s,",
124975115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
125075115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
125175115Sfenner#undef F
125275115Sfenner			}
125375115Sfenner			if (vflag) {
125475115Sfenner				printf("mask=0x%x,", use->rpu_ramask);
125575115Sfenner				printf("raflags=0x%x,", use->rpu_raflags);
125675115Sfenner				if (~use->rpu_vltime == 0)
125775115Sfenner					printf("vltime=infty,");
125875115Sfenner				else
125975115Sfenner					printf("vltime=%u,",
1260127668Sbms					    EXTRACT_32BITS(&use->rpu_vltime));
126175115Sfenner				if (~use->rpu_pltime == 0)
126275115Sfenner					printf("pltime=infty,");
126375115Sfenner				else
126475115Sfenner					printf("pltime=%u,",
1265127668Sbms					    EXTRACT_32BITS(&use->rpu_pltime));
126675115Sfenner			}
126775115Sfenner			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
126875115Sfenner			    sizeof(hbuf)))
126975115Sfenner				printf("%s/%u/%u", hbuf, use->rpu_uselen,
127075115Sfenner				    use->rpu_keeplen);
127175115Sfenner			else
127275115Sfenner				printf("?/%u/%u", use->rpu_uselen,
127375115Sfenner				    use->rpu_keeplen);
127475115Sfenner			/*(*/
127575115Sfenner			printf(")");
127675115Sfenner		}
127775115Sfenner	}
127875115Sfenner
127975115Sfenner	return;
128075115Sfenner
128175115Sfennertrunc:
128275115Sfenner	fputs("[|icmp6]", stdout);
128375115Sfenner}
128475115Sfenner
128556893Sfenner#endif /* INET6 */
1286