print-icmp6.c revision 146773
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_ =
24146773Ssam    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79 2005/01/14 10:41:50 hannes 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
3875115Sfenner#include "ip6.h"
3975115Sfenner#include "icmp6.h"
40127668Sbms#include "ipproto.h"
4156893Sfenner
4256893Sfenner#include "interface.h"
4356893Sfenner#include "addrtoname.h"
44127668Sbms#include "extract.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"},
72146773Ssam    { MLD6_LISTENER_QUERY, "multicast listener query "},
73146773Ssam    { MLD6_LISTENER_REPORT, "multicast listener report "},
74146773Ssam    { MLD6_LISTENER_DONE, "multicast listener done "},
75146773Ssam    { 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"},
83146773Ssam    { 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 char *str;
24198524Sfenner	const struct ip6_hdr *oip;
24298524Sfenner	const struct udphdr *ouh;
24398524Sfenner	int dport;
24498524Sfenner	const u_char *ep;
24556893Sfenner	char buf[256];
246127668Sbms	u_int prot;
24756893Sfenner
24856893Sfenner	dp = (struct icmp6_hdr *)bp;
24956893Sfenner	ip = (struct ip6_hdr *)bp2;
25056893Sfenner	oip = (struct ip6_hdr *)(dp + 1);
25156893Sfenner	str = buf;
25275115Sfenner	/* 'ep' points to the end of available data. */
25356893Sfenner	ep = snapend;
25456893Sfenner
255127668Sbms	TCHECK(dp->icmp6_cksum);
256127668Sbms
257127668Sbms	if (vflag && !fragmented) {
258127668Sbms		int sum = dp->icmp6_cksum;
259127668Sbms
260127668Sbms		if (TTEST2(bp[0], length)) {
261127668Sbms			sum = icmp6_cksum(ip, dp, length);
262127668Sbms			if (sum != 0)
263127668Sbms				(void)printf("[bad icmp6 cksum %x!] ", sum);
264127668Sbms			else
265127668Sbms				(void)printf("[icmp6 sum ok] ");
266127668Sbms		}
267127668Sbms	}
268127668Sbms
269146773Ssam        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
270146773Ssam
271146773Ssam        /* display cosmetics: print the packet length for printer that use the vflag now */
272146773Ssam        if (vflag && (dp->icmp6_type ==
273146773Ssam                      ND_ROUTER_SOLICIT ||
274146773Ssam                      ND_ROUTER_ADVERT ||
275146773Ssam                      ND_NEIGHBOR_ADVERT ||
276146773Ssam                      ND_NEIGHBOR_SOLICIT ||
277146773Ssam                      ND_REDIRECT ||
278146773Ssam                      ICMP6_HADISCOV_REPLY ||
279146773Ssam                      ICMP6_MOBILEPREFIX_ADVERT ))
280146773Ssam            printf(", length %u", length);
281146773Ssam
28275115Sfenner	switch (dp->icmp6_type) {
28356893Sfenner	case ICMP6_DST_UNREACH:
28456893Sfenner		TCHECK(oip->ip6_dst);
285146773Ssam                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
28656893Sfenner		switch (dp->icmp6_code) {
287146773Ssam
288146773Ssam		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
28956893Sfenner		case ICMP6_DST_UNREACH_ADMIN:
290146773Ssam		case ICMP6_DST_UNREACH_ADDR:
291146773Ssam                        printf(" %s",ip6addr_string(&oip->ip6_dst));
292146773Ssam                        break;
29356893Sfenner		case ICMP6_DST_UNREACH_BEYONDSCOPE:
294146773Ssam			printf(" %s, source address %s",
29556893Sfenner			       ip6addr_string(&oip->ip6_dst),
29656893Sfenner			       ip6addr_string(&oip->ip6_src));
29756893Sfenner			break;
29856893Sfenner		case ICMP6_DST_UNREACH_NOPORT:
29975115Sfenner			if ((ouh = get_upperlayer((u_char *)oip, &prot))
30075115Sfenner			    == NULL)
30175115Sfenner				goto trunc;
30275115Sfenner
303127668Sbms			dport = EXTRACT_16BITS(&ouh->uh_dport);
30475115Sfenner			switch (prot) {
30556893Sfenner			case IPPROTO_TCP:
306146773Ssam				printf(", %s tcp port %s",
30756893Sfenner					ip6addr_string(&oip->ip6_dst),
30856893Sfenner					tcpport_string(dport));
30956893Sfenner				break;
31056893Sfenner			case IPPROTO_UDP:
311146773Ssam				printf(", %s udp port %s",
31256893Sfenner					ip6addr_string(&oip->ip6_dst),
31356893Sfenner					udpport_string(dport));
31456893Sfenner				break;
31556893Sfenner			default:
316146773Ssam				printf(", %s protocol %d port %d unreachable",
31756893Sfenner					ip6addr_string(&oip->ip6_dst),
31856893Sfenner					oip->ip6_nxt, dport);
31956893Sfenner				break;
32056893Sfenner			}
32156893Sfenner			break;
32256893Sfenner		default:
323146773Ssam                    if (vflag <= 1) {
324146773Ssam                            print_unknown_data(bp,"\n\t",length);
325146773Ssam                            return;
326146773Ssam                    }
327146773Ssam                    break;
32856893Sfenner		}
32956893Sfenner		break;
33056893Sfenner	case ICMP6_PACKET_TOO_BIG:
33156893Sfenner		TCHECK(dp->icmp6_mtu);
332146773Ssam		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
33356893Sfenner		break;
33456893Sfenner	case ICMP6_TIME_EXCEEDED:
33556893Sfenner		TCHECK(oip->ip6_dst);
33656893Sfenner		switch (dp->icmp6_code) {
33756893Sfenner		case ICMP6_TIME_EXCEED_TRANSIT:
338146773Ssam			printf(" for %s",
33956893Sfenner				ip6addr_string(&oip->ip6_dst));
34056893Sfenner			break;
34156893Sfenner		case ICMP6_TIME_EXCEED_REASSEMBLY:
342146773Ssam			printf(" (reassembly)");
34356893Sfenner			break;
34456893Sfenner		default:
345146773Ssam			printf(", unknown code (%u)", dp->icmp6_code);
34656893Sfenner			break;
34756893Sfenner		}
34856893Sfenner		break;
34956893Sfenner	case ICMP6_PARAM_PROB:
35056893Sfenner		TCHECK(oip->ip6_dst);
35156893Sfenner		switch (dp->icmp6_code) {
35256893Sfenner		case ICMP6_PARAMPROB_HEADER:
353146773Ssam			printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
35456893Sfenner			break;
35556893Sfenner		case ICMP6_PARAMPROB_NEXTHEADER:
356146773Ssam			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
35756893Sfenner			break;
35856893Sfenner		case ICMP6_PARAMPROB_OPTION:
359146773Ssam			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
36056893Sfenner			break;
36156893Sfenner		default:
362146773Ssam			printf(", code-#%d",
36356893Sfenner			       dp->icmp6_code);
36456893Sfenner			break;
36556893Sfenner		}
36656893Sfenner		break;
36756893Sfenner	case ICMP6_ECHO_REQUEST:
36856893Sfenner	case ICMP6_ECHO_REPLY:
369127668Sbms		TCHECK(dp->icmp6_seq);
370146773Ssam		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
37156893Sfenner		break;
37256893Sfenner	case ICMP6_MEMBERSHIP_QUERY:
373146773Ssam		if (length == MLD_MINLEN) {
374146773Ssam			mld6_print((const u_char *)dp);
375146773Ssam		} else if (length >= MLDV2_MINLEN) {
376146773Ssam			printf("v2 ");
377146773Ssam			mldv2_query_print((const u_char *)dp, length);
378146773Ssam		} else {
379146773Ssam			printf(" unknown-version (len %u) ", length);
380146773Ssam		}
38156893Sfenner		break;
38256893Sfenner	case ICMP6_MEMBERSHIP_REPORT:
38356893Sfenner		mld6_print((const u_char *)dp);
38456893Sfenner		break;
38556893Sfenner	case ICMP6_MEMBERSHIP_REDUCTION:
38656893Sfenner		mld6_print((const u_char *)dp);
38756893Sfenner		break;
38856893Sfenner	case ND_ROUTER_SOLICIT:
389146773Ssam#define RTSOLLEN 8
39056893Sfenner		if (vflag) {
39175115Sfenner			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
392127668Sbms					length - RTSOLLEN);
39356893Sfenner		}
39456893Sfenner		break;
39556893Sfenner	case ND_ROUTER_ADVERT:
396146773Ssam#define RTADVLEN 16
39756893Sfenner		if (vflag) {
39856893Sfenner			struct nd_router_advert *p;
39956893Sfenner
40056893Sfenner			p = (struct nd_router_advert *)dp;
40156893Sfenner			TCHECK(p->nd_ra_retransmit);
402146773Ssam			printf("\n\thop limit %u, Flags [%s]" \
403146773Ssam                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
404146773Ssam                               (u_int)p->nd_ra_curhoplimit,
405146773Ssam                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
406146773Ssam                               get_rtpref(p->nd_ra_flags_reserved),
407146773Ssam                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
408146773Ssam                               EXTRACT_32BITS(&p->nd_ra_reachable),
409146773Ssam                               EXTRACT_32BITS(&p->nd_ra_retransmit));
41098524Sfenner
41175115Sfenner			icmp6_opt_print((const u_char *)dp + RTADVLEN,
412127668Sbms					length - RTADVLEN);
41356893Sfenner		}
41456893Sfenner		break;
41556893Sfenner	case ND_NEIGHBOR_SOLICIT:
41656893Sfenner	    {
41756893Sfenner		struct nd_neighbor_solicit *p;
41856893Sfenner		p = (struct nd_neighbor_solicit *)dp;
41956893Sfenner		TCHECK(p->nd_ns_target);
420146773Ssam		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
42156893Sfenner		if (vflag) {
42256893Sfenner#define NDSOLLEN 24
42375115Sfenner			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
424127668Sbms					length - NDSOLLEN);
42556893Sfenner		}
42656893Sfenner	    }
42756893Sfenner		break;
42856893Sfenner	case ND_NEIGHBOR_ADVERT:
42956893Sfenner	    {
43056893Sfenner		struct nd_neighbor_advert *p;
43156893Sfenner
43256893Sfenner		p = (struct nd_neighbor_advert *)dp;
43356893Sfenner		TCHECK(p->nd_na_target);
434146773Ssam		printf(", tgt is %s",
43556893Sfenner			ip6addr_string(&p->nd_na_target));
43675115Sfenner		if (vflag) {
437146773Ssam                        printf(", Flags [%s]",
438146773Ssam                               bittok2str(icmp6_nd_na_flag_values,
439146773Ssam                                          "none",
440146773Ssam                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
44156893Sfenner#define NDADVLEN 24
44275115Sfenner			icmp6_opt_print((const u_char *)dp + NDADVLEN,
443127668Sbms					length - NDADVLEN);
44475115Sfenner#undef NDADVLEN
44556893Sfenner		}
44656893Sfenner	    }
44756893Sfenner		break;
44856893Sfenner	case ND_REDIRECT:
44956893Sfenner#define RDR(i) ((struct nd_redirect *)(i))
45056893Sfenner		TCHECK(RDR(dp)->nd_rd_dst);
451146773Ssam		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
452127668Sbms		TCHECK(RDR(dp)->nd_rd_target);
45375115Sfenner		printf(" to %s",
45475115Sfenner		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
45556893Sfenner#define REDIRECTLEN 40
45656893Sfenner		if (vflag) {
45756893Sfenner			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
458127668Sbms					length - REDIRECTLEN);
45956893Sfenner		}
46056893Sfenner		break;
46175115Sfenner#undef REDIRECTLEN
46275115Sfenner#undef RDR
46356893Sfenner	case ICMP6_ROUTER_RENUMBERING:
464127668Sbms		icmp6_rrenum_print(bp, ep);
46556893Sfenner		break;
46675115Sfenner	case ICMP6_NI_QUERY:
46775115Sfenner	case ICMP6_NI_REPLY:
468127668Sbms		icmp6_nodeinfo_print(length, bp, ep);
46956893Sfenner		break;
470146773Ssam	case IND_SOLICIT:
471146773Ssam	case IND_ADVERT:
472146773Ssam		break;
473146773Ssam	case ICMP6_V2_MEMBERSHIP_REPORT:
474146773Ssam		mldv2_report_print((const u_char *) dp, length);
475146773Ssam		break;
476146773Ssam	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
477127668Sbms	case ICMP6_HADISCOV_REQUEST:
478146773Ssam                TCHECK(dp->icmp6_data16[0]);
479146773Ssam                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
480146773Ssam                break;
481127668Sbms	case ICMP6_HADISCOV_REPLY:
482127668Sbms		if (vflag) {
483127668Sbms			struct in6_addr *in6;
484127668Sbms			u_char *cp;
485127668Sbms
486127668Sbms			TCHECK(dp->icmp6_data16[0]);
487146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
488127668Sbms			cp = (u_char *)dp + length;
489127668Sbms			in6 = (struct in6_addr *)(dp + 1);
490127668Sbms			for (; (u_char *)in6 < cp; in6++) {
491127668Sbms				TCHECK(*in6);
492127668Sbms				printf(", %s", ip6addr_string(in6));
493127668Sbms			}
494127668Sbms		}
495127668Sbms		break;
496127668Sbms	case ICMP6_MOBILEPREFIX_ADVERT:
497127668Sbms		if (vflag) {
498127668Sbms			TCHECK(dp->icmp6_data16[0]);
499146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
500127668Sbms			if (dp->icmp6_data16[1] & 0xc0)
501127668Sbms				printf(" ");
502127668Sbms			if (dp->icmp6_data16[1] & 0x80)
503127668Sbms				printf("M");
504127668Sbms			if (dp->icmp6_data16[1] & 0x40)
505127668Sbms				printf("O");
506127668Sbms#define MPADVLEN 8
507127668Sbms			icmp6_opt_print((const u_char *)dp + MPADVLEN,
508127668Sbms					length - MPADVLEN);
509127668Sbms		}
510127668Sbms		break;
51156893Sfenner	default:
512146773Ssam                printf(", length %u", length);
513146773Ssam                if (vflag <= 1)
514146773Ssam                    print_unknown_data(bp,"\n\t", length);
515146773Ssam                return;
516146773Ssam        }
517146773Ssam        if (!vflag)
518146773Ssam            printf(", length %u", length);
51956893Sfenner	return;
52056893Sfennertrunc:
52156893Sfenner	fputs("[|icmp6]", stdout);
52256893Sfenner}
52356893Sfenner
52475115Sfennerstatic struct udphdr *
525127668Sbmsget_upperlayer(u_char *bp, u_int *prot)
52675115Sfenner{
52798524Sfenner	const u_char *ep;
52875115Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
52975115Sfenner	struct udphdr *uh;
53075115Sfenner	struct ip6_hbh *hbh;
53175115Sfenner	struct ip6_frag *fragh;
53275115Sfenner	struct ah *ah;
533127668Sbms	u_int nh;
534127668Sbms	int hlen;
53575115Sfenner
53675115Sfenner	/* 'ep' points to the end of available data. */
53775115Sfenner	ep = snapend;
53875115Sfenner
539127668Sbms	if (!TTEST(ip6->ip6_nxt))
54075115Sfenner		return NULL;
54175115Sfenner
54275115Sfenner	nh = ip6->ip6_nxt;
54375115Sfenner	hlen = sizeof(struct ip6_hdr);
54475115Sfenner
54575115Sfenner	while (bp < snapend) {
54675115Sfenner		bp += hlen;
54775115Sfenner
54875115Sfenner		switch(nh) {
54975115Sfenner		case IPPROTO_UDP:
55075115Sfenner		case IPPROTO_TCP:
55175115Sfenner			uh = (struct udphdr *)bp;
55275115Sfenner			if (TTEST(uh->uh_dport)) {
55375115Sfenner				*prot = nh;
55475115Sfenner				return(uh);
55575115Sfenner			}
55675115Sfenner			else
55775115Sfenner				return(NULL);
55875115Sfenner			/* NOTREACHED */
55975115Sfenner
56075115Sfenner		case IPPROTO_HOPOPTS:
56175115Sfenner		case IPPROTO_DSTOPTS:
56275115Sfenner		case IPPROTO_ROUTING:
56375115Sfenner			hbh = (struct ip6_hbh *)bp;
564127668Sbms			if (!TTEST(hbh->ip6h_len))
56575115Sfenner				return(NULL);
56675115Sfenner			nh = hbh->ip6h_nxt;
56775115Sfenner			hlen = (hbh->ip6h_len + 1) << 3;
56875115Sfenner			break;
56975115Sfenner
57075115Sfenner		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
57175115Sfenner			fragh = (struct ip6_frag *)bp;
572127668Sbms			if (!TTEST(fragh->ip6f_offlg))
57375115Sfenner				return(NULL);
57475115Sfenner			/* fragments with non-zero offset are meaningless */
575127668Sbms			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
57675115Sfenner				return(NULL);
57775115Sfenner			nh = fragh->ip6f_nxt;
57875115Sfenner			hlen = sizeof(struct ip6_frag);
57975115Sfenner			break;
58075115Sfenner
58175115Sfenner		case IPPROTO_AH:
58275115Sfenner			ah = (struct ah *)bp;
583127668Sbms			if (!TTEST(ah->ah_len))
58475115Sfenner				return(NULL);
58575115Sfenner			nh = ah->ah_nxt;
58675115Sfenner			hlen = (ah->ah_len + 2) << 2;
58775115Sfenner			break;
58875115Sfenner
58975115Sfenner		default:	/* unknown or undecodable header */
59075115Sfenner			*prot = nh; /* meaningless, but set here anyway */
59175115Sfenner			return(NULL);
59275115Sfenner		}
59375115Sfenner	}
59475115Sfenner
59575115Sfenner	return(NULL);		/* should be notreached, though */
59675115Sfenner}
59775115Sfenner
598127668Sbmsstatic void
59998524Sfennericmp6_opt_print(const u_char *bp, int resid)
60056893Sfenner{
60198524Sfenner	const struct nd_opt_hdr *op;
60298524Sfenner	const struct nd_opt_hdr *opl;	/* why there's no struct? */
60398524Sfenner	const struct nd_opt_prefix_info *opp;
60498524Sfenner	const struct icmp6_opts_redirect *opr;
60598524Sfenner	const struct nd_opt_mtu *opm;
60698524Sfenner	const struct nd_opt_advinterval *opa;
607127668Sbms	const struct nd_opt_homeagent_info *oph;
60898524Sfenner	const struct nd_opt_route_info *opri;
60998524Sfenner	const u_char *cp, *ep;
61098524Sfenner	struct in6_addr in6, *in6p;
61198524Sfenner	size_t l;
61256893Sfenner
61356893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
61456893Sfenner
61598524Sfenner	cp = bp;
61675115Sfenner	/* 'ep' points to the end of available data. */
61756893Sfenner	ep = snapend;
61856893Sfenner
61998524Sfenner	while (cp < ep) {
62098524Sfenner		op = (struct nd_opt_hdr *)cp;
62198524Sfenner
62298524Sfenner		ECHECK(op->nd_opt_len);
62398524Sfenner		if (resid <= 0)
62498524Sfenner			return;
62598524Sfenner		if (op->nd_opt_len == 0)
62656893Sfenner			goto trunc;
62798524Sfenner		if (cp + (op->nd_opt_len << 3) > ep)
62856893Sfenner			goto trunc;
62998524Sfenner
630146773Ssam                printf("\n\t  %s option (%u), length %u (%u): ",
631146773Ssam                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
632146773Ssam                       op->nd_opt_type,
633146773Ssam                       op->nd_opt_len << 3,
634146773Ssam                       op->nd_opt_len);
635146773Ssam
63698524Sfenner		switch (op->nd_opt_type) {
63798524Sfenner		case ND_OPT_SOURCE_LINKADDR:
63898524Sfenner			opl = (struct nd_opt_hdr *)op;
63998524Sfenner			l = (op->nd_opt_len << 3) - 2;
64098524Sfenner			print_lladdr(cp + 2, l);
64198524Sfenner			break;
64298524Sfenner		case ND_OPT_TARGET_LINKADDR:
64398524Sfenner			opl = (struct nd_opt_hdr *)op;
64498524Sfenner			l = (op->nd_opt_len << 3) - 2;
64598524Sfenner			print_lladdr(cp + 2, l);
64698524Sfenner			break;
64798524Sfenner		case ND_OPT_PREFIX_INFORMATION:
64898524Sfenner			opp = (struct nd_opt_prefix_info *)op;
64998524Sfenner			TCHECK(opp->nd_opt_pi_prefix);
650146773Ssam                        printf("%s/%u%s, Flags [%s], valid time %ss",
651146773Ssam                               ip6addr_string(&opp->nd_opt_pi_prefix),
652146773Ssam                               opp->nd_opt_pi_prefix_len,
653146773Ssam                               (op->nd_opt_len != 4) ? "badlen" : "",
654146773Ssam                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
655146773Ssam                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
656146773Ssam                        printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
65798524Sfenner			break;
65898524Sfenner		case ND_OPT_REDIRECTED_HEADER:
65998524Sfenner			opr = (struct icmp6_opts_redirect *)op;
660146773Ssam                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
66198524Sfenner			/* xxx */
66298524Sfenner			break;
66398524Sfenner		case ND_OPT_MTU:
66498524Sfenner			opm = (struct nd_opt_mtu *)op;
66598524Sfenner			TCHECK(opm->nd_opt_mtu_mtu);
666146773Ssam			printf(" %u%s",
667146773Ssam                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
668146773Ssam                               (op->nd_opt_len != 1) ? "bad option length" : "" );
669146773Ssam                        break;
67098524Sfenner		case ND_OPT_ADVINTERVAL:
67198524Sfenner			opa = (struct nd_opt_advinterval *)op;
67298524Sfenner			TCHECK(opa->nd_opt_adv_interval);
673146773Ssam			printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
674127668Sbms			break;
675127668Sbms		case ND_OPT_HOMEAGENT_INFO:
676127668Sbms			oph = (struct nd_opt_homeagent_info *)op;
677127668Sbms			TCHECK(oph->nd_opt_hai_lifetime);
678146773Ssam			printf(" preference %u, lifetime %u",
679146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
680146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
681127668Sbms			break;
68298524Sfenner		case ND_OPT_ROUTE_INFO:
68398524Sfenner			opri = (struct nd_opt_route_info *)op;
68498524Sfenner			TCHECK(opri->nd_opt_rti_lifetime);
68598524Sfenner			memset(&in6, 0, sizeof(in6));
68698524Sfenner			in6p = (struct in6_addr *)(opri + 1);
68798524Sfenner			switch (op->nd_opt_len) {
68898524Sfenner			case 1:
68998524Sfenner				break;
69098524Sfenner			case 2:
69198524Sfenner				TCHECK2(*in6p, 8);
69298524Sfenner				memcpy(&in6, opri + 1, 8);
69398524Sfenner				break;
69498524Sfenner			case 3:
69598524Sfenner				TCHECK(*in6p);
69698524Sfenner				memcpy(&in6, opri + 1, sizeof(in6));
69798524Sfenner				break;
69898524Sfenner			default:
69998524Sfenner				goto trunc;
70098524Sfenner			}
70198524Sfenner			printf(" %s/%u", ip6addr_string(&in6),
70298524Sfenner			    opri->nd_opt_rti_prefixlen);
70398524Sfenner			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
70498524Sfenner			printf(", lifetime=%s",
705127668Sbms			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
70698524Sfenner			break;
70798524Sfenner		default:
708146773Ssam                        if (vflag <= 1) {
709146773Ssam                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
710146773Ssam                            return;
711146773Ssam                        }
712146773Ssam                        break;
71356893Sfenner		}
714146773Ssam                /* do we want to see an additional hexdump ? */
715146773Ssam                if (vflag> 1)
716146773Ssam                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
71798524Sfenner
71898524Sfenner		cp += op->nd_opt_len << 3;
71998524Sfenner		resid -= op->nd_opt_len << 3;
72056893Sfenner	}
72156893Sfenner	return;
72298524Sfenner
72356893Sfenner trunc:
72456893Sfenner	fputs("[ndp opt]", stdout);
72556893Sfenner	return;
72656893Sfenner#undef ECHECK
72756893Sfenner}
72856893Sfenner
729127668Sbmsstatic void
73098524Sfennermld6_print(const u_char *bp)
73156893Sfenner{
73298524Sfenner	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
73398524Sfenner	const u_char *ep;
73456893Sfenner
73575115Sfenner	/* 'ep' points to the end of available data. */
73656893Sfenner	ep = snapend;
73756893Sfenner
73856893Sfenner	if ((u_char *)mp + sizeof(*mp) > ep)
73956893Sfenner		return;
74056893Sfenner
741127668Sbms	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
74256893Sfenner	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
74375115Sfenner}
74456893Sfenner
74575115Sfennerstatic void
746146773Ssammldv2_report_print(const u_char *bp, u_int len)
747146773Ssam{
748146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
749146773Ssam    u_int group, nsrcs, ngroups;
750146773Ssam    u_int i, j;
751146773Ssam
752146773Ssam    /* Minimum len is 8 */
753146773Ssam    if (len < 8) {
754146773Ssam	printf(" [invalid len %d]", len);
755146773Ssam	return;
756146773Ssam    }
757146773Ssam
758146773Ssam    TCHECK(icp->icmp6_data16[1]);
759146773Ssam    ngroups = ntohs(icp->icmp6_data16[1]);
760146773Ssam    printf(", %d group record(s)", ngroups);
761146773Ssam    if (vflag > 0) {
762146773Ssam	/* Print the group records */
763146773Ssam	group = 8;
764146773Ssam        for (i = 0; i < ngroups; i++) {
765146773Ssam	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
766146773Ssam	    if (len < group + 20) {
767146773Ssam		printf(" [invalid number of groups]");
768146773Ssam		return;
769146773Ssam	    }
770146773Ssam            TCHECK2(bp[group + 4], 16);
771146773Ssam            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
772146773Ssam	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
773146773Ssam								bp[group]));
774146773Ssam            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
775146773Ssam	    /* Check the number of sources and print them */
776146773Ssam	    if (len < group + 20 + (nsrcs * 16)) {
777146773Ssam		printf(" [invalid number of sources %d]", nsrcs);
778146773Ssam		return;
779146773Ssam	    }
780146773Ssam            if (vflag == 1)
781146773Ssam                printf(", %d source(s)", nsrcs);
782146773Ssam            else {
783146773Ssam		/* Print the sources */
784146773Ssam                (void)printf(" {");
785146773Ssam                for (j = 0; j < nsrcs; j++) {
786146773Ssam                    TCHECK2(bp[group + 20 + j * 16], 16);
787146773Ssam		    printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
788146773Ssam		}
789146773Ssam                (void)printf(" }");
790146773Ssam            }
791146773Ssam	    /* Next group record */
792146773Ssam            group += 20 + nsrcs * 16;
793146773Ssam	    printf("]");
794146773Ssam        }
795146773Ssam    }
796146773Ssam    return;
797146773Ssamtrunc:
798146773Ssam    (void)printf("[|icmp6]");
799146773Ssam    return;
800146773Ssam}
801146773Ssam
802146773Ssamstatic void
803146773Ssammldv2_query_print(const u_char *bp, u_int len)
804146773Ssam{
805146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
806146773Ssam    u_int mrc;
807146773Ssam    int mrt, qqi;
808146773Ssam    u_int nsrcs;
809146773Ssam    register u_int i;
810146773Ssam
811146773Ssam    /* Minimum len is 28 */
812146773Ssam    if (len < 28) {
813146773Ssam	printf(" [invalid len %d]", len);
814146773Ssam	return;
815146773Ssam    }
816146773Ssam    TCHECK(icp->icmp6_data16[0]);
817146773Ssam    mrc = ntohs(icp->icmp6_data16[0]);
818146773Ssam    if (mrc < 32768) {
819146773Ssam	mrt = mrc;
820146773Ssam    } else {
821146773Ssam        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
822146773Ssam    }
823146773Ssam    if (vflag) {
824146773Ssam	(void)printf(" [max resp delay=%d]", mrt);
825146773Ssam    }
826146773Ssam    TCHECK2(bp[8], 16);
827146773Ssam    printf(" [gaddr %s", ip6addr_string(&bp[8]));
828146773Ssam
829146773Ssam    if (vflag) {
830146773Ssam        TCHECK(bp[25]);
831146773Ssam	if (bp[24] & 0x08) {
832146773Ssam		printf(" sflag");
833146773Ssam	}
834146773Ssam	if (bp[24] & 0x07) {
835146773Ssam		printf(" robustness=%d", bp[24] & 0x07);
836146773Ssam	}
837146773Ssam	if (bp[25] < 128) {
838146773Ssam		qqi = bp[25];
839146773Ssam	} else {
840146773Ssam		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
841146773Ssam	}
842146773Ssam	printf(" qqi=%d", qqi);
843146773Ssam    }
844146773Ssam
845146773Ssam    TCHECK2(bp[26], 2);
846146773Ssam    nsrcs = ntohs(*(u_short *)&bp[26]);
847146773Ssam    if (nsrcs > 0) {
848146773Ssam	if (len < 28 + nsrcs * 16)
849146773Ssam	    printf(" [invalid number of sources]");
850146773Ssam	else if (vflag > 1) {
851146773Ssam	    printf(" {");
852146773Ssam	    for (i = 0; i < nsrcs; i++) {
853146773Ssam		TCHECK2(bp[28 + i * 16], 16);
854146773Ssam		printf(" %s", ip6addr_string(&bp[28 + i * 16]));
855146773Ssam	    }
856146773Ssam	    printf(" }");
857146773Ssam	} else
858146773Ssam	    printf(", %d source(s)", nsrcs);
859146773Ssam    }
860146773Ssam    printf("]");
861146773Ssam    return;
862146773Ssamtrunc:
863146773Ssam    (void)printf("[|icmp6]");
864146773Ssam    return;
865146773Ssam}
866146773Ssam
867146773Ssamvoid
86875115Sfennerdnsname_print(const u_char *cp, const u_char *ep)
86975115Sfenner{
87075115Sfenner	int i;
87175115Sfenner
87275115Sfenner	/* DNS name decoding - no decompression */
87375115Sfenner	printf(", \"");
87475115Sfenner	while (cp < ep) {
87575115Sfenner		i = *cp++;
87675115Sfenner		if (i) {
87775115Sfenner			if (i > ep - cp) {
87875115Sfenner				printf("???");
87975115Sfenner				break;
88075115Sfenner			}
88175115Sfenner			while (i-- && cp < ep) {
88275115Sfenner				safeputchar(*cp);
88375115Sfenner				cp++;
88475115Sfenner			}
88575115Sfenner			if (cp + 1 < ep && *cp)
88675115Sfenner				printf(".");
88775115Sfenner		} else {
88875115Sfenner			if (cp == ep) {
88975115Sfenner				/* FQDN */
89075115Sfenner				printf(".");
89175115Sfenner			} else if (cp + 1 == ep && *cp == '\0') {
89275115Sfenner				/* truncated */
89375115Sfenner			} else {
89475115Sfenner				/* invalid */
89575115Sfenner				printf("???");
89675115Sfenner			}
89775115Sfenner			break;
89875115Sfenner		}
89975115Sfenner	}
90075115Sfenner	printf("\"");
90175115Sfenner}
90275115Sfenner
903127668Sbmsstatic void
904127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
90575115Sfenner{
90675115Sfenner	struct icmp6_nodeinfo *ni6;
90775115Sfenner	struct icmp6_hdr *dp;
90875115Sfenner	const u_char *cp;
909127668Sbms	size_t siz, i;
91075115Sfenner	int needcomma;
91175115Sfenner
912127668Sbms	if (ep < bp)
913127668Sbms		return;
91475115Sfenner	dp = (struct icmp6_hdr *)bp;
91575115Sfenner	ni6 = (struct icmp6_nodeinfo *)bp;
91675115Sfenner	siz = ep - bp;
91775115Sfenner
91875115Sfenner	switch (ni6->ni_type) {
91975115Sfenner	case ICMP6_NI_QUERY:
92075115Sfenner		if (siz == sizeof(*dp) + 4) {
92175115Sfenner			/* KAME who-are-you */
922146773Ssam			printf(" who-are-you request");
92375115Sfenner			break;
92475115Sfenner		}
925146773Ssam		printf(" node information query");
92675115Sfenner
92775115Sfenner		TCHECK2(*dp, sizeof(*ni6));
92875115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
92975115Sfenner		printf(" (");	/*)*/
930127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
93175115Sfenner		case NI_QTYPE_NOOP:
93275115Sfenner			printf("noop");
93375115Sfenner			break;
93475115Sfenner		case NI_QTYPE_SUPTYPES:
93575115Sfenner			printf("supported qtypes");
936127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
93775115Sfenner			if (i)
93875115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
93975115Sfenner			break;
94075115Sfenner			break;
94175115Sfenner		case NI_QTYPE_FQDN:
94275115Sfenner			printf("DNS name");
94375115Sfenner			break;
94475115Sfenner		case NI_QTYPE_NODEADDR:
94575115Sfenner			printf("node addresses");
94675115Sfenner			i = ni6->ni_flags;
94775115Sfenner			if (!i)
94875115Sfenner				break;
94975115Sfenner			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
95075115Sfenner			printf(" [%s%s%s%s%s%s]",
95175115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
95275115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
95375115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
95475115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
95575115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
95675115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
95775115Sfenner			break;
95875115Sfenner		default:
95975115Sfenner			printf("unknown");
96075115Sfenner			break;
96175115Sfenner		}
96275115Sfenner
96375115Sfenner		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
96475115Sfenner		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
96575115Sfenner			if (siz != sizeof(*ni6))
96675115Sfenner				if (vflag)
96775115Sfenner					printf(", invalid len");
96875115Sfenner			/*(*/
96975115Sfenner			printf(")");
97075115Sfenner			break;
97175115Sfenner		}
97275115Sfenner
97375115Sfenner
97475115Sfenner		/* XXX backward compat, icmp-name-lookup-03 */
97575115Sfenner		if (siz == sizeof(*ni6)) {
97675115Sfenner			printf(", 03 draft");
97775115Sfenner			/*(*/
97875115Sfenner			printf(")");
97975115Sfenner			break;
98075115Sfenner		}
98175115Sfenner
98275115Sfenner		switch (ni6->ni_code) {
98375115Sfenner		case ICMP6_NI_SUBJ_IPV6:
98475115Sfenner			if (!TTEST2(*dp,
98575115Sfenner			    sizeof(*ni6) + sizeof(struct in6_addr)))
98675115Sfenner				break;
98775115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
98875115Sfenner				if (vflag)
98975115Sfenner					printf(", invalid subject len");
99075115Sfenner				break;
99175115Sfenner			}
99275115Sfenner			printf(", subject=%s",
99375115Sfenner			    getname6((const u_char *)(ni6 + 1)));
99475115Sfenner			break;
99575115Sfenner		case ICMP6_NI_SUBJ_FQDN:
99675115Sfenner			printf(", subject=DNS name");
99775115Sfenner			cp = (const u_char *)(ni6 + 1);
99875115Sfenner			if (cp[0] == ep - cp - 1) {
99975115Sfenner				/* icmp-name-lookup-03, pascal string */
100075115Sfenner				if (vflag)
100175115Sfenner					printf(", 03 draft");
100275115Sfenner				cp++;
100375115Sfenner				printf(", \"");
100475115Sfenner				while (cp < ep) {
100575115Sfenner					safeputchar(*cp);
100675115Sfenner					cp++;
100775115Sfenner				}
100875115Sfenner				printf("\"");
100975115Sfenner			} else
101075115Sfenner				dnsname_print(cp, ep);
101175115Sfenner			break;
101275115Sfenner		case ICMP6_NI_SUBJ_IPV4:
101375115Sfenner			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
101475115Sfenner				break;
101575115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
101675115Sfenner				if (vflag)
101775115Sfenner					printf(", invalid subject len");
101875115Sfenner				break;
101975115Sfenner			}
102075115Sfenner			printf(", subject=%s",
102175115Sfenner			    getname((const u_char *)(ni6 + 1)));
102275115Sfenner			break;
102375115Sfenner		default:
102475115Sfenner			printf(", unknown subject");
102575115Sfenner			break;
102675115Sfenner		}
102775115Sfenner
102875115Sfenner		/*(*/
102975115Sfenner		printf(")");
103075115Sfenner		break;
103175115Sfenner
103275115Sfenner	case ICMP6_NI_REPLY:
103375115Sfenner		if (icmp6len > siz) {
103475115Sfenner			printf("[|icmp6: node information reply]");
103575115Sfenner			break;
103675115Sfenner		}
103775115Sfenner
103875115Sfenner		needcomma = 0;
103975115Sfenner
104075115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
1041146773Ssam		printf(" node information reply");
104275115Sfenner		printf(" (");	/*)*/
104375115Sfenner		switch (ni6->ni_code) {
104475115Sfenner		case ICMP6_NI_SUCCESS:
104575115Sfenner			if (vflag) {
104675115Sfenner				printf("success");
104775115Sfenner				needcomma++;
104875115Sfenner			}
104975115Sfenner			break;
105075115Sfenner		case ICMP6_NI_REFUSED:
105175115Sfenner			printf("refused");
105275115Sfenner			needcomma++;
105375115Sfenner			if (siz != sizeof(*ni6))
105475115Sfenner				if (vflag)
105575115Sfenner					printf(", invalid length");
105675115Sfenner			break;
105775115Sfenner		case ICMP6_NI_UNKNOWN:
105875115Sfenner			printf("unknown");
105975115Sfenner			needcomma++;
106075115Sfenner			if (siz != sizeof(*ni6))
106175115Sfenner				if (vflag)
106275115Sfenner					printf(", invalid length");
106375115Sfenner			break;
106475115Sfenner		}
106575115Sfenner
106675115Sfenner		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
106775115Sfenner			/*(*/
106875115Sfenner			printf(")");
106975115Sfenner			break;
107075115Sfenner		}
107175115Sfenner
1072127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
107375115Sfenner		case NI_QTYPE_NOOP:
107475115Sfenner			if (needcomma)
107575115Sfenner				printf(", ");
107675115Sfenner			printf("noop");
107775115Sfenner			if (siz != sizeof(*ni6))
107875115Sfenner				if (vflag)
107975115Sfenner					printf(", invalid length");
108075115Sfenner			break;
108175115Sfenner		case NI_QTYPE_SUPTYPES:
108275115Sfenner			if (needcomma)
108375115Sfenner				printf(", ");
108475115Sfenner			printf("supported qtypes");
1085127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
108675115Sfenner			if (i)
108775115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
108875115Sfenner			break;
108975115Sfenner		case NI_QTYPE_FQDN:
109075115Sfenner			if (needcomma)
109175115Sfenner				printf(", ");
109275115Sfenner			printf("DNS name");
109375115Sfenner			cp = (const u_char *)(ni6 + 1) + 4;
109475115Sfenner			if (cp[0] == ep - cp - 1) {
109575115Sfenner				/* icmp-name-lookup-03, pascal string */
109675115Sfenner				if (vflag)
109775115Sfenner					printf(", 03 draft");
109875115Sfenner				cp++;
109975115Sfenner				printf(", \"");
110075115Sfenner				while (cp < ep) {
110175115Sfenner					safeputchar(*cp);
110275115Sfenner					cp++;
110375115Sfenner				}
110475115Sfenner				printf("\"");
110575115Sfenner			} else
110675115Sfenner				dnsname_print(cp, ep);
1107127668Sbms			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
110875115Sfenner				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
110975115Sfenner			break;
111075115Sfenner		case NI_QTYPE_NODEADDR:
111175115Sfenner			if (needcomma)
111275115Sfenner				printf(", ");
111375115Sfenner			printf("node addresses");
111475115Sfenner			i = sizeof(*ni6);
111575115Sfenner			while (i < siz) {
111675115Sfenner				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
111775115Sfenner					break;
111875115Sfenner				printf(" %s", getname6(bp + i));
111975115Sfenner				i += sizeof(struct in6_addr);
1120127668Sbms				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
112175115Sfenner				i += sizeof(int32_t);
112275115Sfenner			}
112375115Sfenner			i = ni6->ni_flags;
112475115Sfenner			if (!i)
112575115Sfenner				break;
112675115Sfenner			printf(" [%s%s%s%s%s%s%s]",
112775115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
112875115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
112975115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
113075115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
113175115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
113275115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
113375115Sfenner			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
113475115Sfenner			break;
113575115Sfenner		default:
113675115Sfenner			if (needcomma)
113775115Sfenner				printf(", ");
113875115Sfenner			printf("unknown");
113975115Sfenner			break;
114075115Sfenner		}
114175115Sfenner
114275115Sfenner		/*(*/
114375115Sfenner		printf(")");
114475115Sfenner		break;
114575115Sfenner	}
114656893Sfenner	return;
114775115Sfenner
114875115Sfennertrunc:
114975115Sfenner	fputs("[|icmp6]", stdout);
115056893Sfenner}
115175115Sfenner
1152127668Sbmsstatic void
1153127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep)
115475115Sfenner{
115575115Sfenner	struct icmp6_router_renum *rr6;
115675115Sfenner	struct icmp6_hdr *dp;
115775115Sfenner	size_t siz;
115875115Sfenner	const char *cp;
115975115Sfenner	struct rr_pco_match *match;
116075115Sfenner	struct rr_pco_use *use;
116175115Sfenner	char hbuf[NI_MAXHOST];
116275115Sfenner	int n;
116375115Sfenner
1164127668Sbms	if (ep < bp)
1165127668Sbms		return;
116675115Sfenner	dp = (struct icmp6_hdr *)bp;
116775115Sfenner	rr6 = (struct icmp6_router_renum *)bp;
116875115Sfenner	siz = ep - bp;
116975115Sfenner	cp = (const char *)(rr6 + 1);
117075115Sfenner
117175115Sfenner	TCHECK(rr6->rr_reserved);
117275115Sfenner	switch (rr6->rr_code) {
117375115Sfenner	case ICMP6_ROUTER_RENUMBERING_COMMAND:
117475115Sfenner		printf("router renum: command");
117575115Sfenner		break;
117675115Sfenner	case ICMP6_ROUTER_RENUMBERING_RESULT:
117775115Sfenner		printf("router renum: result");
117875115Sfenner		break;
117975115Sfenner	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
118075115Sfenner		printf("router renum: sequence number reset");
118175115Sfenner		break;
118275115Sfenner	default:
118375115Sfenner		printf("router renum: code-#%d", rr6->rr_code);
118475115Sfenner		break;
118575115Sfenner	}
118675115Sfenner
1187127668Sbms	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
118875115Sfenner
118975115Sfenner	if (vflag) {
119075115Sfenner#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
119175115Sfenner		printf("[");	/*]*/
119275115Sfenner		if (rr6->rr_flags) {
119375115Sfenner			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
119475115Sfenner			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
119598524Sfenner			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
119675115Sfenner			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
119775115Sfenner			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
119875115Sfenner		}
119975115Sfenner		printf("seg=%u,", rr6->rr_segnum);
120075115Sfenner		printf("maxdelay=%u", rr6->rr_maxdelay);
120175115Sfenner		if (rr6->rr_reserved)
1202127668Sbms			printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
120375115Sfenner		/*[*/
120475115Sfenner		printf("]");
120575115Sfenner#undef F
120675115Sfenner	}
120775115Sfenner
120875115Sfenner	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
120975115Sfenner		match = (struct rr_pco_match *)cp;
121075115Sfenner		cp = (const char *)(match + 1);
121175115Sfenner
121275115Sfenner		TCHECK(match->rpm_prefix);
121375115Sfenner
121498524Sfenner		if (vflag > 1)
121575115Sfenner			printf("\n\t");
121675115Sfenner		else
121775115Sfenner			printf(" ");
121875115Sfenner		printf("match(");	/*)*/
121975115Sfenner		switch (match->rpm_code) {
122075115Sfenner		case RPM_PCO_ADD:	printf("add"); break;
122175115Sfenner		case RPM_PCO_CHANGE:	printf("change"); break;
122275115Sfenner		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
122375115Sfenner		default:		printf("#%u", match->rpm_code); break;
122475115Sfenner		}
122575115Sfenner
122675115Sfenner		if (vflag) {
122775115Sfenner			printf(",ord=%u", match->rpm_ordinal);
122875115Sfenner			printf(",min=%u", match->rpm_minlen);
122975115Sfenner			printf(",max=%u", match->rpm_maxlen);
123075115Sfenner		}
123175115Sfenner		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
123275115Sfenner			printf(",%s/%u", hbuf, match->rpm_matchlen);
123375115Sfenner		else
123475115Sfenner			printf(",?/%u", match->rpm_matchlen);
123575115Sfenner		/*(*/
123675115Sfenner		printf(")");
123775115Sfenner
123875115Sfenner		n = match->rpm_len - 3;
123975115Sfenner		if (n % 4)
124075115Sfenner			goto trunc;
124175115Sfenner		n /= 4;
124275115Sfenner		while (n-- > 0) {
124375115Sfenner			use = (struct rr_pco_use *)cp;
124475115Sfenner			cp = (const char *)(use + 1);
124575115Sfenner
124675115Sfenner			TCHECK(use->rpu_prefix);
124775115Sfenner
124898524Sfenner			if (vflag > 1)
124975115Sfenner				printf("\n\t");
125075115Sfenner			else
125175115Sfenner				printf(" ");
125275115Sfenner			printf("use(");	/*)*/
125375115Sfenner			if (use->rpu_flags) {
125475115Sfenner#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
125575115Sfenner				printf("%s%s,",
125675115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
125775115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
125875115Sfenner#undef F
125975115Sfenner			}
126075115Sfenner			if (vflag) {
126175115Sfenner				printf("mask=0x%x,", use->rpu_ramask);
126275115Sfenner				printf("raflags=0x%x,", use->rpu_raflags);
126375115Sfenner				if (~use->rpu_vltime == 0)
126475115Sfenner					printf("vltime=infty,");
126575115Sfenner				else
126675115Sfenner					printf("vltime=%u,",
1267127668Sbms					    EXTRACT_32BITS(&use->rpu_vltime));
126875115Sfenner				if (~use->rpu_pltime == 0)
126975115Sfenner					printf("pltime=infty,");
127075115Sfenner				else
127175115Sfenner					printf("pltime=%u,",
1272127668Sbms					    EXTRACT_32BITS(&use->rpu_pltime));
127375115Sfenner			}
127475115Sfenner			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
127575115Sfenner			    sizeof(hbuf)))
127675115Sfenner				printf("%s/%u/%u", hbuf, use->rpu_uselen,
127775115Sfenner				    use->rpu_keeplen);
127875115Sfenner			else
127975115Sfenner				printf("?/%u/%u", use->rpu_uselen,
128075115Sfenner				    use->rpu_keeplen);
128175115Sfenner			/*(*/
128275115Sfenner			printf(")");
128375115Sfenner		}
128475115Sfenner	}
128575115Sfenner
128675115Sfenner	return;
128775115Sfenner
128875115Sfennertrunc:
128975115Sfenner	fputs("[|icmp6]", stdout);
129075115Sfenner}
129175115Sfenner
129256893Sfenner#endif /* INET6 */
1293