print-icmp6.c revision 127668
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_ =
24127668Sbms    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.72.2.4 2004/03/24 00:14:09 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
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 *);
54127668Sbmsstatic struct udphdr *get_upperlayer(u_char *, u_int *);
5575115Sfennerstatic void dnsname_print(const u_char *, const u_char *);
56127668Sbmsstatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
57127668Sbmsstatic void icmp6_rrenum_print(const u_char *, const u_char *);
5856893Sfenner
5975115Sfenner#ifndef abs
6075115Sfenner#define abs(a)	((0 < (a)) ? (a) : -(a))
6175115Sfenner#endif
6275115Sfenner
6398524Sfennerstatic const char *
6498524Sfennerget_rtpref(u_int v)
6598524Sfenner{
6698524Sfenner	static const char *rtpref_str[] = {
6798524Sfenner		"medium",		/* 00 */
6898524Sfenner		"high",			/* 01 */
6998524Sfenner		"rsv",			/* 10 */
7098524Sfenner		"low"			/* 11 */
7198524Sfenner	};
7298524Sfenner
7398524Sfenner	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
7498524Sfenner}
7598524Sfenner
7698524Sfennerstatic const char *
7798524Sfennerget_lifetime(u_int32_t v)
7898524Sfenner{
7998524Sfenner	static char buf[20];
8098524Sfenner
8198524Sfenner	if (v == (u_int32_t)~0UL)
8298524Sfenner		return "infinity";
8398524Sfenner	else {
8498524Sfenner		snprintf(buf, sizeof(buf), "%u", v);
8598524Sfenner		return buf;
8698524Sfenner	}
8798524Sfenner}
8898524Sfenner
8998524Sfennerstatic void
9098524Sfennerprint_lladdr(const u_int8_t *p, size_t l)
9198524Sfenner{
9298524Sfenner	const u_int8_t *ep, *q;
9398524Sfenner
9498524Sfenner	q = p;
9598524Sfenner	ep = p + l;
9698524Sfenner	while (l > 0 && q < ep) {
9798524Sfenner		if (q > p)
9898524Sfenner			printf(":");
9998524Sfenner		printf("%02x", *q++);
10098524Sfenner		l--;
10198524Sfenner	}
10298524Sfenner}
10398524Sfenner
104127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
105127668Sbms	u_int len)
106127668Sbms{
107127668Sbms	size_t i;
108127668Sbms	register const u_int16_t *sp;
109127668Sbms	u_int32_t sum;
110127668Sbms	union {
111127668Sbms		struct {
112127668Sbms			struct in6_addr ph_src;
113127668Sbms			struct in6_addr ph_dst;
114127668Sbms			u_int32_t	ph_len;
115127668Sbms			u_int8_t	ph_zero[3];
116127668Sbms			u_int8_t	ph_nxt;
117127668Sbms		} ph;
118127668Sbms		u_int16_t pa[20];
119127668Sbms	} phu;
120127668Sbms
121127668Sbms	/* pseudo-header */
122127668Sbms	memset(&phu, 0, sizeof(phu));
123127668Sbms	phu.ph.ph_src = ip6->ip6_src;
124127668Sbms	phu.ph.ph_dst = ip6->ip6_dst;
125127668Sbms	phu.ph.ph_len = htonl(len);
126127668Sbms	phu.ph.ph_nxt = IPPROTO_ICMPV6;
127127668Sbms
128127668Sbms	sum = 0;
129127668Sbms	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
130127668Sbms		sum += phu.pa[i];
131127668Sbms
132127668Sbms	sp = (const u_int16_t *)icp;
133127668Sbms
134127668Sbms	for (i = 0; i < (len & ~1); i += 2)
135127668Sbms		sum += *sp++;
136127668Sbms
137127668Sbms	if (len & 1)
138127668Sbms		sum += htons((*(const u_int8_t *)sp) << 8);
139127668Sbms
140127668Sbms	while (sum > 0xffff)
141127668Sbms		sum = (sum & 0xffff) + (sum >> 16);
142127668Sbms	sum = ~sum & 0xffff;
143127668Sbms
144127668Sbms	return (sum);
145127668Sbms}
146127668Sbms
14756893Sfennervoid
148127668Sbmsicmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
14956893Sfenner{
15075115Sfenner	const struct icmp6_hdr *dp;
15198524Sfenner	const struct ip6_hdr *ip;
15298524Sfenner	const char *str;
15398524Sfenner	const struct ip6_hdr *oip;
15498524Sfenner	const struct udphdr *ouh;
15598524Sfenner	int dport;
15698524Sfenner	const u_char *ep;
15756893Sfenner	char buf[256];
158127668Sbms	u_int prot;
15956893Sfenner
16056893Sfenner	dp = (struct icmp6_hdr *)bp;
16156893Sfenner	ip = (struct ip6_hdr *)bp2;
16256893Sfenner	oip = (struct ip6_hdr *)(dp + 1);
16356893Sfenner	str = buf;
16475115Sfenner	/* 'ep' points to the end of available data. */
16556893Sfenner	ep = snapend;
16656893Sfenner
167127668Sbms	TCHECK(dp->icmp6_cksum);
168127668Sbms
169127668Sbms	if (vflag && !fragmented) {
170127668Sbms		int sum = dp->icmp6_cksum;
171127668Sbms
172127668Sbms		if (TTEST2(bp[0], length)) {
173127668Sbms			sum = icmp6_cksum(ip, dp, length);
174127668Sbms			if (sum != 0)
175127668Sbms				(void)printf("[bad icmp6 cksum %x!] ", sum);
176127668Sbms			else
177127668Sbms				(void)printf("[icmp6 sum ok] ");
178127668Sbms		}
179127668Sbms	}
180127668Sbms
18175115Sfenner	switch (dp->icmp6_type) {
18256893Sfenner	case ICMP6_DST_UNREACH:
18356893Sfenner		TCHECK(oip->ip6_dst);
18456893Sfenner		switch (dp->icmp6_code) {
18556893Sfenner		case ICMP6_DST_UNREACH_NOROUTE:
18656893Sfenner			printf("icmp6: %s unreachable route",
18756893Sfenner			       ip6addr_string(&oip->ip6_dst));
18856893Sfenner			break;
18956893Sfenner		case ICMP6_DST_UNREACH_ADMIN:
19056893Sfenner			printf("icmp6: %s unreachable prohibited",
19156893Sfenner			       ip6addr_string(&oip->ip6_dst));
19256893Sfenner			break;
19356893Sfenner		case ICMP6_DST_UNREACH_BEYONDSCOPE:
19456893Sfenner			printf("icmp6: %s beyond scope of source address %s",
19556893Sfenner			       ip6addr_string(&oip->ip6_dst),
19656893Sfenner			       ip6addr_string(&oip->ip6_src));
19756893Sfenner			break;
19856893Sfenner		case ICMP6_DST_UNREACH_ADDR:
19956893Sfenner			printf("icmp6: %s unreachable address",
20056893Sfenner			       ip6addr_string(&oip->ip6_dst));
20156893Sfenner			break;
20256893Sfenner		case ICMP6_DST_UNREACH_NOPORT:
20375115Sfenner			if ((ouh = get_upperlayer((u_char *)oip, &prot))
20475115Sfenner			    == NULL)
20575115Sfenner				goto trunc;
20675115Sfenner
207127668Sbms			dport = EXTRACT_16BITS(&ouh->uh_dport);
20875115Sfenner			switch (prot) {
20956893Sfenner			case IPPROTO_TCP:
21056893Sfenner				printf("icmp6: %s tcp port %s unreachable",
21156893Sfenner					ip6addr_string(&oip->ip6_dst),
21256893Sfenner					tcpport_string(dport));
21356893Sfenner				break;
21456893Sfenner			case IPPROTO_UDP:
21556893Sfenner				printf("icmp6: %s udp port %s unreachable",
21656893Sfenner					ip6addr_string(&oip->ip6_dst),
21756893Sfenner					udpport_string(dport));
21856893Sfenner				break;
21956893Sfenner			default:
22056893Sfenner				printf("icmp6: %s protocol %d port %d unreachable",
22156893Sfenner					ip6addr_string(&oip->ip6_dst),
22256893Sfenner					oip->ip6_nxt, dport);
22356893Sfenner				break;
22456893Sfenner			}
22556893Sfenner			break;
22656893Sfenner		default:
22756893Sfenner			printf("icmp6: %s unreachable code-#%d",
22856893Sfenner				ip6addr_string(&oip->ip6_dst),
22956893Sfenner				dp->icmp6_code);
23056893Sfenner			break;
23156893Sfenner		}
23256893Sfenner		break;
23356893Sfenner	case ICMP6_PACKET_TOO_BIG:
23456893Sfenner		TCHECK(dp->icmp6_mtu);
235127668Sbms		printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu));
23656893Sfenner		break;
23756893Sfenner	case ICMP6_TIME_EXCEEDED:
23856893Sfenner		TCHECK(oip->ip6_dst);
23956893Sfenner		switch (dp->icmp6_code) {
24056893Sfenner		case ICMP6_TIME_EXCEED_TRANSIT:
24156893Sfenner			printf("icmp6: time exceeded in-transit for %s",
24256893Sfenner				ip6addr_string(&oip->ip6_dst));
24356893Sfenner			break;
24456893Sfenner		case ICMP6_TIME_EXCEED_REASSEMBLY:
24556893Sfenner			printf("icmp6: ip6 reassembly time exceeded");
24656893Sfenner			break;
24756893Sfenner		default:
24856893Sfenner			printf("icmp6: time exceeded code-#%d",
24956893Sfenner				dp->icmp6_code);
25056893Sfenner			break;
25156893Sfenner		}
25256893Sfenner		break;
25356893Sfenner	case ICMP6_PARAM_PROB:
25456893Sfenner		TCHECK(oip->ip6_dst);
25556893Sfenner		switch (dp->icmp6_code) {
25656893Sfenner		case ICMP6_PARAMPROB_HEADER:
25798524Sfenner			printf("icmp6: parameter problem errorneous - octet %u",
258127668Sbms				EXTRACT_32BITS(&dp->icmp6_pptr));
25956893Sfenner			break;
26056893Sfenner		case ICMP6_PARAMPROB_NEXTHEADER:
26198524Sfenner			printf("icmp6: parameter problem next header - octet %u",
262127668Sbms				EXTRACT_32BITS(&dp->icmp6_pptr));
26356893Sfenner			break;
26456893Sfenner		case ICMP6_PARAMPROB_OPTION:
26598524Sfenner			printf("icmp6: parameter problem option - octet %u",
266127668Sbms				EXTRACT_32BITS(&dp->icmp6_pptr));
26756893Sfenner			break;
26856893Sfenner		default:
26956893Sfenner			printf("icmp6: parameter problem code-#%d",
27056893Sfenner			       dp->icmp6_code);
27156893Sfenner			break;
27256893Sfenner		}
27356893Sfenner		break;
27456893Sfenner	case ICMP6_ECHO_REQUEST:
27556893Sfenner	case ICMP6_ECHO_REPLY:
276127668Sbms		TCHECK(dp->icmp6_seq);
277127668Sbms		printf("icmp6: echo %s seq %u",
278127668Sbms			dp->icmp6_type == ICMP6_ECHO_REQUEST ?
279127668Sbms			"request" : "reply",
280127668Sbms			EXTRACT_16BITS(&dp->icmp6_seq));
28156893Sfenner		break;
28256893Sfenner	case ICMP6_MEMBERSHIP_QUERY:
28356893Sfenner		printf("icmp6: multicast listener query ");
28456893Sfenner		mld6_print((const u_char *)dp);
28556893Sfenner		break;
28656893Sfenner	case ICMP6_MEMBERSHIP_REPORT:
28756893Sfenner		printf("icmp6: multicast listener report ");
28856893Sfenner		mld6_print((const u_char *)dp);
28956893Sfenner		break;
29056893Sfenner	case ICMP6_MEMBERSHIP_REDUCTION:
29156893Sfenner		printf("icmp6: multicast listener done ");
29256893Sfenner		mld6_print((const u_char *)dp);
29356893Sfenner		break;
29456893Sfenner	case ND_ROUTER_SOLICIT:
29556893Sfenner		printf("icmp6: router solicitation ");
29656893Sfenner		if (vflag) {
29756893Sfenner#define RTSOLLEN 8
29875115Sfenner			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
299127668Sbms					length - RTSOLLEN);
30056893Sfenner		}
30156893Sfenner		break;
30256893Sfenner	case ND_ROUTER_ADVERT:
30356893Sfenner		printf("icmp6: router advertisement");
30456893Sfenner		if (vflag) {
30556893Sfenner			struct nd_router_advert *p;
30656893Sfenner
30756893Sfenner			p = (struct nd_router_advert *)dp;
30856893Sfenner			TCHECK(p->nd_ra_retransmit);
30956893Sfenner			printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
31056893Sfenner			if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
31156893Sfenner				printf("M");
31256893Sfenner			if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
31356893Sfenner				printf("O");
31498524Sfenner			if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
31575115Sfenner				printf("H");
31698524Sfenner
31798524Sfenner			if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
31898524Sfenner			    != 0)
31956893Sfenner				printf(" ");
32098524Sfenner
32198524Sfenner			printf("pref=%s, ",
32298524Sfenner			    get_rtpref(p->nd_ra_flags_reserved));
32398524Sfenner
324127668Sbms			printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime));
32556893Sfenner			printf("reachable_time=%u, ",
326127668Sbms				EXTRACT_32BITS(&p->nd_ra_reachable));
32756893Sfenner			printf("retrans_time=%u)",
328127668Sbms				EXTRACT_32BITS(&p->nd_ra_retransmit));
32956893Sfenner#define RTADVLEN 16
33075115Sfenner			icmp6_opt_print((const u_char *)dp + RTADVLEN,
331127668Sbms					length - RTADVLEN);
33256893Sfenner		}
33356893Sfenner		break;
33456893Sfenner	case ND_NEIGHBOR_SOLICIT:
33556893Sfenner	    {
33656893Sfenner		struct nd_neighbor_solicit *p;
33756893Sfenner		p = (struct nd_neighbor_solicit *)dp;
33856893Sfenner		TCHECK(p->nd_ns_target);
33956893Sfenner		printf("icmp6: neighbor sol: who has %s",
34056893Sfenner			ip6addr_string(&p->nd_ns_target));
34156893Sfenner		if (vflag) {
34256893Sfenner#define NDSOLLEN 24
34375115Sfenner			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
344127668Sbms					length - NDSOLLEN);
34556893Sfenner		}
34656893Sfenner	    }
34756893Sfenner		break;
34856893Sfenner	case ND_NEIGHBOR_ADVERT:
34956893Sfenner	    {
35056893Sfenner		struct nd_neighbor_advert *p;
35156893Sfenner
35256893Sfenner		p = (struct nd_neighbor_advert *)dp;
35356893Sfenner		TCHECK(p->nd_na_target);
35456893Sfenner		printf("icmp6: neighbor adv: tgt is %s",
35556893Sfenner			ip6addr_string(&p->nd_na_target));
35675115Sfenner		if (vflag) {
35756893Sfenner#define ND_NA_FLAG_ALL	\
35856893Sfenner	(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
35956893Sfenner			/* we don't need ntohl() here.  see advanced-api-04. */
36056893Sfenner			if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
36156893Sfenner#undef ND_NA_FLAG_ALL
36256893Sfenner				u_int32_t flags;
36356893Sfenner
36456893Sfenner				flags = p->nd_na_flags_reserved;
36556893Sfenner				printf("(");
36656893Sfenner				if (flags & ND_NA_FLAG_ROUTER)
36756893Sfenner					printf("R");
36856893Sfenner				if (flags & ND_NA_FLAG_SOLICITED)
36956893Sfenner					printf("S");
37056893Sfenner				if (flags & ND_NA_FLAG_OVERRIDE)
37156893Sfenner					printf("O");
37256893Sfenner				printf(")");
37356893Sfenner			}
37456893Sfenner#define NDADVLEN 24
37575115Sfenner			icmp6_opt_print((const u_char *)dp + NDADVLEN,
376127668Sbms					length - NDADVLEN);
37775115Sfenner#undef NDADVLEN
37856893Sfenner		}
37956893Sfenner	    }
38056893Sfenner		break;
38156893Sfenner	case ND_REDIRECT:
38256893Sfenner#define RDR(i) ((struct nd_redirect *)(i))
38356893Sfenner		TCHECK(RDR(dp)->nd_rd_dst);
38475115Sfenner		printf("icmp6: redirect %s",
38575115Sfenner		    getname6((const u_char *)&RDR(dp)->nd_rd_dst));
386127668Sbms		TCHECK(RDR(dp)->nd_rd_target);
38775115Sfenner		printf(" to %s",
38875115Sfenner		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
38956893Sfenner#define REDIRECTLEN 40
39056893Sfenner		if (vflag) {
39156893Sfenner			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
392127668Sbms					length - REDIRECTLEN);
39356893Sfenner		}
39456893Sfenner		break;
39575115Sfenner#undef REDIRECTLEN
39675115Sfenner#undef RDR
39756893Sfenner	case ICMP6_ROUTER_RENUMBERING:
398127668Sbms		icmp6_rrenum_print(bp, ep);
39956893Sfenner		break;
40075115Sfenner	case ICMP6_NI_QUERY:
40175115Sfenner	case ICMP6_NI_REPLY:
402127668Sbms		icmp6_nodeinfo_print(length, bp, ep);
40356893Sfenner		break;
404127668Sbms	case ICMP6_HADISCOV_REQUEST:
405127668Sbms		printf("icmp6: ha discovery request");
406127668Sbms		if (vflag) {
407127668Sbms			TCHECK(dp->icmp6_data16[0]);
408127668Sbms			printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
409127668Sbms		}
410127668Sbms		break;
411127668Sbms	case ICMP6_HADISCOV_REPLY:
412127668Sbms		printf("icmp6: ha discovery reply");
413127668Sbms		if (vflag) {
414127668Sbms			struct in6_addr *in6;
415127668Sbms			u_char *cp;
416127668Sbms
417127668Sbms			TCHECK(dp->icmp6_data16[0]);
418127668Sbms			printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
419127668Sbms			cp = (u_char *)dp + length;
420127668Sbms			in6 = (struct in6_addr *)(dp + 1);
421127668Sbms			for (; (u_char *)in6 < cp; in6++) {
422127668Sbms				TCHECK(*in6);
423127668Sbms				printf(", %s", ip6addr_string(in6));
424127668Sbms			}
425127668Sbms			printf(")");
426127668Sbms		}
427127668Sbms		break;
428127668Sbms	case ICMP6_MOBILEPREFIX_SOLICIT:
429127668Sbms		printf("icmp6: mobile router solicitation");
430127668Sbms		if (vflag) {
431127668Sbms			TCHECK(dp->icmp6_data16[0]);
432127668Sbms			printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
433127668Sbms		}
434127668Sbms		break;
435127668Sbms	case ICMP6_MOBILEPREFIX_ADVERT:
436127668Sbms		printf("icmp6: mobile router advertisement");
437127668Sbms		if (vflag) {
438127668Sbms			TCHECK(dp->icmp6_data16[0]);
439127668Sbms			printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
440127668Sbms			if (dp->icmp6_data16[1] & 0xc0)
441127668Sbms				printf(" ");
442127668Sbms			if (dp->icmp6_data16[1] & 0x80)
443127668Sbms				printf("M");
444127668Sbms			if (dp->icmp6_data16[1] & 0x40)
445127668Sbms				printf("O");
446127668Sbms			printf(")");
447127668Sbms#define MPADVLEN 8
448127668Sbms			icmp6_opt_print((const u_char *)dp + MPADVLEN,
449127668Sbms					length - MPADVLEN);
450127668Sbms		}
451127668Sbms		break;
45256893Sfenner	default:
45356893Sfenner		printf("icmp6: type-#%d", dp->icmp6_type);
45456893Sfenner		break;
45556893Sfenner	}
45656893Sfenner	return;
45756893Sfennertrunc:
45856893Sfenner	fputs("[|icmp6]", stdout);
45956893Sfenner}
46056893Sfenner
46175115Sfennerstatic struct udphdr *
462127668Sbmsget_upperlayer(u_char *bp, u_int *prot)
46375115Sfenner{
46498524Sfenner	const u_char *ep;
46575115Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
46675115Sfenner	struct udphdr *uh;
46775115Sfenner	struct ip6_hbh *hbh;
46875115Sfenner	struct ip6_frag *fragh;
46975115Sfenner	struct ah *ah;
470127668Sbms	u_int nh;
471127668Sbms	int hlen;
47275115Sfenner
47375115Sfenner	/* 'ep' points to the end of available data. */
47475115Sfenner	ep = snapend;
47575115Sfenner
476127668Sbms	if (!TTEST(ip6->ip6_nxt))
47775115Sfenner		return NULL;
47875115Sfenner
47975115Sfenner	nh = ip6->ip6_nxt;
48075115Sfenner	hlen = sizeof(struct ip6_hdr);
48175115Sfenner
48275115Sfenner	while (bp < snapend) {
48375115Sfenner		bp += hlen;
48475115Sfenner
48575115Sfenner		switch(nh) {
48675115Sfenner		case IPPROTO_UDP:
48775115Sfenner		case IPPROTO_TCP:
48875115Sfenner			uh = (struct udphdr *)bp;
48975115Sfenner			if (TTEST(uh->uh_dport)) {
49075115Sfenner				*prot = nh;
49175115Sfenner				return(uh);
49275115Sfenner			}
49375115Sfenner			else
49475115Sfenner				return(NULL);
49575115Sfenner			/* NOTREACHED */
49675115Sfenner
49775115Sfenner		case IPPROTO_HOPOPTS:
49875115Sfenner		case IPPROTO_DSTOPTS:
49975115Sfenner		case IPPROTO_ROUTING:
50075115Sfenner			hbh = (struct ip6_hbh *)bp;
501127668Sbms			if (!TTEST(hbh->ip6h_len))
50275115Sfenner				return(NULL);
50375115Sfenner			nh = hbh->ip6h_nxt;
50475115Sfenner			hlen = (hbh->ip6h_len + 1) << 3;
50575115Sfenner			break;
50675115Sfenner
50775115Sfenner		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
50875115Sfenner			fragh = (struct ip6_frag *)bp;
509127668Sbms			if (!TTEST(fragh->ip6f_offlg))
51075115Sfenner				return(NULL);
51175115Sfenner			/* fragments with non-zero offset are meaningless */
512127668Sbms			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
51375115Sfenner				return(NULL);
51475115Sfenner			nh = fragh->ip6f_nxt;
51575115Sfenner			hlen = sizeof(struct ip6_frag);
51675115Sfenner			break;
51775115Sfenner
51875115Sfenner		case IPPROTO_AH:
51975115Sfenner			ah = (struct ah *)bp;
520127668Sbms			if (!TTEST(ah->ah_len))
52175115Sfenner				return(NULL);
52275115Sfenner			nh = ah->ah_nxt;
52375115Sfenner			hlen = (ah->ah_len + 2) << 2;
52475115Sfenner			break;
52575115Sfenner
52675115Sfenner		default:	/* unknown or undecodable header */
52775115Sfenner			*prot = nh; /* meaningless, but set here anyway */
52875115Sfenner			return(NULL);
52975115Sfenner		}
53075115Sfenner	}
53175115Sfenner
53275115Sfenner	return(NULL);		/* should be notreached, though */
53375115Sfenner}
53475115Sfenner
535127668Sbmsstatic void
53698524Sfennericmp6_opt_print(const u_char *bp, int resid)
53756893Sfenner{
53898524Sfenner	const struct nd_opt_hdr *op;
53998524Sfenner	const struct nd_opt_hdr *opl;	/* why there's no struct? */
54098524Sfenner	const struct nd_opt_prefix_info *opp;
54198524Sfenner	const struct icmp6_opts_redirect *opr;
54298524Sfenner	const struct nd_opt_mtu *opm;
54398524Sfenner	const struct nd_opt_advinterval *opa;
544127668Sbms	const struct nd_opt_homeagent_info *oph;
54598524Sfenner	const struct nd_opt_route_info *opri;
54698524Sfenner	const u_char *cp, *ep;
54798524Sfenner	struct in6_addr in6, *in6p;
54898524Sfenner	size_t l;
54956893Sfenner
55056893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
55156893Sfenner
55298524Sfenner	cp = bp;
55375115Sfenner	/* 'ep' points to the end of available data. */
55456893Sfenner	ep = snapend;
55556893Sfenner
55698524Sfenner	while (cp < ep) {
55798524Sfenner		op = (struct nd_opt_hdr *)cp;
55898524Sfenner
55998524Sfenner		ECHECK(op->nd_opt_len);
56098524Sfenner		if (resid <= 0)
56198524Sfenner			return;
56298524Sfenner		if (op->nd_opt_len == 0)
56356893Sfenner			goto trunc;
56498524Sfenner		if (cp + (op->nd_opt_len << 3) > ep)
56556893Sfenner			goto trunc;
56698524Sfenner
56798524Sfenner		switch (op->nd_opt_type) {
56898524Sfenner		case ND_OPT_SOURCE_LINKADDR:
56998524Sfenner			opl = (struct nd_opt_hdr *)op;
57098524Sfenner			printf("(src lladdr: ");
57198524Sfenner			l = (op->nd_opt_len << 3) - 2;
57298524Sfenner			print_lladdr(cp + 2, l);
57398524Sfenner			/*(*/
57498524Sfenner			printf(")");
57598524Sfenner			break;
57698524Sfenner		case ND_OPT_TARGET_LINKADDR:
57798524Sfenner			opl = (struct nd_opt_hdr *)op;
57898524Sfenner			printf("(tgt lladdr: ");
57998524Sfenner			l = (op->nd_opt_len << 3) - 2;
58098524Sfenner			print_lladdr(cp + 2, l);
58198524Sfenner			/*(*/
58298524Sfenner			printf(")");
58398524Sfenner			break;
58498524Sfenner		case ND_OPT_PREFIX_INFORMATION:
58598524Sfenner			opp = (struct nd_opt_prefix_info *)op;
58698524Sfenner			TCHECK(opp->nd_opt_pi_prefix);
58798524Sfenner			printf("(prefix info: ");	/*)*/
58898524Sfenner			if (op->nd_opt_len != 4) {
58998524Sfenner				printf("badlen");
59098524Sfenner				/*(*/
59198524Sfenner				printf(")");
59298524Sfenner				break;
59398524Sfenner			}
59498524Sfenner			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
59598524Sfenner				printf("L");
59698524Sfenner			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
59798524Sfenner				printf("A");
59898524Sfenner			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
59998524Sfenner				printf("R");
60098524Sfenner			if (opp->nd_opt_pi_flags_reserved)
60198524Sfenner				printf(" ");
60298524Sfenner			printf("valid_ltime=%s,",
603127668Sbms			    get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
60498524Sfenner			printf("preferred_ltime=%s,",
605127668Sbms			    get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
60698524Sfenner			printf("prefix=%s/%d",
60798524Sfenner			    ip6addr_string(&opp->nd_opt_pi_prefix),
60898524Sfenner			    opp->nd_opt_pi_prefix_len);
60998524Sfenner			if (opp->nd_opt_pi_len != 4)
61098524Sfenner				printf("!");
61198524Sfenner			/*(*/
61298524Sfenner			printf(")");
61398524Sfenner			break;
61498524Sfenner		case ND_OPT_REDIRECTED_HEADER:
61598524Sfenner			opr = (struct icmp6_opts_redirect *)op;
61698524Sfenner			printf("(redirect)");
61798524Sfenner			/* xxx */
61898524Sfenner			break;
61998524Sfenner		case ND_OPT_MTU:
62098524Sfenner			opm = (struct nd_opt_mtu *)op;
62198524Sfenner			TCHECK(opm->nd_opt_mtu_mtu);
62298524Sfenner			printf("(mtu:");	/*)*/
62398524Sfenner			if (op->nd_opt_len != 1) {
62498524Sfenner				printf("badlen");
62598524Sfenner				/*(*/
62698524Sfenner				printf(")");
62798524Sfenner				break;
62898524Sfenner			}
629127668Sbms			printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
63098524Sfenner			if (opm->nd_opt_mtu_len != 1)
63198524Sfenner				printf("!");
63298524Sfenner			printf(")");
63398524Sfenner			break;
63498524Sfenner		case ND_OPT_ADVINTERVAL:
63598524Sfenner			opa = (struct nd_opt_advinterval *)op;
63698524Sfenner			TCHECK(opa->nd_opt_adv_interval);
63798524Sfenner			printf("(advint:");	/*)*/
63898524Sfenner			printf(" advint=%u",
639127668Sbms			    EXTRACT_32BITS(&opa->nd_opt_adv_interval));
64098524Sfenner			/*(*/
64198524Sfenner			printf(")");
642127668Sbms			break;
643127668Sbms		case ND_OPT_HOMEAGENT_INFO:
644127668Sbms			oph = (struct nd_opt_homeagent_info *)op;
645127668Sbms			TCHECK(oph->nd_opt_hai_lifetime);
646127668Sbms			printf("(ha info:");	/*)*/
647127668Sbms			printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
648127668Sbms			printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
649127668Sbms			printf(")");
650127668Sbms			break;
65198524Sfenner		case ND_OPT_ROUTE_INFO:
65298524Sfenner			opri = (struct nd_opt_route_info *)op;
65398524Sfenner			TCHECK(opri->nd_opt_rti_lifetime);
65498524Sfenner			memset(&in6, 0, sizeof(in6));
65598524Sfenner			in6p = (struct in6_addr *)(opri + 1);
65698524Sfenner			switch (op->nd_opt_len) {
65798524Sfenner			case 1:
65898524Sfenner				break;
65998524Sfenner			case 2:
66098524Sfenner				TCHECK2(*in6p, 8);
66198524Sfenner				memcpy(&in6, opri + 1, 8);
66298524Sfenner				break;
66398524Sfenner			case 3:
66498524Sfenner				TCHECK(*in6p);
66598524Sfenner				memcpy(&in6, opri + 1, sizeof(in6));
66698524Sfenner				break;
66798524Sfenner			default:
66898524Sfenner				goto trunc;
66998524Sfenner			}
67098524Sfenner			printf("(rtinfo:");	/*)*/
67198524Sfenner			printf(" %s/%u", ip6addr_string(&in6),
67298524Sfenner			    opri->nd_opt_rti_prefixlen);
67398524Sfenner			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
67498524Sfenner			printf(", lifetime=%s",
675127668Sbms			    get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
67698524Sfenner			/*(*/
67798524Sfenner			printf(")");
67898524Sfenner			break;
67998524Sfenner		default:
680111726Sfenner			printf("(unknown opt_type=%d, opt_len=%d)",
68198524Sfenner			       op->nd_opt_type, op->nd_opt_len);
68298524Sfenner			break;
68356893Sfenner		}
68498524Sfenner
68598524Sfenner		cp += op->nd_opt_len << 3;
68698524Sfenner		resid -= op->nd_opt_len << 3;
68756893Sfenner	}
68856893Sfenner	return;
68998524Sfenner
69056893Sfenner trunc:
69156893Sfenner	fputs("[ndp opt]", stdout);
69256893Sfenner	return;
69356893Sfenner#undef ECHECK
69456893Sfenner}
69556893Sfenner
696127668Sbmsstatic void
69798524Sfennermld6_print(const u_char *bp)
69856893Sfenner{
69998524Sfenner	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
70098524Sfenner	const u_char *ep;
70156893Sfenner
70275115Sfenner	/* 'ep' points to the end of available data. */
70356893Sfenner	ep = snapend;
70456893Sfenner
70556893Sfenner	if ((u_char *)mp + sizeof(*mp) > ep)
70656893Sfenner		return;
70756893Sfenner
708127668Sbms	printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
70956893Sfenner	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
71075115Sfenner}
71156893Sfenner
71275115Sfennerstatic void
71375115Sfennerdnsname_print(const u_char *cp, const u_char *ep)
71475115Sfenner{
71575115Sfenner	int i;
71675115Sfenner
71775115Sfenner	/* DNS name decoding - no decompression */
71875115Sfenner	printf(", \"");
71975115Sfenner	while (cp < ep) {
72075115Sfenner		i = *cp++;
72175115Sfenner		if (i) {
72275115Sfenner			if (i > ep - cp) {
72375115Sfenner				printf("???");
72475115Sfenner				break;
72575115Sfenner			}
72675115Sfenner			while (i-- && cp < ep) {
72775115Sfenner				safeputchar(*cp);
72875115Sfenner				cp++;
72975115Sfenner			}
73075115Sfenner			if (cp + 1 < ep && *cp)
73175115Sfenner				printf(".");
73275115Sfenner		} else {
73375115Sfenner			if (cp == ep) {
73475115Sfenner				/* FQDN */
73575115Sfenner				printf(".");
73675115Sfenner			} else if (cp + 1 == ep && *cp == '\0') {
73775115Sfenner				/* truncated */
73875115Sfenner			} else {
73975115Sfenner				/* invalid */
74075115Sfenner				printf("???");
74175115Sfenner			}
74275115Sfenner			break;
74375115Sfenner		}
74475115Sfenner	}
74575115Sfenner	printf("\"");
74675115Sfenner}
74775115Sfenner
748127668Sbmsstatic void
749127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
75075115Sfenner{
75175115Sfenner	struct icmp6_nodeinfo *ni6;
75275115Sfenner	struct icmp6_hdr *dp;
75375115Sfenner	const u_char *cp;
754127668Sbms	size_t siz, i;
75575115Sfenner	int needcomma;
75675115Sfenner
757127668Sbms	if (ep < bp)
758127668Sbms		return;
75975115Sfenner	dp = (struct icmp6_hdr *)bp;
76075115Sfenner	ni6 = (struct icmp6_nodeinfo *)bp;
76175115Sfenner	siz = ep - bp;
76275115Sfenner
76375115Sfenner	switch (ni6->ni_type) {
76475115Sfenner	case ICMP6_NI_QUERY:
76575115Sfenner		if (siz == sizeof(*dp) + 4) {
76675115Sfenner			/* KAME who-are-you */
76775115Sfenner			printf("icmp6: who-are-you request");
76875115Sfenner			break;
76975115Sfenner		}
77075115Sfenner		printf("icmp6: node information query");
77175115Sfenner
77275115Sfenner		TCHECK2(*dp, sizeof(*ni6));
77375115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
77475115Sfenner		printf(" (");	/*)*/
775127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
77675115Sfenner		case NI_QTYPE_NOOP:
77775115Sfenner			printf("noop");
77875115Sfenner			break;
77975115Sfenner		case NI_QTYPE_SUPTYPES:
78075115Sfenner			printf("supported qtypes");
781127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
78275115Sfenner			if (i)
78375115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
78475115Sfenner			break;
78575115Sfenner			break;
78675115Sfenner		case NI_QTYPE_FQDN:
78775115Sfenner			printf("DNS name");
78875115Sfenner			break;
78975115Sfenner		case NI_QTYPE_NODEADDR:
79075115Sfenner			printf("node addresses");
79175115Sfenner			i = ni6->ni_flags;
79275115Sfenner			if (!i)
79375115Sfenner				break;
79475115Sfenner			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
79575115Sfenner			printf(" [%s%s%s%s%s%s]",
79675115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
79775115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
79875115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
79975115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
80075115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
80175115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
80275115Sfenner			break;
80375115Sfenner		default:
80475115Sfenner			printf("unknown");
80575115Sfenner			break;
80675115Sfenner		}
80775115Sfenner
80875115Sfenner		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
80975115Sfenner		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
81075115Sfenner			if (siz != sizeof(*ni6))
81175115Sfenner				if (vflag)
81275115Sfenner					printf(", invalid len");
81375115Sfenner			/*(*/
81475115Sfenner			printf(")");
81575115Sfenner			break;
81675115Sfenner		}
81775115Sfenner
81875115Sfenner
81975115Sfenner		/* XXX backward compat, icmp-name-lookup-03 */
82075115Sfenner		if (siz == sizeof(*ni6)) {
82175115Sfenner			printf(", 03 draft");
82275115Sfenner			/*(*/
82375115Sfenner			printf(")");
82475115Sfenner			break;
82575115Sfenner		}
82675115Sfenner
82775115Sfenner		switch (ni6->ni_code) {
82875115Sfenner		case ICMP6_NI_SUBJ_IPV6:
82975115Sfenner			if (!TTEST2(*dp,
83075115Sfenner			    sizeof(*ni6) + sizeof(struct in6_addr)))
83175115Sfenner				break;
83275115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
83375115Sfenner				if (vflag)
83475115Sfenner					printf(", invalid subject len");
83575115Sfenner				break;
83675115Sfenner			}
83775115Sfenner			printf(", subject=%s",
83875115Sfenner			    getname6((const u_char *)(ni6 + 1)));
83975115Sfenner			break;
84075115Sfenner		case ICMP6_NI_SUBJ_FQDN:
84175115Sfenner			printf(", subject=DNS name");
84275115Sfenner			cp = (const u_char *)(ni6 + 1);
84375115Sfenner			if (cp[0] == ep - cp - 1) {
84475115Sfenner				/* icmp-name-lookup-03, pascal string */
84575115Sfenner				if (vflag)
84675115Sfenner					printf(", 03 draft");
84775115Sfenner				cp++;
84875115Sfenner				printf(", \"");
84975115Sfenner				while (cp < ep) {
85075115Sfenner					safeputchar(*cp);
85175115Sfenner					cp++;
85275115Sfenner				}
85375115Sfenner				printf("\"");
85475115Sfenner			} else
85575115Sfenner				dnsname_print(cp, ep);
85675115Sfenner			break;
85775115Sfenner		case ICMP6_NI_SUBJ_IPV4:
85875115Sfenner			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
85975115Sfenner				break;
86075115Sfenner			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
86175115Sfenner				if (vflag)
86275115Sfenner					printf(", invalid subject len");
86375115Sfenner				break;
86475115Sfenner			}
86575115Sfenner			printf(", subject=%s",
86675115Sfenner			    getname((const u_char *)(ni6 + 1)));
86775115Sfenner			break;
86875115Sfenner		default:
86975115Sfenner			printf(", unknown subject");
87075115Sfenner			break;
87175115Sfenner		}
87275115Sfenner
87375115Sfenner		/*(*/
87475115Sfenner		printf(")");
87575115Sfenner		break;
87675115Sfenner
87775115Sfenner	case ICMP6_NI_REPLY:
87875115Sfenner		if (icmp6len > siz) {
87975115Sfenner			printf("[|icmp6: node information reply]");
88075115Sfenner			break;
88175115Sfenner		}
88275115Sfenner
88375115Sfenner		needcomma = 0;
88475115Sfenner
88575115Sfenner		ni6 = (struct icmp6_nodeinfo *)dp;
88675115Sfenner		printf("icmp6: node information reply");
88775115Sfenner		printf(" (");	/*)*/
88875115Sfenner		switch (ni6->ni_code) {
88975115Sfenner		case ICMP6_NI_SUCCESS:
89075115Sfenner			if (vflag) {
89175115Sfenner				printf("success");
89275115Sfenner				needcomma++;
89375115Sfenner			}
89475115Sfenner			break;
89575115Sfenner		case ICMP6_NI_REFUSED:
89675115Sfenner			printf("refused");
89775115Sfenner			needcomma++;
89875115Sfenner			if (siz != sizeof(*ni6))
89975115Sfenner				if (vflag)
90075115Sfenner					printf(", invalid length");
90175115Sfenner			break;
90275115Sfenner		case ICMP6_NI_UNKNOWN:
90375115Sfenner			printf("unknown");
90475115Sfenner			needcomma++;
90575115Sfenner			if (siz != sizeof(*ni6))
90675115Sfenner				if (vflag)
90775115Sfenner					printf(", invalid length");
90875115Sfenner			break;
90975115Sfenner		}
91075115Sfenner
91175115Sfenner		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
91275115Sfenner			/*(*/
91375115Sfenner			printf(")");
91475115Sfenner			break;
91575115Sfenner		}
91675115Sfenner
917127668Sbms		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
91875115Sfenner		case NI_QTYPE_NOOP:
91975115Sfenner			if (needcomma)
92075115Sfenner				printf(", ");
92175115Sfenner			printf("noop");
92275115Sfenner			if (siz != sizeof(*ni6))
92375115Sfenner				if (vflag)
92475115Sfenner					printf(", invalid length");
92575115Sfenner			break;
92675115Sfenner		case NI_QTYPE_SUPTYPES:
92775115Sfenner			if (needcomma)
92875115Sfenner				printf(", ");
92975115Sfenner			printf("supported qtypes");
930127668Sbms			i = EXTRACT_16BITS(&ni6->ni_flags);
93175115Sfenner			if (i)
93275115Sfenner				printf(" [%s]", (i & 0x01) ? "C" : "");
93375115Sfenner			break;
93475115Sfenner		case NI_QTYPE_FQDN:
93575115Sfenner			if (needcomma)
93675115Sfenner				printf(", ");
93775115Sfenner			printf("DNS name");
93875115Sfenner			cp = (const u_char *)(ni6 + 1) + 4;
93975115Sfenner			if (cp[0] == ep - cp - 1) {
94075115Sfenner				/* icmp-name-lookup-03, pascal string */
94175115Sfenner				if (vflag)
94275115Sfenner					printf(", 03 draft");
94375115Sfenner				cp++;
94475115Sfenner				printf(", \"");
94575115Sfenner				while (cp < ep) {
94675115Sfenner					safeputchar(*cp);
94775115Sfenner					cp++;
94875115Sfenner				}
94975115Sfenner				printf("\"");
95075115Sfenner			} else
95175115Sfenner				dnsname_print(cp, ep);
952127668Sbms			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
95375115Sfenner				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
95475115Sfenner			break;
95575115Sfenner		case NI_QTYPE_NODEADDR:
95675115Sfenner			if (needcomma)
95775115Sfenner				printf(", ");
95875115Sfenner			printf("node addresses");
95975115Sfenner			i = sizeof(*ni6);
96075115Sfenner			while (i < siz) {
96175115Sfenner				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
96275115Sfenner					break;
96375115Sfenner				printf(" %s", getname6(bp + i));
96475115Sfenner				i += sizeof(struct in6_addr);
965127668Sbms				printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
96675115Sfenner				i += sizeof(int32_t);
96775115Sfenner			}
96875115Sfenner			i = ni6->ni_flags;
96975115Sfenner			if (!i)
97075115Sfenner				break;
97175115Sfenner			printf(" [%s%s%s%s%s%s%s]",
97275115Sfenner			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
97375115Sfenner			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
97475115Sfenner			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
97575115Sfenner			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
97675115Sfenner			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
97775115Sfenner			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
97875115Sfenner			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
97975115Sfenner			break;
98075115Sfenner		default:
98175115Sfenner			if (needcomma)
98275115Sfenner				printf(", ");
98375115Sfenner			printf("unknown");
98475115Sfenner			break;
98575115Sfenner		}
98675115Sfenner
98775115Sfenner		/*(*/
98875115Sfenner		printf(")");
98975115Sfenner		break;
99075115Sfenner	}
99156893Sfenner	return;
99275115Sfenner
99375115Sfennertrunc:
99475115Sfenner	fputs("[|icmp6]", stdout);
99556893Sfenner}
99675115Sfenner
997127668Sbmsstatic void
998127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep)
99975115Sfenner{
100075115Sfenner	struct icmp6_router_renum *rr6;
100175115Sfenner	struct icmp6_hdr *dp;
100275115Sfenner	size_t siz;
100375115Sfenner	const char *cp;
100475115Sfenner	struct rr_pco_match *match;
100575115Sfenner	struct rr_pco_use *use;
100675115Sfenner	char hbuf[NI_MAXHOST];
100775115Sfenner	int n;
100875115Sfenner
1009127668Sbms	if (ep < bp)
1010127668Sbms		return;
101175115Sfenner	dp = (struct icmp6_hdr *)bp;
101275115Sfenner	rr6 = (struct icmp6_router_renum *)bp;
101375115Sfenner	siz = ep - bp;
101475115Sfenner	cp = (const char *)(rr6 + 1);
101575115Sfenner
101675115Sfenner	TCHECK(rr6->rr_reserved);
101775115Sfenner	switch (rr6->rr_code) {
101875115Sfenner	case ICMP6_ROUTER_RENUMBERING_COMMAND:
101975115Sfenner		printf("router renum: command");
102075115Sfenner		break;
102175115Sfenner	case ICMP6_ROUTER_RENUMBERING_RESULT:
102275115Sfenner		printf("router renum: result");
102375115Sfenner		break;
102475115Sfenner	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
102575115Sfenner		printf("router renum: sequence number reset");
102675115Sfenner		break;
102775115Sfenner	default:
102875115Sfenner		printf("router renum: code-#%d", rr6->rr_code);
102975115Sfenner		break;
103075115Sfenner	}
103175115Sfenner
1032127668Sbms	printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
103375115Sfenner
103475115Sfenner	if (vflag) {
103575115Sfenner#define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
103675115Sfenner		printf("[");	/*]*/
103775115Sfenner		if (rr6->rr_flags) {
103875115Sfenner			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
103975115Sfenner			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
104098524Sfenner			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
104175115Sfenner			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
104275115Sfenner			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
104375115Sfenner		}
104475115Sfenner		printf("seg=%u,", rr6->rr_segnum);
104575115Sfenner		printf("maxdelay=%u", rr6->rr_maxdelay);
104675115Sfenner		if (rr6->rr_reserved)
1047127668Sbms			printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
104875115Sfenner		/*[*/
104975115Sfenner		printf("]");
105075115Sfenner#undef F
105175115Sfenner	}
105275115Sfenner
105375115Sfenner	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
105475115Sfenner		match = (struct rr_pco_match *)cp;
105575115Sfenner		cp = (const char *)(match + 1);
105675115Sfenner
105775115Sfenner		TCHECK(match->rpm_prefix);
105875115Sfenner
105998524Sfenner		if (vflag > 1)
106075115Sfenner			printf("\n\t");
106175115Sfenner		else
106275115Sfenner			printf(" ");
106375115Sfenner		printf("match(");	/*)*/
106475115Sfenner		switch (match->rpm_code) {
106575115Sfenner		case RPM_PCO_ADD:	printf("add"); break;
106675115Sfenner		case RPM_PCO_CHANGE:	printf("change"); break;
106775115Sfenner		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
106875115Sfenner		default:		printf("#%u", match->rpm_code); break;
106975115Sfenner		}
107075115Sfenner
107175115Sfenner		if (vflag) {
107275115Sfenner			printf(",ord=%u", match->rpm_ordinal);
107375115Sfenner			printf(",min=%u", match->rpm_minlen);
107475115Sfenner			printf(",max=%u", match->rpm_maxlen);
107575115Sfenner		}
107675115Sfenner		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
107775115Sfenner			printf(",%s/%u", hbuf, match->rpm_matchlen);
107875115Sfenner		else
107975115Sfenner			printf(",?/%u", match->rpm_matchlen);
108075115Sfenner		/*(*/
108175115Sfenner		printf(")");
108275115Sfenner
108375115Sfenner		n = match->rpm_len - 3;
108475115Sfenner		if (n % 4)
108575115Sfenner			goto trunc;
108675115Sfenner		n /= 4;
108775115Sfenner		while (n-- > 0) {
108875115Sfenner			use = (struct rr_pco_use *)cp;
108975115Sfenner			cp = (const char *)(use + 1);
109075115Sfenner
109175115Sfenner			TCHECK(use->rpu_prefix);
109275115Sfenner
109398524Sfenner			if (vflag > 1)
109475115Sfenner				printf("\n\t");
109575115Sfenner			else
109675115Sfenner				printf(" ");
109775115Sfenner			printf("use(");	/*)*/
109875115Sfenner			if (use->rpu_flags) {
109975115Sfenner#define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
110075115Sfenner				printf("%s%s,",
110175115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
110275115Sfenner				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
110375115Sfenner#undef F
110475115Sfenner			}
110575115Sfenner			if (vflag) {
110675115Sfenner				printf("mask=0x%x,", use->rpu_ramask);
110775115Sfenner				printf("raflags=0x%x,", use->rpu_raflags);
110875115Sfenner				if (~use->rpu_vltime == 0)
110975115Sfenner					printf("vltime=infty,");
111075115Sfenner				else
111175115Sfenner					printf("vltime=%u,",
1112127668Sbms					    EXTRACT_32BITS(&use->rpu_vltime));
111375115Sfenner				if (~use->rpu_pltime == 0)
111475115Sfenner					printf("pltime=infty,");
111575115Sfenner				else
111675115Sfenner					printf("pltime=%u,",
1117127668Sbms					    EXTRACT_32BITS(&use->rpu_pltime));
111875115Sfenner			}
111975115Sfenner			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
112075115Sfenner			    sizeof(hbuf)))
112175115Sfenner				printf("%s/%u/%u", hbuf, use->rpu_uselen,
112275115Sfenner				    use->rpu_keeplen);
112375115Sfenner			else
112475115Sfenner				printf("?/%u/%u", use->rpu_uselen,
112575115Sfenner				    use->rpu_keeplen);
112675115Sfenner			/*(*/
112775115Sfenner			printf(")");
112875115Sfenner		}
112975115Sfenner	}
113075115Sfenner
113175115Sfenner	return;
113275115Sfenner
113375115Sfennertrunc:
113475115Sfenner	fputs("[|icmp6]", stdout);
113575115Sfenner}
113675115Sfenner
113756893Sfenner#endif /* INET6 */
1138