print-icmp6.c revision 229244
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_ =
24214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 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
65214478Srpaulo/* inline the various RPL definitions */
66214478Srpaulo#define ND_RPL_MESSAGE 0x9B
67214478Srpaulo
68146773Ssamstatic struct tok icmp6_type_values[] = {
69146773Ssam    { ICMP6_DST_UNREACH, "destination unreachable"},
70146773Ssam    { ICMP6_PACKET_TOO_BIG, "packet too big"},
71146773Ssam    { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
72146773Ssam    { ICMP6_PARAM_PROB, "parameter problem"},
73146773Ssam    { ICMP6_ECHO_REQUEST, "echo request"},
74146773Ssam    { ICMP6_ECHO_REPLY, "echo reply"},
75147899Ssam    { MLD6_LISTENER_QUERY, "multicast listener query"},
76147899Ssam    { MLD6_LISTENER_REPORT, "multicast listener report"},
77147899Ssam    { MLD6_LISTENER_DONE, "multicast listener done"},
78147899Ssam    { ND_ROUTER_SOLICIT, "router solicitation"},
79146773Ssam    { ND_ROUTER_ADVERT, "router advertisement"},
80146773Ssam    { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
81162017Ssam    { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
82146773Ssam    { ND_REDIRECT, "redirect"},
83146773Ssam    { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
84146773Ssam    { IND_SOLICIT, "inverse neighbor solicitation"},
85146773Ssam    { IND_ADVERT, "inverse neighbor advertisement"},
86147899Ssam    { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
87146773Ssam    { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
88146773Ssam    { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
89146773Ssam    { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
90146773Ssam    { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
91146773Ssam    { ICMP6_WRUREQUEST, "who-are-you request"},
92146773Ssam    { ICMP6_WRUREPLY, "who-are-you reply"},
93146773Ssam    { ICMP6_NI_QUERY, "node information query"},
94146773Ssam    { ICMP6_NI_REPLY, "node information reply"},
95146773Ssam    { MLD6_MTRACE, "mtrace message"},
96146773Ssam    { MLD6_MTRACE_RESP, "mtrace response"},
97214478Srpaulo    { ND_RPL_MESSAGE,   "RPL"},
98146773Ssam    { 0,	NULL }
99146773Ssam};
100146773Ssam
101146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = {
102146773Ssam    { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
103146773Ssam    { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
104146773Ssam    { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
105146773Ssam    { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
106146773Ssam    { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
107146773Ssam    { 0,	NULL }
108146773Ssam};
109146773Ssam
110146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = {
111146773Ssam    { ND_OPT_PI_FLAG_ONLINK, "onlink" },
112146773Ssam    { ND_OPT_PI_FLAG_AUTO, "auto" },
113146773Ssam    { ND_OPT_PI_FLAG_ROUTER, "router" },
114146773Ssam    { 0,	NULL }
115146773Ssam};
116146773Ssam
117146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = {
118146773Ssam    { ND_RA_FLAG_MANAGED, "managed" },
119146773Ssam    { ND_RA_FLAG_OTHER, "other stateful"},
120146773Ssam    { ND_RA_FLAG_HOME_AGENT, "home agent"},
121146773Ssam    { 0,	NULL }
122146773Ssam};
123146773Ssam
124146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = {
125146773Ssam    { ND_NA_FLAG_ROUTER, "router" },
126146773Ssam    { ND_NA_FLAG_SOLICITED, "solicited" },
127146773Ssam    { ND_NA_FLAG_OVERRIDE, "override" },
128146773Ssam    { 0,	NULL }
129146773Ssam};
130146773Ssam
131146773Ssam
132146773Ssamstatic struct tok icmp6_opt_values[] = {
133146773Ssam   { ND_OPT_SOURCE_LINKADDR, "source link-address"},
134146773Ssam   { ND_OPT_TARGET_LINKADDR, "destination link-address"},
135146773Ssam   { ND_OPT_PREFIX_INFORMATION, "prefix info"},
136146773Ssam   { ND_OPT_REDIRECTED_HEADER, "redirected header"},
137146773Ssam   { ND_OPT_MTU, "mtu"},
138214478Srpaulo   { ND_OPT_RDNSS, "rdnss"},
139162017Ssam   { ND_OPT_ADVINTERVAL, "advertisement interval"},
140146773Ssam   { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
141146773Ssam   { ND_OPT_ROUTE_INFO, "route info"},
142146773Ssam   { 0,	NULL }
143146773Ssam};
144146773Ssam
145146773Ssam/* mldv2 report types */
146146773Ssamstatic struct tok mldv2report2str[] = {
147146773Ssam	{ 1,	"is_in" },
148146773Ssam	{ 2,	"is_ex" },
149146773Ssam	{ 3,	"to_in" },
150146773Ssam	{ 4,	"to_ex" },
151146773Ssam	{ 5,	"allow" },
152146773Ssam	{ 6,	"block" },
153146773Ssam	{ 0,	NULL }
154146773Ssam};
155146773Ssam
15698524Sfennerstatic const char *
15798524Sfennerget_rtpref(u_int v)
15898524Sfenner{
15998524Sfenner	static const char *rtpref_str[] = {
16098524Sfenner		"medium",		/* 00 */
16198524Sfenner		"high",			/* 01 */
16298524Sfenner		"rsv",			/* 10 */
16398524Sfenner		"low"			/* 11 */
16498524Sfenner	};
16598524Sfenner
16698524Sfenner	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
16798524Sfenner}
16898524Sfenner
16998524Sfennerstatic const char *
17098524Sfennerget_lifetime(u_int32_t v)
17198524Sfenner{
17298524Sfenner	static char buf[20];
17398524Sfenner
17498524Sfenner	if (v == (u_int32_t)~0UL)
17598524Sfenner		return "infinity";
17698524Sfenner	else {
17798524Sfenner		snprintf(buf, sizeof(buf), "%u", v);
17898524Sfenner		return buf;
17998524Sfenner	}
18098524Sfenner}
18198524Sfenner
18298524Sfennerstatic void
18398524Sfennerprint_lladdr(const u_int8_t *p, size_t l)
18498524Sfenner{
18598524Sfenner	const u_int8_t *ep, *q;
18698524Sfenner
18798524Sfenner	q = p;
18898524Sfenner	ep = p + l;
18998524Sfenner	while (l > 0 && q < ep) {
19098524Sfenner		if (q > p)
19198524Sfenner			printf(":");
19298524Sfenner		printf("%02x", *q++);
19398524Sfenner		l--;
19498524Sfenner	}
19598524Sfenner}
19698524Sfenner
197127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
198127668Sbms	u_int len)
199127668Sbms{
200127668Sbms	size_t i;
201127668Sbms	register const u_int16_t *sp;
202127668Sbms	u_int32_t sum;
203127668Sbms	union {
204127668Sbms		struct {
205127668Sbms			struct in6_addr ph_src;
206127668Sbms			struct in6_addr ph_dst;
207127668Sbms			u_int32_t	ph_len;
208127668Sbms			u_int8_t	ph_zero[3];
209127668Sbms			u_int8_t	ph_nxt;
210127668Sbms		} ph;
211127668Sbms		u_int16_t pa[20];
212127668Sbms	} phu;
213127668Sbms
214127668Sbms	/* pseudo-header */
215127668Sbms	memset(&phu, 0, sizeof(phu));
216127668Sbms	phu.ph.ph_src = ip6->ip6_src;
217127668Sbms	phu.ph.ph_dst = ip6->ip6_dst;
218127668Sbms	phu.ph.ph_len = htonl(len);
219127668Sbms	phu.ph.ph_nxt = IPPROTO_ICMPV6;
220127668Sbms
221127668Sbms	sum = 0;
222127668Sbms	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
223127668Sbms		sum += phu.pa[i];
224127668Sbms
225127668Sbms	sp = (const u_int16_t *)icp;
226127668Sbms
227127668Sbms	for (i = 0; i < (len & ~1); i += 2)
228127668Sbms		sum += *sp++;
229127668Sbms
230127668Sbms	if (len & 1)
231127668Sbms		sum += htons((*(const u_int8_t *)sp) << 8);
232127668Sbms
233127668Sbms	while (sum > 0xffff)
234127668Sbms		sum = (sum & 0xffff) + (sum >> 16);
235127668Sbms	sum = ~sum & 0xffff;
236127668Sbms
237127668Sbms	return (sum);
238127668Sbms}
239127668Sbms
240214478Srpauloenum ND_RPL_CODE {
241214478Srpaulo        ND_RPL_DAG_IS=0x01,
242214478Srpaulo        ND_RPL_DAG_IO=0x02,
243214478Srpaulo        ND_RPL_DAO   =0x04
244214478Srpaulo};
245214478Srpaulo
246214478Srpauloenum ND_RPL_DIO_FLAGS {
247214478Srpaulo        ND_RPL_DIO_GROUNDED = 0x80,
248214478Srpaulo        ND_RPL_DIO_DATRIG   = 0x40,
249214478Srpaulo        ND_RPL_DIO_DASUPPORT= 0x20,
250214478Srpaulo        ND_RPL_DIO_RES4     = 0x10,
251214478Srpaulo        ND_RPL_DIO_RES3     = 0x08,
252214478Srpaulo        ND_RPL_DIO_PRF_MASK = 0x07,  /* 3-bit preference */
253214478Srpaulo};
254214478Srpaulo
255214478Srpaulostruct nd_rpl_dio {
256214478Srpaulo        u_int8_t rpl_flags;
257214478Srpaulo        u_int8_t rpl_seq;
258214478Srpaulo        u_int8_t rpl_instanceid;
259214478Srpaulo        u_int8_t rpl_dagrank;
260214478Srpaulo        u_int8_t rpl_dagid[16];
261214478Srpaulo};
262214478Srpaulo
263214478Srpaulostatic void
264214478Srpaulorpl_print(netdissect_options *ndo,
265214478Srpaulo          const struct icmp6_hdr *hdr,
266214478Srpaulo          const u_char *bp, u_int length _U_)
267214478Srpaulo{
268214478Srpaulo        struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp;
269214478Srpaulo
270214478Srpaulo        ND_TCHECK(dio->rpl_dagid);
271214478Srpaulo
272214478Srpaulo        switch(hdr->icmp6_code) {
273214478Srpaulo        case ND_RPL_DAG_IS:
274214478Srpaulo                ND_PRINT((ndo, ", DAG Information Solicitation"));
275214478Srpaulo                if(ndo->ndo_vflag) {
276214478Srpaulo                }
277214478Srpaulo                break;
278214478Srpaulo        case ND_RPL_DAG_IO:
279214478Srpaulo                ND_PRINT((ndo, ", DAG Information Object"));
280214478Srpaulo                if(ndo->ndo_vflag) {
281214478Srpaulo                        char dagid[65];
282214478Srpaulo                        char *d = dagid;
283214478Srpaulo                        int  i;
284214478Srpaulo                        for(i=0;i<16;i++) {
285214478Srpaulo                                if(isprint(dio->rpl_dagid[i])) {
286214478Srpaulo                                        *d++ = dio->rpl_dagid[i];
287214478Srpaulo                                } else {
288214478Srpaulo                                        int cnt=snprintf(d,4,"0x%02x",
289214478Srpaulo                                                         dio->rpl_dagid[i]);
290214478Srpaulo                                        d += cnt;
291214478Srpaulo                                }
292214478Srpaulo                        }
293214478Srpaulo                        *d++ = '\0';
294214478Srpaulo                        ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]",
295214478Srpaulo                                  dio->rpl_seq,
296214478Srpaulo                                  dio->rpl_instanceid,
297214478Srpaulo                                  dio->rpl_dagrank,
298214478Srpaulo                                  dagid));
299214478Srpaulo                }
300214478Srpaulo                break;
301214478Srpaulo        case ND_RPL_DAO:
302214478Srpaulo                ND_PRINT((ndo, ", Destination Advertisement Object"));
303214478Srpaulo                if(ndo->ndo_vflag) {
304214478Srpaulo                }
305214478Srpaulo                break;
306214478Srpaulo        default:
307214478Srpaulo                ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code));
308214478Srpaulo                break;
309214478Srpaulo        }
310214478Srpaulo	return;
311214478Srpaulotrunc:
312214478Srpaulo	ND_PRINT((ndo," [|truncated]"));
313214478Srpaulo	return;
314214478Srpaulo
315214478Srpaulo}
316214478Srpaulo
317214478Srpaulo
31856893Sfennervoid
319214478Srpauloicmp6_print(netdissect_options *ndo,
320214478Srpaulo            const u_char *bp, u_int length, const u_char *bp2, int fragmented)
32156893Sfenner{
32275115Sfenner	const struct icmp6_hdr *dp;
32398524Sfenner	const struct ip6_hdr *ip;
32498524Sfenner	const struct ip6_hdr *oip;
32598524Sfenner	const struct udphdr *ouh;
32698524Sfenner	int dport;
32798524Sfenner	const u_char *ep;
328127668Sbms	u_int prot;
32956893Sfenner
33056893Sfenner	dp = (struct icmp6_hdr *)bp;
33156893Sfenner	ip = (struct ip6_hdr *)bp2;
33256893Sfenner	oip = (struct ip6_hdr *)(dp + 1);
33375115Sfenner	/* 'ep' points to the end of available data. */
33456893Sfenner	ep = snapend;
33556893Sfenner
336127668Sbms	TCHECK(dp->icmp6_cksum);
337127668Sbms
338127668Sbms	if (vflag && !fragmented) {
339127668Sbms		int sum = dp->icmp6_cksum;
340127668Sbms
341127668Sbms		if (TTEST2(bp[0], length)) {
342127668Sbms			sum = icmp6_cksum(ip, dp, length);
343127668Sbms			if (sum != 0)
344127668Sbms				(void)printf("[bad icmp6 cksum %x!] ", sum);
345127668Sbms			else
346127668Sbms				(void)printf("[icmp6 sum ok] ");
347127668Sbms		}
348127668Sbms	}
349127668Sbms
350146773Ssam        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
351146773Ssam
352146773Ssam        /* display cosmetics: print the packet length for printer that use the vflag now */
353229244Sdim        if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT ||
354229244Sdim                      dp->icmp6_type == ND_ROUTER_ADVERT ||
355229244Sdim                      dp->icmp6_type == ND_NEIGHBOR_ADVERT ||
356229244Sdim                      dp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
357229244Sdim                      dp->icmp6_type == ND_REDIRECT ||
358229244Sdim                      dp->icmp6_type == ICMP6_HADISCOV_REPLY ||
359229244Sdim                      dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
360146773Ssam            printf(", length %u", length);
361146773Ssam
36275115Sfenner	switch (dp->icmp6_type) {
36356893Sfenner	case ICMP6_DST_UNREACH:
36456893Sfenner		TCHECK(oip->ip6_dst);
365146773Ssam                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
36656893Sfenner		switch (dp->icmp6_code) {
367146773Ssam
368146773Ssam		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
36956893Sfenner		case ICMP6_DST_UNREACH_ADMIN:
370146773Ssam		case ICMP6_DST_UNREACH_ADDR:
371146773Ssam                        printf(" %s",ip6addr_string(&oip->ip6_dst));
372146773Ssam                        break;
37356893Sfenner		case ICMP6_DST_UNREACH_BEYONDSCOPE:
374146773Ssam			printf(" %s, source address %s",
37556893Sfenner			       ip6addr_string(&oip->ip6_dst),
37656893Sfenner			       ip6addr_string(&oip->ip6_src));
37756893Sfenner			break;
37856893Sfenner		case ICMP6_DST_UNREACH_NOPORT:
37975115Sfenner			if ((ouh = get_upperlayer((u_char *)oip, &prot))
38075115Sfenner			    == NULL)
38175115Sfenner				goto trunc;
38275115Sfenner
383127668Sbms			dport = EXTRACT_16BITS(&ouh->uh_dport);
38475115Sfenner			switch (prot) {
38556893Sfenner			case IPPROTO_TCP:
386146773Ssam				printf(", %s tcp port %s",
38756893Sfenner					ip6addr_string(&oip->ip6_dst),
38856893Sfenner					tcpport_string(dport));
38956893Sfenner				break;
39056893Sfenner			case IPPROTO_UDP:
391146773Ssam				printf(", %s udp port %s",
39256893Sfenner					ip6addr_string(&oip->ip6_dst),
39356893Sfenner					udpport_string(dport));
39456893Sfenner				break;
39556893Sfenner			default:
396146773Ssam				printf(", %s protocol %d port %d unreachable",
39756893Sfenner					ip6addr_string(&oip->ip6_dst),
39856893Sfenner					oip->ip6_nxt, dport);
39956893Sfenner				break;
40056893Sfenner			}
40156893Sfenner			break;
40256893Sfenner		default:
403146773Ssam                    if (vflag <= 1) {
404146773Ssam                            print_unknown_data(bp,"\n\t",length);
405146773Ssam                            return;
406146773Ssam                    }
407146773Ssam                    break;
40856893Sfenner		}
40956893Sfenner		break;
41056893Sfenner	case ICMP6_PACKET_TOO_BIG:
41156893Sfenner		TCHECK(dp->icmp6_mtu);
412146773Ssam		printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
41356893Sfenner		break;
41456893Sfenner	case ICMP6_TIME_EXCEEDED:
41556893Sfenner		TCHECK(oip->ip6_dst);
41656893Sfenner		switch (dp->icmp6_code) {
41756893Sfenner		case ICMP6_TIME_EXCEED_TRANSIT:
418146773Ssam			printf(" for %s",
41956893Sfenner				ip6addr_string(&oip->ip6_dst));
42056893Sfenner			break;
42156893Sfenner		case ICMP6_TIME_EXCEED_REASSEMBLY:
422146773Ssam			printf(" (reassembly)");
42356893Sfenner			break;
42456893Sfenner		default:
425146773Ssam			printf(", unknown code (%u)", dp->icmp6_code);
42656893Sfenner			break;
42756893Sfenner		}
42856893Sfenner		break;
42956893Sfenner	case ICMP6_PARAM_PROB:
43056893Sfenner		TCHECK(oip->ip6_dst);
43156893Sfenner		switch (dp->icmp6_code) {
43256893Sfenner		case ICMP6_PARAMPROB_HEADER:
433146773Ssam			printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
43456893Sfenner			break;
43556893Sfenner		case ICMP6_PARAMPROB_NEXTHEADER:
436146773Ssam			printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
43756893Sfenner			break;
43856893Sfenner		case ICMP6_PARAMPROB_OPTION:
439146773Ssam			printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
44056893Sfenner			break;
44156893Sfenner		default:
442146773Ssam			printf(", code-#%d",
44356893Sfenner			       dp->icmp6_code);
44456893Sfenner			break;
44556893Sfenner		}
44656893Sfenner		break;
44756893Sfenner	case ICMP6_ECHO_REQUEST:
44856893Sfenner	case ICMP6_ECHO_REPLY:
449127668Sbms		TCHECK(dp->icmp6_seq);
450146773Ssam		printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
45156893Sfenner		break;
45256893Sfenner	case ICMP6_MEMBERSHIP_QUERY:
453146773Ssam		if (length == MLD_MINLEN) {
454146773Ssam			mld6_print((const u_char *)dp);
455146773Ssam		} else if (length >= MLDV2_MINLEN) {
456146773Ssam			printf("v2 ");
457146773Ssam			mldv2_query_print((const u_char *)dp, length);
458146773Ssam		} else {
459146773Ssam			printf(" unknown-version (len %u) ", length);
460146773Ssam		}
46156893Sfenner		break;
46256893Sfenner	case ICMP6_MEMBERSHIP_REPORT:
46356893Sfenner		mld6_print((const u_char *)dp);
46456893Sfenner		break;
46556893Sfenner	case ICMP6_MEMBERSHIP_REDUCTION:
46656893Sfenner		mld6_print((const u_char *)dp);
46756893Sfenner		break;
46856893Sfenner	case ND_ROUTER_SOLICIT:
469146773Ssam#define RTSOLLEN 8
47056893Sfenner		if (vflag) {
47175115Sfenner			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
472127668Sbms					length - RTSOLLEN);
47356893Sfenner		}
47456893Sfenner		break;
47556893Sfenner	case ND_ROUTER_ADVERT:
476146773Ssam#define RTADVLEN 16
47756893Sfenner		if (vflag) {
47856893Sfenner			struct nd_router_advert *p;
47956893Sfenner
48056893Sfenner			p = (struct nd_router_advert *)dp;
48156893Sfenner			TCHECK(p->nd_ra_retransmit);
482146773Ssam			printf("\n\thop limit %u, Flags [%s]" \
483146773Ssam                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
484146773Ssam                               (u_int)p->nd_ra_curhoplimit,
485146773Ssam                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
486146773Ssam                               get_rtpref(p->nd_ra_flags_reserved),
487146773Ssam                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
488146773Ssam                               EXTRACT_32BITS(&p->nd_ra_reachable),
489146773Ssam                               EXTRACT_32BITS(&p->nd_ra_retransmit));
49098524Sfenner
49175115Sfenner			icmp6_opt_print((const u_char *)dp + RTADVLEN,
492127668Sbms					length - RTADVLEN);
49356893Sfenner		}
49456893Sfenner		break;
49556893Sfenner	case ND_NEIGHBOR_SOLICIT:
49656893Sfenner	    {
49756893Sfenner		struct nd_neighbor_solicit *p;
49856893Sfenner		p = (struct nd_neighbor_solicit *)dp;
49956893Sfenner		TCHECK(p->nd_ns_target);
500146773Ssam		printf(", who has %s", ip6addr_string(&p->nd_ns_target));
50156893Sfenner		if (vflag) {
50256893Sfenner#define NDSOLLEN 24
50375115Sfenner			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
504127668Sbms					length - NDSOLLEN);
50556893Sfenner		}
50656893Sfenner	    }
50756893Sfenner		break;
50856893Sfenner	case ND_NEIGHBOR_ADVERT:
50956893Sfenner	    {
51056893Sfenner		struct nd_neighbor_advert *p;
51156893Sfenner
51256893Sfenner		p = (struct nd_neighbor_advert *)dp;
51356893Sfenner		TCHECK(p->nd_na_target);
514146773Ssam		printf(", tgt is %s",
51556893Sfenner			ip6addr_string(&p->nd_na_target));
51675115Sfenner		if (vflag) {
517146773Ssam                        printf(", Flags [%s]",
518146773Ssam                               bittok2str(icmp6_nd_na_flag_values,
519146773Ssam                                          "none",
520146773Ssam                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
52156893Sfenner#define NDADVLEN 24
52275115Sfenner			icmp6_opt_print((const u_char *)dp + NDADVLEN,
523127668Sbms					length - NDADVLEN);
52475115Sfenner#undef NDADVLEN
52556893Sfenner		}
52656893Sfenner	    }
52756893Sfenner		break;
52856893Sfenner	case ND_REDIRECT:
52956893Sfenner#define RDR(i) ((struct nd_redirect *)(i))
53056893Sfenner		TCHECK(RDR(dp)->nd_rd_dst);
531146773Ssam		printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
532127668Sbms		TCHECK(RDR(dp)->nd_rd_target);
53375115Sfenner		printf(" to %s",
53475115Sfenner		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
53556893Sfenner#define REDIRECTLEN 40
53656893Sfenner		if (vflag) {
53756893Sfenner			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
538127668Sbms					length - REDIRECTLEN);
53956893Sfenner		}
54056893Sfenner		break;
54175115Sfenner#undef REDIRECTLEN
54275115Sfenner#undef RDR
54356893Sfenner	case ICMP6_ROUTER_RENUMBERING:
544127668Sbms		icmp6_rrenum_print(bp, ep);
54556893Sfenner		break;
54675115Sfenner	case ICMP6_NI_QUERY:
54775115Sfenner	case ICMP6_NI_REPLY:
548127668Sbms		icmp6_nodeinfo_print(length, bp, ep);
54956893Sfenner		break;
550146773Ssam	case IND_SOLICIT:
551146773Ssam	case IND_ADVERT:
552146773Ssam		break;
553146773Ssam	case ICMP6_V2_MEMBERSHIP_REPORT:
554146773Ssam		mldv2_report_print((const u_char *) dp, length);
555146773Ssam		break;
556146773Ssam	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
557127668Sbms	case ICMP6_HADISCOV_REQUEST:
558146773Ssam                TCHECK(dp->icmp6_data16[0]);
559146773Ssam                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
560146773Ssam                break;
561127668Sbms	case ICMP6_HADISCOV_REPLY:
562127668Sbms		if (vflag) {
563127668Sbms			struct in6_addr *in6;
564127668Sbms			u_char *cp;
565127668Sbms
566127668Sbms			TCHECK(dp->icmp6_data16[0]);
567146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
568127668Sbms			cp = (u_char *)dp + length;
569127668Sbms			in6 = (struct in6_addr *)(dp + 1);
570127668Sbms			for (; (u_char *)in6 < cp; in6++) {
571127668Sbms				TCHECK(*in6);
572127668Sbms				printf(", %s", ip6addr_string(in6));
573127668Sbms			}
574127668Sbms		}
575127668Sbms		break;
576127668Sbms	case ICMP6_MOBILEPREFIX_ADVERT:
577127668Sbms		if (vflag) {
578127668Sbms			TCHECK(dp->icmp6_data16[0]);
579146773Ssam			printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
580127668Sbms			if (dp->icmp6_data16[1] & 0xc0)
581127668Sbms				printf(" ");
582127668Sbms			if (dp->icmp6_data16[1] & 0x80)
583127668Sbms				printf("M");
584127668Sbms			if (dp->icmp6_data16[1] & 0x40)
585127668Sbms				printf("O");
586127668Sbms#define MPADVLEN 8
587127668Sbms			icmp6_opt_print((const u_char *)dp + MPADVLEN,
588127668Sbms					length - MPADVLEN);
589127668Sbms		}
590127668Sbms		break;
591214478Srpaulo        case ND_RPL_MESSAGE:
592214478Srpaulo                rpl_print(ndo, dp, &dp->icmp6_data8[0], length);
593214478Srpaulo                break;
59456893Sfenner	default:
595146773Ssam                printf(", length %u", length);
596146773Ssam                if (vflag <= 1)
597146773Ssam                    print_unknown_data(bp,"\n\t", length);
598146773Ssam                return;
599146773Ssam        }
600146773Ssam        if (!vflag)
601146773Ssam            printf(", length %u", length);
60256893Sfenner	return;
60356893Sfennertrunc:
60456893Sfenner	fputs("[|icmp6]", stdout);
60556893Sfenner}
60656893Sfenner
60775115Sfennerstatic struct udphdr *
608127668Sbmsget_upperlayer(u_char *bp, u_int *prot)
60975115Sfenner{
61098524Sfenner	const u_char *ep;
61175115Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
61275115Sfenner	struct udphdr *uh;
61375115Sfenner	struct ip6_hbh *hbh;
61475115Sfenner	struct ip6_frag *fragh;
61575115Sfenner	struct ah *ah;
616127668Sbms	u_int nh;
617127668Sbms	int hlen;
61875115Sfenner
61975115Sfenner	/* 'ep' points to the end of available data. */
62075115Sfenner	ep = snapend;
62175115Sfenner
622127668Sbms	if (!TTEST(ip6->ip6_nxt))
62375115Sfenner		return NULL;
62475115Sfenner
62575115Sfenner	nh = ip6->ip6_nxt;
62675115Sfenner	hlen = sizeof(struct ip6_hdr);
62775115Sfenner
628147899Ssam	while (bp < ep) {
62975115Sfenner		bp += hlen;
63075115Sfenner
63175115Sfenner		switch(nh) {
63275115Sfenner		case IPPROTO_UDP:
63375115Sfenner		case IPPROTO_TCP:
63475115Sfenner			uh = (struct udphdr *)bp;
63575115Sfenner			if (TTEST(uh->uh_dport)) {
63675115Sfenner				*prot = nh;
63775115Sfenner				return(uh);
63875115Sfenner			}
63975115Sfenner			else
64075115Sfenner				return(NULL);
64175115Sfenner			/* NOTREACHED */
64275115Sfenner
64375115Sfenner		case IPPROTO_HOPOPTS:
64475115Sfenner		case IPPROTO_DSTOPTS:
64575115Sfenner		case IPPROTO_ROUTING:
64675115Sfenner			hbh = (struct ip6_hbh *)bp;
647127668Sbms			if (!TTEST(hbh->ip6h_len))
64875115Sfenner				return(NULL);
64975115Sfenner			nh = hbh->ip6h_nxt;
65075115Sfenner			hlen = (hbh->ip6h_len + 1) << 3;
65175115Sfenner			break;
65275115Sfenner
65375115Sfenner		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
65475115Sfenner			fragh = (struct ip6_frag *)bp;
655127668Sbms			if (!TTEST(fragh->ip6f_offlg))
65675115Sfenner				return(NULL);
65775115Sfenner			/* fragments with non-zero offset are meaningless */
658127668Sbms			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
65975115Sfenner				return(NULL);
66075115Sfenner			nh = fragh->ip6f_nxt;
66175115Sfenner			hlen = sizeof(struct ip6_frag);
66275115Sfenner			break;
66375115Sfenner
66475115Sfenner		case IPPROTO_AH:
66575115Sfenner			ah = (struct ah *)bp;
666127668Sbms			if (!TTEST(ah->ah_len))
66775115Sfenner				return(NULL);
66875115Sfenner			nh = ah->ah_nxt;
66975115Sfenner			hlen = (ah->ah_len + 2) << 2;
67075115Sfenner			break;
67175115Sfenner
67275115Sfenner		default:	/* unknown or undecodable header */
67375115Sfenner			*prot = nh; /* meaningless, but set here anyway */
67475115Sfenner			return(NULL);
67575115Sfenner		}
67675115Sfenner	}
67775115Sfenner
67875115Sfenner	return(NULL);		/* should be notreached, though */
67975115Sfenner}
68075115Sfenner
681127668Sbmsstatic void
68298524Sfennericmp6_opt_print(const u_char *bp, int resid)
68356893Sfenner{
68498524Sfenner	const struct nd_opt_hdr *op;
68598524Sfenner	const struct nd_opt_hdr *opl;	/* why there's no struct? */
68698524Sfenner	const struct nd_opt_prefix_info *opp;
68798524Sfenner	const struct icmp6_opts_redirect *opr;
68898524Sfenner	const struct nd_opt_mtu *opm;
689214478Srpaulo	const struct nd_opt_rdnss *oprd;
69098524Sfenner	const struct nd_opt_advinterval *opa;
691127668Sbms	const struct nd_opt_homeagent_info *oph;
69298524Sfenner	const struct nd_opt_route_info *opri;
69398524Sfenner	const u_char *cp, *ep;
69498524Sfenner	struct in6_addr in6, *in6p;
69598524Sfenner	size_t l;
696214478Srpaulo	u_int i;
69756893Sfenner
69856893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
69956893Sfenner
70098524Sfenner	cp = bp;
70175115Sfenner	/* 'ep' points to the end of available data. */
70256893Sfenner	ep = snapend;
70356893Sfenner
70498524Sfenner	while (cp < ep) {
70598524Sfenner		op = (struct nd_opt_hdr *)cp;
70698524Sfenner
70798524Sfenner		ECHECK(op->nd_opt_len);
70898524Sfenner		if (resid <= 0)
70998524Sfenner			return;
71098524Sfenner		if (op->nd_opt_len == 0)
71156893Sfenner			goto trunc;
71298524Sfenner		if (cp + (op->nd_opt_len << 3) > ep)
71356893Sfenner			goto trunc;
71498524Sfenner
715146773Ssam                printf("\n\t  %s option (%u), length %u (%u): ",
716146773Ssam                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
717146773Ssam                       op->nd_opt_type,
718146773Ssam                       op->nd_opt_len << 3,
719146773Ssam                       op->nd_opt_len);
720146773Ssam
72198524Sfenner		switch (op->nd_opt_type) {
72298524Sfenner		case ND_OPT_SOURCE_LINKADDR:
72398524Sfenner			opl = (struct nd_opt_hdr *)op;
72498524Sfenner			l = (op->nd_opt_len << 3) - 2;
72598524Sfenner			print_lladdr(cp + 2, l);
72698524Sfenner			break;
72798524Sfenner		case ND_OPT_TARGET_LINKADDR:
72898524Sfenner			opl = (struct nd_opt_hdr *)op;
72998524Sfenner			l = (op->nd_opt_len << 3) - 2;
73098524Sfenner			print_lladdr(cp + 2, l);
73198524Sfenner			break;
73298524Sfenner		case ND_OPT_PREFIX_INFORMATION:
73398524Sfenner			opp = (struct nd_opt_prefix_info *)op;
73498524Sfenner			TCHECK(opp->nd_opt_pi_prefix);
735146773Ssam                        printf("%s/%u%s, Flags [%s], valid time %ss",
736146773Ssam                               ip6addr_string(&opp->nd_opt_pi_prefix),
737146773Ssam                               opp->nd_opt_pi_prefix_len,
738146773Ssam                               (op->nd_opt_len != 4) ? "badlen" : "",
739146773Ssam                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
740146773Ssam                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
741146773Ssam                        printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
74298524Sfenner			break;
74398524Sfenner		case ND_OPT_REDIRECTED_HEADER:
74498524Sfenner			opr = (struct icmp6_opts_redirect *)op;
745146773Ssam                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
74698524Sfenner			/* xxx */
74798524Sfenner			break;
74898524Sfenner		case ND_OPT_MTU:
74998524Sfenner			opm = (struct nd_opt_mtu *)op;
75098524Sfenner			TCHECK(opm->nd_opt_mtu_mtu);
751146773Ssam			printf(" %u%s",
752146773Ssam                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
753146773Ssam                               (op->nd_opt_len != 1) ? "bad option length" : "" );
754146773Ssam                        break;
755214478Srpaulo		case ND_OPT_RDNSS:
756214478Srpaulo			oprd = (struct nd_opt_rdnss *)op;
757214478Srpaulo			l = (op->nd_opt_len - 1) / 2;
758214478Srpaulo			printf(" lifetime %us,",
759214478Srpaulo				EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime));
760214478Srpaulo			for (i = 0; i < l; i++) {
761214478Srpaulo				TCHECK(oprd->nd_opt_rdnss_addr[i]);
762214478Srpaulo				printf(" addr: %s",
763214478Srpaulo				    ip6addr_string(&oprd->nd_opt_rdnss_addr[i]));
764214478Srpaulo			}
765214478Srpaulo			break;
76698524Sfenner		case ND_OPT_ADVINTERVAL:
76798524Sfenner			opa = (struct nd_opt_advinterval *)op;
76898524Sfenner			TCHECK(opa->nd_opt_adv_interval);
769146773Ssam			printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
770127668Sbms			break;
771127668Sbms		case ND_OPT_HOMEAGENT_INFO:
772127668Sbms			oph = (struct nd_opt_homeagent_info *)op;
773127668Sbms			TCHECK(oph->nd_opt_hai_lifetime);
774146773Ssam			printf(" preference %u, lifetime %u",
775146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
776146773Ssam                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
777127668Sbms			break;
77898524Sfenner		case ND_OPT_ROUTE_INFO:
77998524Sfenner			opri = (struct nd_opt_route_info *)op;
78098524Sfenner			TCHECK(opri->nd_opt_rti_lifetime);
78198524Sfenner			memset(&in6, 0, sizeof(in6));
78298524Sfenner			in6p = (struct in6_addr *)(opri + 1);
78398524Sfenner			switch (op->nd_opt_len) {
78498524Sfenner			case 1:
78598524Sfenner				break;
78698524Sfenner			case 2:
78798524Sfenner				TCHECK2(*in6p, 8);
78898524Sfenner				memcpy(&in6, opri + 1, 8);
78998524Sfenner				break;
79098524Sfenner			case 3:
79198524Sfenner				TCHECK(*in6p);
79298524Sfenner				memcpy(&in6, opri + 1, sizeof(in6));
79398524Sfenner				break;
79498524Sfenner			default:
79598524Sfenner				goto trunc;
79698524Sfenner			}
79798524Sfenner			printf(" %s/%u", ip6addr_string(&in6),
79898524Sfenner			    opri->nd_opt_rti_prefixlen);
79998524Sfenner			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
80098524Sfenner			printf(", lifetime=%s",
801127668Sbms			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
80298524Sfenner			break;
80398524Sfenner		default:
804146773Ssam                        if (vflag <= 1) {
805146773Ssam                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
806146773Ssam                            return;
807146773Ssam                        }
808146773Ssam                        break;
80956893Sfenner		}
810146773Ssam                /* do we want to see an additional hexdump ? */
811146773Ssam                if (vflag> 1)
812146773Ssam                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
81398524Sfenner
81498524Sfenner		cp += op->nd_opt_len << 3;
81598524Sfenner		resid -= op->nd_opt_len << 3;
81656893Sfenner	}
81756893Sfenner	return;
81898524Sfenner
81956893Sfenner trunc:
82056893Sfenner	fputs("[ndp opt]", stdout);
82156893Sfenner	return;
82256893Sfenner#undef ECHECK
82356893Sfenner}
82456893Sfenner
825127668Sbmsstatic void
82698524Sfennermld6_print(const u_char *bp)
82756893Sfenner{
82898524Sfenner	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
82998524Sfenner	const u_char *ep;
83056893Sfenner
83175115Sfenner	/* 'ep' points to the end of available data. */
83256893Sfenner	ep = snapend;
83356893Sfenner
83456893Sfenner	if ((u_char *)mp + sizeof(*mp) > ep)
83556893Sfenner		return;
83656893Sfenner
837127668Sbms	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
83856893Sfenner	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
83975115Sfenner}
84056893Sfenner
84175115Sfennerstatic void
842146773Ssammldv2_report_print(const u_char *bp, u_int len)
843146773Ssam{
844146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
845146773Ssam    u_int group, nsrcs, ngroups;
846146773Ssam    u_int i, j;
847146773Ssam
848146773Ssam    /* Minimum len is 8 */
849146773Ssam    if (len < 8) {
850146773Ssam	printf(" [invalid len %d]", len);
851146773Ssam	return;
852146773Ssam    }
853146773Ssam
854146773Ssam    TCHECK(icp->icmp6_data16[1]);
855214478Srpaulo    ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
856146773Ssam    printf(", %d group record(s)", ngroups);
857146773Ssam    if (vflag > 0) {
858146773Ssam	/* Print the group records */
859146773Ssam	group = 8;
860146773Ssam        for (i = 0; i < ngroups; i++) {
861146773Ssam	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
862146773Ssam	    if (len < group + 20) {
863146773Ssam		printf(" [invalid number of groups]");
864146773Ssam		return;
865146773Ssam	    }
866162017Ssam            TCHECK2(bp[group + 4], sizeof(struct in6_addr));
867146773Ssam            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
868146773Ssam	    printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
869146773Ssam								bp[group]));
870146773Ssam            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
871146773Ssam	    /* Check the number of sources and print them */
872162017Ssam	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
873146773Ssam		printf(" [invalid number of sources %d]", nsrcs);
874146773Ssam		return;
875146773Ssam	    }
876146773Ssam            if (vflag == 1)
877146773Ssam                printf(", %d source(s)", nsrcs);
878146773Ssam            else {
879146773Ssam		/* Print the sources */
880146773Ssam                (void)printf(" {");
881146773Ssam                for (j = 0; j < nsrcs; j++) {
882162017Ssam                    TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
883162017Ssam                            sizeof(struct in6_addr));
884162017Ssam		    printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)]));
885146773Ssam		}
886146773Ssam                (void)printf(" }");
887146773Ssam            }
888146773Ssam	    /* Next group record */
889162017Ssam            group += 20 + nsrcs * sizeof(struct in6_addr);
890146773Ssam	    printf("]");
891146773Ssam        }
892146773Ssam    }
893146773Ssam    return;
894146773Ssamtrunc:
895146773Ssam    (void)printf("[|icmp6]");
896146773Ssam    return;
897146773Ssam}
898146773Ssam
899146773Ssamstatic void
900146773Ssammldv2_query_print(const u_char *bp, u_int len)
901146773Ssam{
902146773Ssam    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
903146773Ssam    u_int mrc;
904146773Ssam    int mrt, qqi;
905146773Ssam    u_int nsrcs;
906146773Ssam    register u_int i;
907146773Ssam
908146773Ssam    /* Minimum len is 28 */
909146773Ssam    if (len < 28) {
910146773Ssam	printf(" [invalid len %d]", len);
911146773Ssam	return;
912146773Ssam    }
913146773Ssam    TCHECK(icp->icmp6_data16[0]);
914214478Srpaulo    mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
915146773Ssam    if (mrc < 32768) {
916146773Ssam	mrt = mrc;
917146773Ssam    } else {
918146773Ssam        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
919146773Ssam    }
920146773Ssam    if (vflag) {
921146773Ssam	(void)printf(" [max resp delay=%d]", mrt);
922146773Ssam    }
923162017Ssam    TCHECK2(bp[8], sizeof(struct in6_addr));
924146773Ssam    printf(" [gaddr %s", ip6addr_string(&bp[8]));
925146773Ssam
926146773Ssam    if (vflag) {
927146773Ssam        TCHECK(bp[25]);
928146773Ssam	if (bp[24] & 0x08) {
929146773Ssam		printf(" sflag");
930146773Ssam	}
931146773Ssam	if (bp[24] & 0x07) {
932146773Ssam		printf(" robustness=%d", bp[24] & 0x07);
933146773Ssam	}
934146773Ssam	if (bp[25] < 128) {
935146773Ssam		qqi = bp[25];
936146773Ssam	} else {
937146773Ssam		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
938146773Ssam	}
939146773Ssam	printf(" qqi=%d", qqi);
940146773Ssam    }
941146773Ssam
942146773Ssam    TCHECK2(bp[26], 2);
943214478Srpaulo    nsrcs = EXTRACT_16BITS(&bp[26]);
944146773Ssam    if (nsrcs > 0) {
945162017Ssam	if (len < 28 + nsrcs * sizeof(struct in6_addr))
946146773Ssam	    printf(" [invalid number of sources]");
947146773Ssam	else if (vflag > 1) {
948146773Ssam	    printf(" {");
949146773Ssam	    for (i = 0; i < nsrcs; i++) {
950162017Ssam		TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
951162017Ssam                        sizeof(struct in6_addr));
952162017Ssam		printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)]));
953146773Ssam	    }
954146773Ssam	    printf(" }");
955146773Ssam	} else
956146773Ssam	    printf(", %d source(s)", nsrcs);
957146773Ssam    }
958146773Ssam    printf("]");
959146773Ssam    return;
960146773Ssamtrunc:
961146773Ssam    (void)printf("[|icmp6]");
962146773Ssam    return;
963146773Ssam}
964146773Ssam
965214478Srpaulostatic void
96675115Sfennerdnsname_print(const u_char *cp, const u_char *ep)
96775115Sfenner{
96875115Sfenner	int i;
96975115Sfenner
97075115Sfenner	/* DNS name decoding - no decompression */
97175115Sfenner	printf(", \"");
97275115Sfenner	while (cp < ep) {
97375115Sfenner		i = *cp++;
97475115Sfenner		if (i) {
97575115Sfenner			if (i > ep - cp) {
97675115Sfenner				printf("???");
97775115Sfenner				break;
97875115Sfenner			}
97975115Sfenner			while (i-- && cp < ep) {
98075115Sfenner				safeputchar(*cp);
98175115Sfenner				cp++;
98275115Sfenner			}
98375115Sfenner			if (cp + 1 < ep && *cp)
98475115Sfenner				printf(".");
98575115Sfenner		} else {
98675115Sfenner			if (cp == ep) {
98775115Sfenner				/* FQDN */
98875115Sfenner				printf(".");
98975115Sfenner			} else if (cp + 1 == ep && *cp == '\0') {
99075115Sfenner				/* truncated */
99175115Sfenner			} else {
99275115Sfenner				/* invalid */
99375115Sfenner				printf("???");
99475115Sfenner			}
99575115Sfenner			break;
99675115Sfenner		}
99775115Sfenner	}
99875115Sfenner	printf("\"");
99975115Sfenner}
100075115Sfenner
1001127668Sbmsstatic void
1002127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
100375115Sfenner{
100475115Sfenner	struct icmp6_nodeinfo *ni6;
100575115Sfenner	struct icmp6_hdr *dp;
100675115Sfenner	const u_char *cp;
1007127668Sbms	size_t siz, i;
100875115Sfenner	int needcomma;
100975115Sfenner
1010127668Sbms	if (ep < bp)
1011127668Sbms		return;
101275115Sfenner	dp = (struct icmp6_hdr *)bp;
101375115Sfenner	ni6 = (struct icmp6_nodeinfo *)bp;
101475115Sfenner	siz = ep - bp;
101575115Sfenner
101675115Sfenner	switch (ni6->ni_type) {
101775115Sfenner	case ICMP6_NI_QUERY:
101875115Sfenner		if (siz == sizeof(*dp) + 4) {
101975115Sfenner			/* KAME who-are-you */
1020146773Ssam			printf(" who-are-you request");
102175115Sfenner			break;
102275115Sfenner		}
1023146773Ssam		printf(" node information query");
102475115Sfenner
102575115Sfenner		TCHECK2(*dp, sizeof(*ni6));
102675115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
102775115Sfenner		printf(" (");	/*)*/
1028127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
102975115Sfenner		case NI_QTYPE_NOOP:
103075115Sfenner			printf("noop");
103175115Sfenner			break;
103275115Sfenner		case NI_QTYPE_SUPTYPES:
103375115Sfenner			printf("supported qtypes");
1034127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
103575115Sfenner			if (i)
103675115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
103775115Sfenner			break;
103875115Sfenner			break;
103975115Sfenner		case NI_QTYPE_FQDN:
104075115Sfenner			printf("DNS name");
104175115Sfenner			break;
104275115Sfenner		case NI_QTYPE_NODEADDR:
104375115Sfenner			printf("node addresses");
104475115Sfenner			i = ni6->ni_flags;
104575115Sfenner			if (!i)
104675115Sfenner				break;
104775115Sfenner			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
104875115Sfenner			printf(" [%s%s%s%s%s%s]",
104975115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
105075115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
105175115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
105275115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
105375115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
105475115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
105575115Sfenner			break;
105675115Sfenner		default:
105775115Sfenner			printf("unknown");
105875115Sfenner			break;
105975115Sfenner		}
106075115Sfenner
106175115Sfenner		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
106275115Sfenner		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
106375115Sfenner			if (siz != sizeof(*ni6))
106475115Sfenner				if (vflag)
106575115Sfenner					printf(", invalid len");
106675115Sfenner			/*(*/
106775115Sfenner			printf(")");
106875115Sfenner			break;
106975115Sfenner		}
107075115Sfenner
107175115Sfenner
107275115Sfenner		/* XXX backward compat, icmp-name-lookup-03 */
107375115Sfenner		if (siz == sizeof(*ni6)) {
107475115Sfenner			printf(", 03 draft");
107575115Sfenner			/*(*/
107675115Sfenner			printf(")");
107775115Sfenner			break;
107875115Sfenner		}
107975115Sfenner
108075115Sfenner		switch (ni6->ni_code) {
108175115Sfenner		case ICMP6_NI_SUBJ_IPV6:
108275115Sfenner			if (!TTEST2(*dp,
108375115Sfenner			    sizeof(*ni6) + sizeof(struct in6_addr)))
108475115Sfenner				break;
108575115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
108675115Sfenner				if (vflag)
108775115Sfenner					printf(", invalid subject len");
108875115Sfenner				break;
108975115Sfenner			}
109075115Sfenner			printf(", subject=%s",
109175115Sfenner			    getname6((const u_char *)(ni6 + 1)));
109275115Sfenner			break;
109375115Sfenner		case ICMP6_NI_SUBJ_FQDN:
109475115Sfenner			printf(", subject=DNS name");
109575115Sfenner			cp = (const u_char *)(ni6 + 1);
109675115Sfenner			if (cp[0] == ep - cp - 1) {
109775115Sfenner				/* icmp-name-lookup-03, pascal string */
109875115Sfenner				if (vflag)
109975115Sfenner					printf(", 03 draft");
110075115Sfenner				cp++;
110175115Sfenner				printf(", \"");
110275115Sfenner				while (cp < ep) {
110375115Sfenner					safeputchar(*cp);
110475115Sfenner					cp++;
110575115Sfenner				}
110675115Sfenner				printf("\"");
110775115Sfenner			} else
110875115Sfenner				dnsname_print(cp, ep);
110975115Sfenner			break;
111075115Sfenner		case ICMP6_NI_SUBJ_IPV4:
111175115Sfenner			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
111275115Sfenner				break;
111375115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
111475115Sfenner				if (vflag)
111575115Sfenner					printf(", invalid subject len");
111675115Sfenner				break;
111775115Sfenner			}
111875115Sfenner			printf(", subject=%s",
111975115Sfenner			    getname((const u_char *)(ni6 + 1)));
112075115Sfenner			break;
112175115Sfenner		default:
112275115Sfenner			printf(", unknown subject");
112375115Sfenner			break;
112475115Sfenner		}
112575115Sfenner
112675115Sfenner		/*(*/
112775115Sfenner		printf(")");
112875115Sfenner		break;
112975115Sfenner
113075115Sfenner	case ICMP6_NI_REPLY:
113175115Sfenner		if (icmp6len > siz) {
113275115Sfenner			printf("[|icmp6: node information reply]");
113375115Sfenner			break;
113475115Sfenner		}
113575115Sfenner
113675115Sfenner		needcomma = 0;
113775115Sfenner
113875115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
1139146773Ssam		printf(" node information reply");
114075115Sfenner		printf(" (");	/*)*/
114175115Sfenner		switch (ni6->ni_code) {
114275115Sfenner		case ICMP6_NI_SUCCESS:
114375115Sfenner			if (vflag) {
114475115Sfenner				printf("success");
114575115Sfenner				needcomma++;
114675115Sfenner			}
114775115Sfenner			break;
114875115Sfenner		case ICMP6_NI_REFUSED:
114975115Sfenner			printf("refused");
115075115Sfenner			needcomma++;
115175115Sfenner			if (siz != sizeof(*ni6))
115275115Sfenner				if (vflag)
115375115Sfenner					printf(", invalid length");
115475115Sfenner			break;
115575115Sfenner		case ICMP6_NI_UNKNOWN:
115675115Sfenner			printf("unknown");
115775115Sfenner			needcomma++;
115875115Sfenner			if (siz != sizeof(*ni6))
115975115Sfenner				if (vflag)
116075115Sfenner					printf(", invalid length");
116175115Sfenner			break;
116275115Sfenner		}
116375115Sfenner
116475115Sfenner		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
116575115Sfenner			/*(*/
116675115Sfenner			printf(")");
116775115Sfenner			break;
116875115Sfenner		}
116975115Sfenner
1170127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
117175115Sfenner		case NI_QTYPE_NOOP:
117275115Sfenner			if (needcomma)
117375115Sfenner				printf(", ");
117475115Sfenner			printf("noop");
117575115Sfenner			if (siz != sizeof(*ni6))
117675115Sfenner				if (vflag)
117775115Sfenner					printf(", invalid length");
117875115Sfenner			break;
117975115Sfenner		case NI_QTYPE_SUPTYPES:
118075115Sfenner			if (needcomma)
118175115Sfenner				printf(", ");
118275115Sfenner			printf("supported qtypes");
1183127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
118475115Sfenner			if (i)
118575115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
118675115Sfenner			break;
118775115Sfenner		case NI_QTYPE_FQDN:
118875115Sfenner			if (needcomma)
118975115Sfenner				printf(", ");
119075115Sfenner			printf("DNS name");
119175115Sfenner			cp = (const u_char *)(ni6 + 1) + 4;
119275115Sfenner			if (cp[0] == ep - cp - 1) {
119375115Sfenner				/* icmp-name-lookup-03, pascal string */
119475115Sfenner				if (vflag)
119575115Sfenner					printf(", 03 draft");
119675115Sfenner				cp++;
119775115Sfenner				printf(", \"");
119875115Sfenner				while (cp < ep) {
119975115Sfenner					safeputchar(*cp);
120075115Sfenner					cp++;
120175115Sfenner				}
120275115Sfenner				printf("\"");
120375115Sfenner			} else
120475115Sfenner				dnsname_print(cp, ep);
1205127668Sbms			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
120675115Sfenner				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
120775115Sfenner			break;
120875115Sfenner		case NI_QTYPE_NODEADDR:
120975115Sfenner			if (needcomma)
121075115Sfenner				printf(", ");
121175115Sfenner			printf("node addresses");
121275115Sfenner			i = sizeof(*ni6);
121375115Sfenner			while (i < siz) {
121475115Sfenner				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
121575115Sfenner					break;
121675115Sfenner				printf(" %s", getname6(bp + i));
121775115Sfenner				i += sizeof(struct in6_addr);
1218127668Sbms				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
121975115Sfenner				i += sizeof(int32_t);
122075115Sfenner			}
122175115Sfenner			i = ni6->ni_flags;
122275115Sfenner			if (!i)
122375115Sfenner				break;
122475115Sfenner			printf(" [%s%s%s%s%s%s%s]",
122575115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
122675115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
122775115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
122875115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
122975115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
123075115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
123175115Sfenner			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
123275115Sfenner			break;
123375115Sfenner		default:
123475115Sfenner			if (needcomma)
123575115Sfenner				printf(", ");
123675115Sfenner			printf("unknown");
123775115Sfenner			break;
123875115Sfenner		}
123975115Sfenner
124075115Sfenner		/*(*/
124175115Sfenner		printf(")");
124275115Sfenner		break;
124375115Sfenner	}
124456893Sfenner	return;
124575115Sfenner
124675115Sfennertrunc:
124775115Sfenner	fputs("[|icmp6]", stdout);
124856893Sfenner}
124975115Sfenner
1250127668Sbmsstatic void
1251127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep)
125275115Sfenner{
125375115Sfenner	struct icmp6_router_renum *rr6;
125475115Sfenner	const char *cp;
125575115Sfenner	struct rr_pco_match *match;
125675115Sfenner	struct rr_pco_use *use;
125775115Sfenner	char hbuf[NI_MAXHOST];
125875115Sfenner	int n;
125975115Sfenner
1260127668Sbms	if (ep < bp)
1261127668Sbms		return;
126275115Sfenner	rr6 = (struct icmp6_router_renum *)bp;
126375115Sfenner	cp = (const char *)(rr6 + 1);
126475115Sfenner
126575115Sfenner	TCHECK(rr6->rr_reserved);
126675115Sfenner	switch (rr6->rr_code) {
126775115Sfenner	case ICMP6_ROUTER_RENUMBERING_COMMAND:
126875115Sfenner		printf("router renum: command");
126975115Sfenner		break;
127075115Sfenner	case ICMP6_ROUTER_RENUMBERING_RESULT:
127175115Sfenner		printf("router renum: result");
127275115Sfenner		break;
127375115Sfenner	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
127475115Sfenner		printf("router renum: sequence number reset");
127575115Sfenner		break;
127675115Sfenner	default:
127775115Sfenner		printf("router renum: code-#%d", rr6->rr_code);
127875115Sfenner		break;
127975115Sfenner	}
128075115Sfenner
1281127668Sbms	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
128275115Sfenner
128375115Sfenner	if (vflag) {
128475115Sfenner#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
128575115Sfenner		printf("[");	/*]*/
128675115Sfenner		if (rr6->rr_flags) {
128775115Sfenner			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
128875115Sfenner			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
128998524Sfenner			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
129075115Sfenner			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
129175115Sfenner			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
129275115Sfenner		}
129375115Sfenner		printf("seg=%u,", rr6->rr_segnum);
1294190207Srpaulo		printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
129575115Sfenner		if (rr6->rr_reserved)
1296190207Srpaulo			printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
129775115Sfenner		/*[*/
129875115Sfenner		printf("]");
129975115Sfenner#undef F
130075115Sfenner	}
130175115Sfenner
130275115Sfenner	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
130375115Sfenner		match = (struct rr_pco_match *)cp;
130475115Sfenner		cp = (const char *)(match + 1);
130575115Sfenner
130675115Sfenner		TCHECK(match->rpm_prefix);
130775115Sfenner
130898524Sfenner		if (vflag > 1)
130975115Sfenner			printf("\n\t");
131075115Sfenner		else
131175115Sfenner			printf(" ");
131275115Sfenner		printf("match(");	/*)*/
131375115Sfenner		switch (match->rpm_code) {
131475115Sfenner		case RPM_PCO_ADD:	printf("add"); break;
131575115Sfenner		case RPM_PCO_CHANGE:	printf("change"); break;
131675115Sfenner		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
131775115Sfenner		default:		printf("#%u", match->rpm_code); break;
131875115Sfenner		}
131975115Sfenner
132075115Sfenner		if (vflag) {
132175115Sfenner			printf(",ord=%u", match->rpm_ordinal);
132275115Sfenner			printf(",min=%u", match->rpm_minlen);
132375115Sfenner			printf(",max=%u", match->rpm_maxlen);
132475115Sfenner		}
132575115Sfenner		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
132675115Sfenner			printf(",%s/%u", hbuf, match->rpm_matchlen);
132775115Sfenner		else
132875115Sfenner			printf(",?/%u", match->rpm_matchlen);
132975115Sfenner		/*(*/
133075115Sfenner		printf(")");
133175115Sfenner
133275115Sfenner		n = match->rpm_len - 3;
133375115Sfenner		if (n % 4)
133475115Sfenner			goto trunc;
133575115Sfenner		n /= 4;
133675115Sfenner		while (n-- > 0) {
133775115Sfenner			use = (struct rr_pco_use *)cp;
133875115Sfenner			cp = (const char *)(use + 1);
133975115Sfenner
134075115Sfenner			TCHECK(use->rpu_prefix);
134175115Sfenner
134298524Sfenner			if (vflag > 1)
134375115Sfenner				printf("\n\t");
134475115Sfenner			else
134575115Sfenner				printf(" ");
134675115Sfenner			printf("use(");	/*)*/
134775115Sfenner			if (use->rpu_flags) {
134875115Sfenner#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
134975115Sfenner				printf("%s%s,",
135075115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
135175115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
135275115Sfenner#undef F
135375115Sfenner			}
135475115Sfenner			if (vflag) {
135575115Sfenner				printf("mask=0x%x,", use->rpu_ramask);
135675115Sfenner				printf("raflags=0x%x,", use->rpu_raflags);
135775115Sfenner				if (~use->rpu_vltime == 0)
135875115Sfenner					printf("vltime=infty,");
135975115Sfenner				else
136075115Sfenner					printf("vltime=%u,",
1361127668Sbms					    EXTRACT_32BITS(&use->rpu_vltime));
136275115Sfenner				if (~use->rpu_pltime == 0)
136375115Sfenner					printf("pltime=infty,");
136475115Sfenner				else
136575115Sfenner					printf("pltime=%u,",
1366127668Sbms					    EXTRACT_32BITS(&use->rpu_pltime));
136775115Sfenner			}
136875115Sfenner			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
136975115Sfenner			    sizeof(hbuf)))
137075115Sfenner				printf("%s/%u/%u", hbuf, use->rpu_uselen,
137175115Sfenner				    use->rpu_keeplen);
137275115Sfenner			else
137375115Sfenner				printf("?/%u/%u", use->rpu_uselen,
137475115Sfenner				    use->rpu_keeplen);
137575115Sfenner			/*(*/
137675115Sfenner			printf(")");
137775115Sfenner		}
137875115Sfenner	}
137975115Sfenner
138075115Sfenner	return;
138175115Sfenner
138275115Sfennertrunc:
138375115Sfenner	fputs("[|icmp6]", stdout);
138475115Sfenner}
138575115Sfenner
138656893Sfenner#endif /* INET6 */
1387