xref: /freebsd/contrib/tcpdump/print-icmp6.c (revision a90e161be323456b08b7fe13acb201536809510f)
1b0453382SBill Fenner /*
2b0453382SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
3b0453382SBill Fenner  *	The Regents of the University of California.  All rights reserved.
4b0453382SBill Fenner  *
5b0453382SBill Fenner  * Redistribution and use in source and binary forms, with or without
6b0453382SBill Fenner  * modification, are permitted provided that: (1) source code distributions
7b0453382SBill Fenner  * retain the above copyright notice and this paragraph in its entirety, (2)
8b0453382SBill Fenner  * distributions including binary code include the above copyright notice and
9b0453382SBill Fenner  * this paragraph in its entirety in the documentation or other materials
10b0453382SBill Fenner  * provided with the distribution, and (3) all advertising materials mentioning
11b0453382SBill Fenner  * features or use of this software display the following acknowledgement:
12b0453382SBill Fenner  * ``This product includes software developed by the University of California,
13b0453382SBill Fenner  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14b0453382SBill Fenner  * the University nor the names of its contributors may be used to endorse
15b0453382SBill Fenner  * or promote products derived from this software without specific prior
16b0453382SBill Fenner  * written permission.
17b0453382SBill Fenner  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18b0453382SBill Fenner  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19b0453382SBill Fenner  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20b0453382SBill Fenner  */
21b0453382SBill Fenner 
22b0453382SBill Fenner #ifndef lint
23b0453382SBill Fenner static const char rcsid[] =
24a90e161bSBill Fenner     "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.56 2001/06/27 02:48:43 itojun Exp $";
25b0453382SBill Fenner #endif
26b0453382SBill Fenner 
27b0453382SBill Fenner #ifdef HAVE_CONFIG_H
28b0453382SBill Fenner #include "config.h"
29b0453382SBill Fenner #endif
30b0453382SBill Fenner 
31b0453382SBill Fenner #ifdef INET6
32b0453382SBill Fenner 
33b0453382SBill Fenner #include <ctype.h>
34b0453382SBill Fenner 
35b0453382SBill Fenner #include <sys/param.h>
36b0453382SBill Fenner #include <sys/time.h>
37b0453382SBill Fenner #include <sys/types.h>
38b0453382SBill Fenner #include <sys/socket.h>
39b0453382SBill Fenner 
40b0453382SBill Fenner 
41b0453382SBill Fenner #include <netinet/in.h>
42b0453382SBill Fenner 
43b0453382SBill Fenner #include <arpa/inet.h>
44b0453382SBill Fenner 
45b0453382SBill Fenner #include <stdio.h>
46a90e161bSBill Fenner #include <string.h>
47685295f4SBill Fenner #include <netdb.h>
48b0453382SBill Fenner 
49685295f4SBill Fenner #include "ip6.h"
50685295f4SBill Fenner #include "icmp6.h"
51b0453382SBill Fenner 
52b0453382SBill Fenner #include "interface.h"
53b0453382SBill Fenner #include "addrtoname.h"
54b0453382SBill Fenner 
55685295f4SBill Fenner #include "udp.h"
56685295f4SBill Fenner #include "ah.h"
57685295f4SBill Fenner 
58a90e161bSBill Fenner static const char *get_rtpref(u_int);
59a90e161bSBill Fenner static const char *get_lifetime(u_int32_t);
60a90e161bSBill Fenner static void print_lladdr(const u_char *, size_t);
61b0453382SBill Fenner void icmp6_opt_print(const u_char *, int);
62b0453382SBill Fenner void mld6_print(const u_char *);
63685295f4SBill Fenner static struct udphdr *get_upperlayer(u_char *, int *);
64685295f4SBill Fenner static void dnsname_print(const u_char *, const u_char *);
65685295f4SBill Fenner void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
66685295f4SBill Fenner void icmp6_rrenum_print(int, const u_char *, const u_char *);
67685295f4SBill Fenner 
68685295f4SBill Fenner #ifndef abs
69685295f4SBill Fenner #define abs(a)	((0 < (a)) ? (a) : -(a))
70685295f4SBill Fenner #endif
71b0453382SBill Fenner 
72a90e161bSBill Fenner static const char *
73a90e161bSBill Fenner get_rtpref(u_int v)
74a90e161bSBill Fenner {
75a90e161bSBill Fenner 	static const char *rtpref_str[] = {
76a90e161bSBill Fenner 		"medium",		/* 00 */
77a90e161bSBill Fenner 		"high",			/* 01 */
78a90e161bSBill Fenner 		"rsv",			/* 10 */
79a90e161bSBill Fenner 		"low"			/* 11 */
80a90e161bSBill Fenner 	};
81a90e161bSBill Fenner 
82a90e161bSBill Fenner 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
83a90e161bSBill Fenner }
84a90e161bSBill Fenner 
85a90e161bSBill Fenner static const char *
86a90e161bSBill Fenner get_lifetime(u_int32_t v)
87a90e161bSBill Fenner {
88a90e161bSBill Fenner 	static char buf[20];
89a90e161bSBill Fenner 
90a90e161bSBill Fenner 	if (v == (u_int32_t)~0UL)
91a90e161bSBill Fenner 		return "infinity";
92a90e161bSBill Fenner 	else {
93a90e161bSBill Fenner 		snprintf(buf, sizeof(buf), "%u", v);
94a90e161bSBill Fenner 		return buf;
95a90e161bSBill Fenner 	}
96a90e161bSBill Fenner }
97a90e161bSBill Fenner 
98a90e161bSBill Fenner static void
99a90e161bSBill Fenner print_lladdr(const u_int8_t *p, size_t l)
100a90e161bSBill Fenner {
101a90e161bSBill Fenner 	const u_int8_t *ep, *q;
102a90e161bSBill Fenner 
103a90e161bSBill Fenner 	q = p;
104a90e161bSBill Fenner 	ep = p + l;
105a90e161bSBill Fenner 	while (l > 0 && q < ep) {
106a90e161bSBill Fenner 		if (q > p)
107a90e161bSBill Fenner 			printf(":");
108a90e161bSBill Fenner 		printf("%02x", *q++);
109a90e161bSBill Fenner 		l--;
110a90e161bSBill Fenner 	}
111a90e161bSBill Fenner }
112a90e161bSBill Fenner 
113b0453382SBill Fenner void
114a90e161bSBill Fenner icmp6_print(const u_char *bp, const u_char *bp2)
115b0453382SBill Fenner {
116685295f4SBill Fenner 	const struct icmp6_hdr *dp;
117a90e161bSBill Fenner 	const struct ip6_hdr *ip;
118a90e161bSBill Fenner 	const char *str;
119a90e161bSBill Fenner 	const struct ip6_hdr *oip;
120a90e161bSBill Fenner 	const struct udphdr *ouh;
121a90e161bSBill Fenner 	int dport;
122a90e161bSBill Fenner 	const u_char *ep;
123b0453382SBill Fenner 	char buf[256];
124685295f4SBill Fenner 	int icmp6len, prot;
125b0453382SBill Fenner 
126b0453382SBill Fenner 	dp = (struct icmp6_hdr *)bp;
127b0453382SBill Fenner 	ip = (struct ip6_hdr *)bp2;
128b0453382SBill Fenner 	oip = (struct ip6_hdr *)(dp + 1);
129b0453382SBill Fenner 	str = buf;
130685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
131b0453382SBill Fenner 	ep = snapend;
132b0453382SBill Fenner 	if (ip->ip6_plen)
133b0453382SBill Fenner 		icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
134b0453382SBill Fenner 			    (bp - bp2));
135b0453382SBill Fenner 	else			/* XXX: jumbo payload case... */
136b0453382SBill Fenner 		icmp6len = snapend - bp;
137b0453382SBill Fenner 
138b0453382SBill Fenner 	TCHECK(dp->icmp6_code);
139b0453382SBill Fenner 	switch (dp->icmp6_type) {
140b0453382SBill Fenner 	case ICMP6_DST_UNREACH:
141b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
142b0453382SBill Fenner 		switch (dp->icmp6_code) {
143b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOROUTE:
144b0453382SBill Fenner 			printf("icmp6: %s unreachable route",
145b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
146b0453382SBill Fenner 			break;
147b0453382SBill Fenner 		case ICMP6_DST_UNREACH_ADMIN:
148b0453382SBill Fenner 			printf("icmp6: %s unreachable prohibited",
149b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
150b0453382SBill Fenner 			break;
151b0453382SBill Fenner 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
152b0453382SBill Fenner 			printf("icmp6: %s beyond scope of source address %s",
153b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst),
154b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_src));
155b0453382SBill Fenner 			break;
156b0453382SBill Fenner 		case ICMP6_DST_UNREACH_ADDR:
157b0453382SBill Fenner 			printf("icmp6: %s unreachable address",
158b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
159b0453382SBill Fenner 			break;
160b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOPORT:
161685295f4SBill Fenner 			if ((ouh = get_upperlayer((u_char *)oip, &prot))
162685295f4SBill Fenner 			    == NULL)
163685295f4SBill Fenner 				goto trunc;
164685295f4SBill Fenner 
165b0453382SBill Fenner 			dport = ntohs(ouh->uh_dport);
166685295f4SBill Fenner 			switch (prot) {
167b0453382SBill Fenner 			case IPPROTO_TCP:
168b0453382SBill Fenner 				printf("icmp6: %s tcp port %s unreachable",
169b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
170b0453382SBill Fenner 					tcpport_string(dport));
171b0453382SBill Fenner 				break;
172b0453382SBill Fenner 			case IPPROTO_UDP:
173b0453382SBill Fenner 				printf("icmp6: %s udp port %s unreachable",
174b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
175b0453382SBill Fenner 					udpport_string(dport));
176b0453382SBill Fenner 				break;
177b0453382SBill Fenner 			default:
178b0453382SBill Fenner 				printf("icmp6: %s protocol %d port %d unreachable",
179b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
180b0453382SBill Fenner 					oip->ip6_nxt, dport);
181b0453382SBill Fenner 				break;
182b0453382SBill Fenner 			}
183b0453382SBill Fenner 			break;
184b0453382SBill Fenner 		default:
185b0453382SBill Fenner 			printf("icmp6: %s unreachable code-#%d",
186b0453382SBill Fenner 				ip6addr_string(&oip->ip6_dst),
187b0453382SBill Fenner 				dp->icmp6_code);
188b0453382SBill Fenner 			break;
189b0453382SBill Fenner 		}
190b0453382SBill Fenner 		break;
191b0453382SBill Fenner 	case ICMP6_PACKET_TOO_BIG:
192b0453382SBill Fenner 		TCHECK(dp->icmp6_mtu);
193a90e161bSBill Fenner 		printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu));
194b0453382SBill Fenner 		break;
195b0453382SBill Fenner 	case ICMP6_TIME_EXCEEDED:
196b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
197b0453382SBill Fenner 		switch (dp->icmp6_code) {
198b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_TRANSIT:
199b0453382SBill Fenner 			printf("icmp6: time exceeded in-transit for %s",
200b0453382SBill Fenner 				ip6addr_string(&oip->ip6_dst));
201b0453382SBill Fenner 			break;
202b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_REASSEMBLY:
203b0453382SBill Fenner 			printf("icmp6: ip6 reassembly time exceeded");
204b0453382SBill Fenner 			break;
205b0453382SBill Fenner 		default:
206b0453382SBill Fenner 			printf("icmp6: time exceeded code-#%d",
207b0453382SBill Fenner 				dp->icmp6_code);
208b0453382SBill Fenner 			break;
209b0453382SBill Fenner 		}
210b0453382SBill Fenner 		break;
211b0453382SBill Fenner 	case ICMP6_PARAM_PROB:
212b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
213b0453382SBill Fenner 		switch (dp->icmp6_code) {
214b0453382SBill Fenner 		case ICMP6_PARAMPROB_HEADER:
215a90e161bSBill Fenner 			printf("icmp6: parameter problem errorneous - octet %u",
216b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
217b0453382SBill Fenner 			break;
218b0453382SBill Fenner 		case ICMP6_PARAMPROB_NEXTHEADER:
219a90e161bSBill Fenner 			printf("icmp6: parameter problem next header - octet %u",
220b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
221b0453382SBill Fenner 			break;
222b0453382SBill Fenner 		case ICMP6_PARAMPROB_OPTION:
223a90e161bSBill Fenner 			printf("icmp6: parameter problem option - octet %u",
224b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
225b0453382SBill Fenner 			break;
226b0453382SBill Fenner 		default:
227b0453382SBill Fenner 			printf("icmp6: parameter problem code-#%d",
228b0453382SBill Fenner 			       dp->icmp6_code);
229b0453382SBill Fenner 			break;
230b0453382SBill Fenner 		}
231b0453382SBill Fenner 		break;
232b0453382SBill Fenner 	case ICMP6_ECHO_REQUEST:
233b0453382SBill Fenner 		printf("icmp6: echo request");
234b0453382SBill Fenner 		break;
235b0453382SBill Fenner 	case ICMP6_ECHO_REPLY:
236b0453382SBill Fenner 		printf("icmp6: echo reply");
237b0453382SBill Fenner 		break;
238b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_QUERY:
239b0453382SBill Fenner 		printf("icmp6: multicast listener query ");
240b0453382SBill Fenner 		mld6_print((const u_char *)dp);
241b0453382SBill Fenner 		break;
242b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REPORT:
243b0453382SBill Fenner 		printf("icmp6: multicast listener report ");
244b0453382SBill Fenner 		mld6_print((const u_char *)dp);
245b0453382SBill Fenner 		break;
246b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REDUCTION:
247b0453382SBill Fenner 		printf("icmp6: multicast listener done ");
248b0453382SBill Fenner 		mld6_print((const u_char *)dp);
249b0453382SBill Fenner 		break;
250b0453382SBill Fenner 	case ND_ROUTER_SOLICIT:
251b0453382SBill Fenner 		printf("icmp6: router solicitation ");
252b0453382SBill Fenner 		if (vflag) {
253b0453382SBill Fenner #define RTSOLLEN 8
254b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + RTSOLLEN,
255b0453382SBill Fenner 					icmp6len - RTSOLLEN);
256b0453382SBill Fenner 		}
257b0453382SBill Fenner 		break;
258b0453382SBill Fenner 	case ND_ROUTER_ADVERT:
259b0453382SBill Fenner 		printf("icmp6: router advertisement");
260b0453382SBill Fenner 		if (vflag) {
261b0453382SBill Fenner 			struct nd_router_advert *p;
262b0453382SBill Fenner 
263b0453382SBill Fenner 			p = (struct nd_router_advert *)dp;
264b0453382SBill Fenner 			TCHECK(p->nd_ra_retransmit);
265b0453382SBill Fenner 			printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
266b0453382SBill Fenner 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
267b0453382SBill Fenner 				printf("M");
268b0453382SBill Fenner 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
269b0453382SBill Fenner 				printf("O");
270a90e161bSBill Fenner 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
271685295f4SBill Fenner 				printf("H");
272a90e161bSBill Fenner 
273a90e161bSBill Fenner 			if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
274a90e161bSBill Fenner 			    != 0)
275b0453382SBill Fenner 				printf(" ");
276a90e161bSBill Fenner 
277a90e161bSBill Fenner 			printf("pref=%s, ",
278a90e161bSBill Fenner 			    get_rtpref(p->nd_ra_flags_reserved));
279a90e161bSBill Fenner 
280b0453382SBill Fenner 			printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
281b0453382SBill Fenner 			printf("reachable_time=%u, ",
282b0453382SBill Fenner 				(u_int32_t)ntohl(p->nd_ra_reachable));
283b0453382SBill Fenner 			printf("retrans_time=%u)",
284b0453382SBill Fenner 				(u_int32_t)ntohl(p->nd_ra_retransmit));
285b0453382SBill Fenner #define RTADVLEN 16
286b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + RTADVLEN,
287b0453382SBill Fenner 					icmp6len - RTADVLEN);
288b0453382SBill Fenner 		}
289b0453382SBill Fenner 		break;
290b0453382SBill Fenner 	case ND_NEIGHBOR_SOLICIT:
291b0453382SBill Fenner 	    {
292b0453382SBill Fenner 		struct nd_neighbor_solicit *p;
293b0453382SBill Fenner 		p = (struct nd_neighbor_solicit *)dp;
294b0453382SBill Fenner 		TCHECK(p->nd_ns_target);
295b0453382SBill Fenner 		printf("icmp6: neighbor sol: who has %s",
296b0453382SBill Fenner 			ip6addr_string(&p->nd_ns_target));
297b0453382SBill Fenner 		if (vflag) {
298b0453382SBill Fenner #define NDSOLLEN 24
299b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + NDSOLLEN,
300b0453382SBill Fenner 					icmp6len - NDSOLLEN);
301b0453382SBill Fenner 		}
302b0453382SBill Fenner 	    }
303b0453382SBill Fenner 		break;
304b0453382SBill Fenner 	case ND_NEIGHBOR_ADVERT:
305b0453382SBill Fenner 	    {
306b0453382SBill Fenner 		struct nd_neighbor_advert *p;
307b0453382SBill Fenner 
308b0453382SBill Fenner 		p = (struct nd_neighbor_advert *)dp;
309b0453382SBill Fenner 		TCHECK(p->nd_na_target);
310b0453382SBill Fenner 		printf("icmp6: neighbor adv: tgt is %s",
311b0453382SBill Fenner 			ip6addr_string(&p->nd_na_target));
312b0453382SBill Fenner 		if (vflag) {
313b0453382SBill Fenner #define ND_NA_FLAG_ALL	\
314b0453382SBill Fenner 	(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
315b0453382SBill Fenner 			/* we don't need ntohl() here.  see advanced-api-04. */
316b0453382SBill Fenner 			if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
317b0453382SBill Fenner #undef ND_NA_FLAG_ALL
318b0453382SBill Fenner 				u_int32_t flags;
319b0453382SBill Fenner 
320b0453382SBill Fenner 				flags = p->nd_na_flags_reserved;
321b0453382SBill Fenner 				printf("(");
322b0453382SBill Fenner 				if (flags & ND_NA_FLAG_ROUTER)
323b0453382SBill Fenner 					printf("R");
324b0453382SBill Fenner 				if (flags & ND_NA_FLAG_SOLICITED)
325b0453382SBill Fenner 					printf("S");
326b0453382SBill Fenner 				if (flags & ND_NA_FLAG_OVERRIDE)
327b0453382SBill Fenner 					printf("O");
328b0453382SBill Fenner 				printf(")");
329b0453382SBill Fenner 			}
330b0453382SBill Fenner #define NDADVLEN 24
331b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + NDADVLEN,
332b0453382SBill Fenner 					icmp6len - NDADVLEN);
333685295f4SBill Fenner #undef NDADVLEN
334b0453382SBill Fenner 		}
335b0453382SBill Fenner 	    }
336b0453382SBill Fenner 		break;
337b0453382SBill Fenner 	case ND_REDIRECT:
338b0453382SBill Fenner #define RDR(i) ((struct nd_redirect *)(i))
339b0453382SBill Fenner 		TCHECK(RDR(dp)->nd_rd_dst);
340685295f4SBill Fenner 		printf("icmp6: redirect %s",
341685295f4SBill Fenner 		    getname6((const u_char *)&RDR(dp)->nd_rd_dst));
342685295f4SBill Fenner 		printf(" to %s",
343685295f4SBill Fenner 		    getname6((const u_char*)&RDR(dp)->nd_rd_target));
344b0453382SBill Fenner #define REDIRECTLEN 40
345b0453382SBill Fenner 		if (vflag) {
346b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
347b0453382SBill Fenner 					icmp6len - REDIRECTLEN);
348b0453382SBill Fenner 		}
349b0453382SBill Fenner 		break;
350685295f4SBill Fenner #undef REDIRECTLEN
351685295f4SBill Fenner #undef RDR
352b0453382SBill Fenner 	case ICMP6_ROUTER_RENUMBERING:
353685295f4SBill Fenner 		icmp6_rrenum_print(icmp6len, bp, ep);
354b0453382SBill Fenner 		break;
355685295f4SBill Fenner 	case ICMP6_NI_QUERY:
356685295f4SBill Fenner 	case ICMP6_NI_REPLY:
357685295f4SBill Fenner 		icmp6_nodeinfo_print(icmp6len, bp, ep);
358b0453382SBill Fenner 		break;
359b0453382SBill Fenner 	default:
360b0453382SBill Fenner 		printf("icmp6: type-#%d", dp->icmp6_type);
361b0453382SBill Fenner 		break;
362b0453382SBill Fenner 	}
363b0453382SBill Fenner 	return;
364b0453382SBill Fenner trunc:
365b0453382SBill Fenner 	fputs("[|icmp6]", stdout);
366b0453382SBill Fenner }
367b0453382SBill Fenner 
368685295f4SBill Fenner static struct udphdr *
369a90e161bSBill Fenner get_upperlayer(u_char *bp, int *prot)
370685295f4SBill Fenner {
371a90e161bSBill Fenner 	const u_char *ep;
372685295f4SBill Fenner 	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
373685295f4SBill Fenner 	struct udphdr *uh;
374685295f4SBill Fenner 	struct ip6_hbh *hbh;
375685295f4SBill Fenner 	struct ip6_frag *fragh;
376685295f4SBill Fenner 	struct ah *ah;
377685295f4SBill Fenner 	int nh, hlen;
378685295f4SBill Fenner 
379685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
380685295f4SBill Fenner 	ep = snapend;
381685295f4SBill Fenner 
382685295f4SBill Fenner 	if (TTEST(ip6->ip6_nxt) == 0)
383685295f4SBill Fenner 		return NULL;
384685295f4SBill Fenner 
385685295f4SBill Fenner 	nh = ip6->ip6_nxt;
386685295f4SBill Fenner 	hlen = sizeof(struct ip6_hdr);
387685295f4SBill Fenner 
388685295f4SBill Fenner 	while (bp < snapend) {
389685295f4SBill Fenner 		bp += hlen;
390685295f4SBill Fenner 
391685295f4SBill Fenner 		switch(nh) {
392685295f4SBill Fenner 		case IPPROTO_UDP:
393685295f4SBill Fenner 		case IPPROTO_TCP:
394685295f4SBill Fenner 			uh = (struct udphdr *)bp;
395685295f4SBill Fenner 			if (TTEST(uh->uh_dport)) {
396685295f4SBill Fenner 				*prot = nh;
397685295f4SBill Fenner 				return(uh);
398685295f4SBill Fenner 			}
399685295f4SBill Fenner 			else
400685295f4SBill Fenner 				return(NULL);
401685295f4SBill Fenner 			/* NOTREACHED */
402685295f4SBill Fenner 
403685295f4SBill Fenner 		case IPPROTO_HOPOPTS:
404685295f4SBill Fenner 		case IPPROTO_DSTOPTS:
405685295f4SBill Fenner 		case IPPROTO_ROUTING:
406685295f4SBill Fenner 			hbh = (struct ip6_hbh *)bp;
407685295f4SBill Fenner 			if (TTEST(hbh->ip6h_len) == 0)
408685295f4SBill Fenner 				return(NULL);
409685295f4SBill Fenner 			nh = hbh->ip6h_nxt;
410685295f4SBill Fenner 			hlen = (hbh->ip6h_len + 1) << 3;
411685295f4SBill Fenner 			break;
412685295f4SBill Fenner 
413685295f4SBill Fenner 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
414685295f4SBill Fenner 			fragh = (struct ip6_frag *)bp;
415685295f4SBill Fenner 			if (TTEST(fragh->ip6f_offlg) == 0)
416685295f4SBill Fenner 				return(NULL);
417685295f4SBill Fenner 			/* fragments with non-zero offset are meaningless */
418685295f4SBill Fenner 			if ((fragh->ip6f_offlg & IP6F_OFF_MASK) != 0)
419685295f4SBill Fenner 				return(NULL);
420685295f4SBill Fenner 			nh = fragh->ip6f_nxt;
421685295f4SBill Fenner 			hlen = sizeof(struct ip6_frag);
422685295f4SBill Fenner 			break;
423685295f4SBill Fenner 
424685295f4SBill Fenner 		case IPPROTO_AH:
425685295f4SBill Fenner 			ah = (struct ah *)bp;
426685295f4SBill Fenner 			if (TTEST(ah->ah_len) == 0)
427685295f4SBill Fenner 				return(NULL);
428685295f4SBill Fenner 			nh = ah->ah_nxt;
429685295f4SBill Fenner 			hlen = (ah->ah_len + 2) << 2;
430685295f4SBill Fenner 			break;
431685295f4SBill Fenner 
432685295f4SBill Fenner 		default:	/* unknown or undecodable header */
433685295f4SBill Fenner 			*prot = nh; /* meaningless, but set here anyway */
434685295f4SBill Fenner 			return(NULL);
435685295f4SBill Fenner 		}
436685295f4SBill Fenner 	}
437685295f4SBill Fenner 
438685295f4SBill Fenner 	return(NULL);		/* should be notreached, though */
439685295f4SBill Fenner }
440685295f4SBill Fenner 
441b0453382SBill Fenner void
442a90e161bSBill Fenner icmp6_opt_print(const u_char *bp, int resid)
443b0453382SBill Fenner {
444a90e161bSBill Fenner 	const struct nd_opt_hdr *op;
445a90e161bSBill Fenner 	const struct nd_opt_hdr *opl;	/* why there's no struct? */
446a90e161bSBill Fenner 	const struct nd_opt_prefix_info *opp;
447a90e161bSBill Fenner 	const struct icmp6_opts_redirect *opr;
448a90e161bSBill Fenner 	const struct nd_opt_mtu *opm;
449a90e161bSBill Fenner 	const struct nd_opt_advinterval *opa;
450a90e161bSBill Fenner 	const struct nd_opt_route_info *opri;
451a90e161bSBill Fenner 	const u_char *cp, *ep;
452a90e161bSBill Fenner 	struct in6_addr in6, *in6p;
453a90e161bSBill Fenner 	size_t l;
454b0453382SBill Fenner 
455b0453382SBill Fenner #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
456b0453382SBill Fenner 
457a90e161bSBill Fenner 	cp = bp;
458685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
459b0453382SBill Fenner 	ep = snapend;
460b0453382SBill Fenner 
461a90e161bSBill Fenner 	while (cp < ep) {
462a90e161bSBill Fenner 		op = (struct nd_opt_hdr *)cp;
463a90e161bSBill Fenner 
464b0453382SBill Fenner 		ECHECK(op->nd_opt_len);
465b0453382SBill Fenner 		if (resid <= 0)
466b0453382SBill Fenner 			return;
467a90e161bSBill Fenner 		if (op->nd_opt_len == 0)
468a90e161bSBill Fenner 			goto trunc;
469a90e161bSBill Fenner 		if (cp + (op->nd_opt_len << 3) > ep)
470a90e161bSBill Fenner 			goto trunc;
471a90e161bSBill Fenner 
472b0453382SBill Fenner 		switch (op->nd_opt_type) {
473b0453382SBill Fenner 		case ND_OPT_SOURCE_LINKADDR:
474b0453382SBill Fenner 			opl = (struct nd_opt_hdr *)op;
475a90e161bSBill Fenner 			printf("(src lladdr: ");
476a90e161bSBill Fenner 			l = (op->nd_opt_len << 3) - 2;
477a90e161bSBill Fenner 			print_lladdr(cp + 2, l);
478685295f4SBill Fenner 			/*(*/
479b0453382SBill Fenner 			printf(")");
480b0453382SBill Fenner 			break;
481b0453382SBill Fenner 		case ND_OPT_TARGET_LINKADDR:
482b0453382SBill Fenner 			opl = (struct nd_opt_hdr *)op;
483a90e161bSBill Fenner 			printf("(tgt lladdr: ");
484a90e161bSBill Fenner 			l = (op->nd_opt_len << 3) - 2;
485a90e161bSBill Fenner 			print_lladdr(cp + 2, l);
486685295f4SBill Fenner 			/*(*/
487b0453382SBill Fenner 			printf(")");
488b0453382SBill Fenner 			break;
489b0453382SBill Fenner 		case ND_OPT_PREFIX_INFORMATION:
490b0453382SBill Fenner 			opp = (struct nd_opt_prefix_info *)op;
491b0453382SBill Fenner 			TCHECK(opp->nd_opt_pi_prefix);
492685295f4SBill Fenner 			printf("(prefix info: ");	/*)*/
493a90e161bSBill Fenner 			if (op->nd_opt_len != 4) {
494a90e161bSBill Fenner 				printf("badlen");
495a90e161bSBill Fenner 				/*(*/
496a90e161bSBill Fenner 				printf(")");
497a90e161bSBill Fenner 				break;
498a90e161bSBill Fenner 			}
499b0453382SBill Fenner 			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
500b0453382SBill Fenner 				printf("L");
501b0453382SBill Fenner 			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
502b0453382SBill Fenner 				printf("A");
503685295f4SBill Fenner 			if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
504685295f4SBill Fenner 				printf("R");
505b0453382SBill Fenner 			if (opp->nd_opt_pi_flags_reserved)
506b0453382SBill Fenner 				printf(" ");
507a90e161bSBill Fenner 			printf("valid_ltime=%s,",
508a90e161bSBill Fenner 			    get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_valid_time)));
509a90e161bSBill Fenner 			printf("preferred_ltime=%s,",
510a90e161bSBill Fenner 			    get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)));
511a90e161bSBill Fenner 			printf("prefix=%s/%d",
512a90e161bSBill Fenner 			    ip6addr_string(&opp->nd_opt_pi_prefix),
513b0453382SBill Fenner 			    opp->nd_opt_pi_prefix_len);
514b0453382SBill Fenner 			if (opp->nd_opt_pi_len != 4)
515b0453382SBill Fenner 				printf("!");
516685295f4SBill Fenner 			/*(*/
517b0453382SBill Fenner 			printf(")");
518b0453382SBill Fenner 			break;
519b0453382SBill Fenner 		case ND_OPT_REDIRECTED_HEADER:
520b0453382SBill Fenner 			opr = (struct icmp6_opts_redirect *)op;
521b0453382SBill Fenner 			printf("(redirect)");
522b0453382SBill Fenner 			/* xxx */
523b0453382SBill Fenner 			break;
524b0453382SBill Fenner 		case ND_OPT_MTU:
525b0453382SBill Fenner 			opm = (struct nd_opt_mtu *)op;
526b0453382SBill Fenner 			TCHECK(opm->nd_opt_mtu_mtu);
527685295f4SBill Fenner 			printf("(mtu:");	/*)*/
528a90e161bSBill Fenner 			if (op->nd_opt_len != 1) {
529a90e161bSBill Fenner 				printf("badlen");
530a90e161bSBill Fenner 				/*(*/
531a90e161bSBill Fenner 				printf(")");
532a90e161bSBill Fenner 				break;
533a90e161bSBill Fenner 			}
534b0453382SBill Fenner 			printf(" mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
535b0453382SBill Fenner 			if (opm->nd_opt_mtu_len != 1)
536b0453382SBill Fenner 				printf("!");
537b0453382SBill Fenner 			printf(")");
538b0453382SBill Fenner 			break;
539a90e161bSBill Fenner 		case ND_OPT_ADVINTERVAL:
540a90e161bSBill Fenner 			opa = (struct nd_opt_advinterval *)op;
541a90e161bSBill Fenner 			TCHECK(opa->nd_opt_adv_interval);
542685295f4SBill Fenner 			printf("(advint:");	/*)*/
543685295f4SBill Fenner 			printf(" advint=%u",
544a90e161bSBill Fenner 			    (u_int32_t)ntohl(opa->nd_opt_adv_interval));
545685295f4SBill Fenner 			/*(*/
546685295f4SBill Fenner 			printf(")");
547a90e161bSBill Fenner 			break;
548a90e161bSBill Fenner 		case ND_OPT_ROUTE_INFO:
549a90e161bSBill Fenner 			opri = (struct nd_opt_route_info *)op;
550a90e161bSBill Fenner 			TCHECK(opri->nd_opt_rti_lifetime);
551a90e161bSBill Fenner 			memset(&in6, 0, sizeof(in6));
552a90e161bSBill Fenner 			in6p = (struct in6_addr *)(opri + 1);
553a90e161bSBill Fenner 			switch (op->nd_opt_len) {
554a90e161bSBill Fenner 			case 1:
555a90e161bSBill Fenner 				break;
556a90e161bSBill Fenner 			case 2:
557a90e161bSBill Fenner 				TCHECK2(*in6p, 8);
558a90e161bSBill Fenner 				memcpy(&in6, opri + 1, 8);
559a90e161bSBill Fenner 				break;
560a90e161bSBill Fenner 			case 3:
561a90e161bSBill Fenner 				TCHECK(*in6p);
562a90e161bSBill Fenner 				memcpy(&in6, opri + 1, sizeof(in6));
563685295f4SBill Fenner 				break;
564b0453382SBill Fenner 			default:
565a90e161bSBill Fenner 				goto trunc;
566a90e161bSBill Fenner 			}
567a90e161bSBill Fenner 			printf("(rtinfo:");	/*)*/
568a90e161bSBill Fenner 			printf(" %s/%u", ip6addr_string(&in6),
569a90e161bSBill Fenner 			    opri->nd_opt_rti_prefixlen);
570a90e161bSBill Fenner 			printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
571a90e161bSBill Fenner 			printf(", lifetime=%s",
572a90e161bSBill Fenner 			    get_lifetime((u_int32_t)ntohl(opri->nd_opt_rti_lifetime)));
573a90e161bSBill Fenner 			/*(*/
574a90e161bSBill Fenner 			printf(")");
575a90e161bSBill Fenner 			break;
576a90e161bSBill Fenner 		default:
577b0453382SBill Fenner 			printf("(unknwon opt_type=%d, opt_len=%d)",
578a90e161bSBill Fenner 			       op->nd_opt_type, op->nd_opt_len);
579b0453382SBill Fenner 			break;
580b0453382SBill Fenner 		}
581a90e161bSBill Fenner 
582a90e161bSBill Fenner 		cp += op->nd_opt_len << 3;
583a90e161bSBill Fenner 		resid -= op->nd_opt_len << 3;
584a90e161bSBill Fenner 	}
585b0453382SBill Fenner 	return;
586a90e161bSBill Fenner 
587b0453382SBill Fenner  trunc:
588b0453382SBill Fenner 	fputs("[ndp opt]", stdout);
589b0453382SBill Fenner 	return;
590b0453382SBill Fenner #undef ECHECK
591b0453382SBill Fenner }
592b0453382SBill Fenner 
593b0453382SBill Fenner void
594a90e161bSBill Fenner mld6_print(const u_char *bp)
595b0453382SBill Fenner {
596a90e161bSBill Fenner 	struct mld6_hdr *mp = (struct mld6_hdr *)bp;
597a90e161bSBill Fenner 	const u_char *ep;
598b0453382SBill Fenner 
599685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
600b0453382SBill Fenner 	ep = snapend;
601b0453382SBill Fenner 
602b0453382SBill Fenner 	if ((u_char *)mp + sizeof(*mp) > ep)
603b0453382SBill Fenner 		return;
604b0453382SBill Fenner 
605b0453382SBill Fenner 	printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
606b0453382SBill Fenner 	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
607685295f4SBill Fenner }
608685295f4SBill Fenner 
609685295f4SBill Fenner static void
610685295f4SBill Fenner dnsname_print(const u_char *cp, const u_char *ep)
611685295f4SBill Fenner {
612685295f4SBill Fenner 	int i;
613685295f4SBill Fenner 
614685295f4SBill Fenner 	/* DNS name decoding - no decompression */
615685295f4SBill Fenner 	printf(", \"");
616685295f4SBill Fenner 	while (cp < ep) {
617685295f4SBill Fenner 		i = *cp++;
618685295f4SBill Fenner 		if (i) {
619685295f4SBill Fenner 			if (i > ep - cp) {
620685295f4SBill Fenner 				printf("???");
621685295f4SBill Fenner 				break;
622685295f4SBill Fenner 			}
623685295f4SBill Fenner 			while (i-- && cp < ep) {
624685295f4SBill Fenner 				safeputchar(*cp);
625685295f4SBill Fenner 				cp++;
626685295f4SBill Fenner 			}
627685295f4SBill Fenner 			if (cp + 1 < ep && *cp)
628685295f4SBill Fenner 				printf(".");
629685295f4SBill Fenner 		} else {
630685295f4SBill Fenner 			if (cp == ep) {
631685295f4SBill Fenner 				/* FQDN */
632685295f4SBill Fenner 				printf(".");
633685295f4SBill Fenner 			} else if (cp + 1 == ep && *cp == '\0') {
634685295f4SBill Fenner 				/* truncated */
635685295f4SBill Fenner 			} else {
636685295f4SBill Fenner 				/* invalid */
637685295f4SBill Fenner 				printf("???");
638685295f4SBill Fenner 			}
639685295f4SBill Fenner 			break;
640685295f4SBill Fenner 		}
641685295f4SBill Fenner 	}
642685295f4SBill Fenner 	printf("\"");
643685295f4SBill Fenner }
644685295f4SBill Fenner 
645685295f4SBill Fenner void
646685295f4SBill Fenner icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
647685295f4SBill Fenner {
648685295f4SBill Fenner 	struct icmp6_nodeinfo *ni6;
649685295f4SBill Fenner 	struct icmp6_hdr *dp;
650685295f4SBill Fenner 	const u_char *cp;
651685295f4SBill Fenner 	int siz, i;
652685295f4SBill Fenner 	int needcomma;
653685295f4SBill Fenner 
654685295f4SBill Fenner 	dp = (struct icmp6_hdr *)bp;
655685295f4SBill Fenner 	ni6 = (struct icmp6_nodeinfo *)bp;
656685295f4SBill Fenner 	siz = ep - bp;
657685295f4SBill Fenner 
658685295f4SBill Fenner 	switch (ni6->ni_type) {
659685295f4SBill Fenner 	case ICMP6_NI_QUERY:
660685295f4SBill Fenner 		if (siz == sizeof(*dp) + 4) {
661685295f4SBill Fenner 			/* KAME who-are-you */
662685295f4SBill Fenner 			printf("icmp6: who-are-you request");
663685295f4SBill Fenner 			break;
664685295f4SBill Fenner 		}
665685295f4SBill Fenner 		printf("icmp6: node information query");
666685295f4SBill Fenner 
667685295f4SBill Fenner 		TCHECK2(*dp, sizeof(*ni6));
668685295f4SBill Fenner 		ni6 = (struct icmp6_nodeinfo *)dp;
669685295f4SBill Fenner 		printf(" (");	/*)*/
670685295f4SBill Fenner 		switch (ntohs(ni6->ni_qtype)) {
671685295f4SBill Fenner 		case NI_QTYPE_NOOP:
672685295f4SBill Fenner 			printf("noop");
673685295f4SBill Fenner 			break;
674685295f4SBill Fenner 		case NI_QTYPE_SUPTYPES:
675685295f4SBill Fenner 			printf("supported qtypes");
676685295f4SBill Fenner 			i = ntohs(ni6->ni_flags);
677685295f4SBill Fenner 			if (i)
678685295f4SBill Fenner 				printf(" [%s]", (i & 0x01) ? "C" : "");
679685295f4SBill Fenner 			break;
680685295f4SBill Fenner 			break;
681685295f4SBill Fenner 		case NI_QTYPE_FQDN:
682685295f4SBill Fenner 			printf("DNS name");
683685295f4SBill Fenner 			break;
684685295f4SBill Fenner 		case NI_QTYPE_NODEADDR:
685685295f4SBill Fenner 			printf("node addresses");
686685295f4SBill Fenner 			i = ni6->ni_flags;
687685295f4SBill Fenner 			if (!i)
688685295f4SBill Fenner 				break;
689685295f4SBill Fenner 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
690685295f4SBill Fenner 			printf(" [%s%s%s%s%s%s]",
691685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
692685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
693685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
694685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
695685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
696685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
697685295f4SBill Fenner 			break;
698685295f4SBill Fenner 		default:
699685295f4SBill Fenner 			printf("unknown");
700685295f4SBill Fenner 			break;
701685295f4SBill Fenner 		}
702685295f4SBill Fenner 
703685295f4SBill Fenner 		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
704685295f4SBill Fenner 		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
705685295f4SBill Fenner 			if (siz != sizeof(*ni6))
706685295f4SBill Fenner 				if (vflag)
707685295f4SBill Fenner 					printf(", invalid len");
708685295f4SBill Fenner 			/*(*/
709685295f4SBill Fenner 			printf(")");
710685295f4SBill Fenner 			break;
711685295f4SBill Fenner 		}
712685295f4SBill Fenner 
713685295f4SBill Fenner 
714685295f4SBill Fenner 		/* XXX backward compat, icmp-name-lookup-03 */
715685295f4SBill Fenner 		if (siz == sizeof(*ni6)) {
716685295f4SBill Fenner 			printf(", 03 draft");
717685295f4SBill Fenner 			/*(*/
718685295f4SBill Fenner 			printf(")");
719685295f4SBill Fenner 			break;
720685295f4SBill Fenner 		}
721685295f4SBill Fenner 
722685295f4SBill Fenner 		switch (ni6->ni_code) {
723685295f4SBill Fenner 		case ICMP6_NI_SUBJ_IPV6:
724685295f4SBill Fenner 			if (!TTEST2(*dp,
725685295f4SBill Fenner 			    sizeof(*ni6) + sizeof(struct in6_addr)))
726685295f4SBill Fenner 				break;
727685295f4SBill Fenner 			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
728685295f4SBill Fenner 				if (vflag)
729685295f4SBill Fenner 					printf(", invalid subject len");
730685295f4SBill Fenner 				break;
731685295f4SBill Fenner 			}
732685295f4SBill Fenner 			printf(", subject=%s",
733685295f4SBill Fenner 			    getname6((const u_char *)(ni6 + 1)));
734685295f4SBill Fenner 			break;
735685295f4SBill Fenner 		case ICMP6_NI_SUBJ_FQDN:
736685295f4SBill Fenner 			printf(", subject=DNS name");
737685295f4SBill Fenner 			cp = (const u_char *)(ni6 + 1);
738685295f4SBill Fenner 			if (cp[0] == ep - cp - 1) {
739685295f4SBill Fenner 				/* icmp-name-lookup-03, pascal string */
740685295f4SBill Fenner 				if (vflag)
741685295f4SBill Fenner 					printf(", 03 draft");
742685295f4SBill Fenner 				cp++;
743685295f4SBill Fenner 				printf(", \"");
744685295f4SBill Fenner 				while (cp < ep) {
745685295f4SBill Fenner 					safeputchar(*cp);
746685295f4SBill Fenner 					cp++;
747685295f4SBill Fenner 				}
748685295f4SBill Fenner 				printf("\"");
749685295f4SBill Fenner 			} else
750685295f4SBill Fenner 				dnsname_print(cp, ep);
751685295f4SBill Fenner 			break;
752685295f4SBill Fenner 		case ICMP6_NI_SUBJ_IPV4:
753685295f4SBill Fenner 			if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
754685295f4SBill Fenner 				break;
755685295f4SBill Fenner 			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
756685295f4SBill Fenner 				if (vflag)
757685295f4SBill Fenner 					printf(", invalid subject len");
758685295f4SBill Fenner 				break;
759685295f4SBill Fenner 			}
760685295f4SBill Fenner 			printf(", subject=%s",
761685295f4SBill Fenner 			    getname((const u_char *)(ni6 + 1)));
762685295f4SBill Fenner 			break;
763685295f4SBill Fenner 		default:
764685295f4SBill Fenner 			printf(", unknown subject");
765685295f4SBill Fenner 			break;
766685295f4SBill Fenner 		}
767685295f4SBill Fenner 
768685295f4SBill Fenner 		/*(*/
769685295f4SBill Fenner 		printf(")");
770685295f4SBill Fenner 		break;
771685295f4SBill Fenner 
772685295f4SBill Fenner 	case ICMP6_NI_REPLY:
773685295f4SBill Fenner 		if (icmp6len > siz) {
774685295f4SBill Fenner 			printf("[|icmp6: node information reply]");
775685295f4SBill Fenner 			break;
776685295f4SBill Fenner 		}
777685295f4SBill Fenner 
778685295f4SBill Fenner 		needcomma = 0;
779685295f4SBill Fenner 
780685295f4SBill Fenner 		ni6 = (struct icmp6_nodeinfo *)dp;
781685295f4SBill Fenner 		printf("icmp6: node information reply");
782685295f4SBill Fenner 		printf(" (");	/*)*/
783685295f4SBill Fenner 		switch (ni6->ni_code) {
784685295f4SBill Fenner 		case ICMP6_NI_SUCCESS:
785685295f4SBill Fenner 			if (vflag) {
786685295f4SBill Fenner 				printf("success");
787685295f4SBill Fenner 				needcomma++;
788685295f4SBill Fenner 			}
789685295f4SBill Fenner 			break;
790685295f4SBill Fenner 		case ICMP6_NI_REFUSED:
791685295f4SBill Fenner 			printf("refused");
792685295f4SBill Fenner 			needcomma++;
793685295f4SBill Fenner 			if (siz != sizeof(*ni6))
794685295f4SBill Fenner 				if (vflag)
795685295f4SBill Fenner 					printf(", invalid length");
796685295f4SBill Fenner 			break;
797685295f4SBill Fenner 		case ICMP6_NI_UNKNOWN:
798685295f4SBill Fenner 			printf("unknown");
799685295f4SBill Fenner 			needcomma++;
800685295f4SBill Fenner 			if (siz != sizeof(*ni6))
801685295f4SBill Fenner 				if (vflag)
802685295f4SBill Fenner 					printf(", invalid length");
803685295f4SBill Fenner 			break;
804685295f4SBill Fenner 		}
805685295f4SBill Fenner 
806685295f4SBill Fenner 		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
807685295f4SBill Fenner 			/*(*/
808685295f4SBill Fenner 			printf(")");
809685295f4SBill Fenner 			break;
810685295f4SBill Fenner 		}
811685295f4SBill Fenner 
812685295f4SBill Fenner 		switch (ntohs(ni6->ni_qtype)) {
813685295f4SBill Fenner 		case NI_QTYPE_NOOP:
814685295f4SBill Fenner 			if (needcomma)
815685295f4SBill Fenner 				printf(", ");
816685295f4SBill Fenner 			printf("noop");
817685295f4SBill Fenner 			if (siz != sizeof(*ni6))
818685295f4SBill Fenner 				if (vflag)
819685295f4SBill Fenner 					printf(", invalid length");
820685295f4SBill Fenner 			break;
821685295f4SBill Fenner 		case NI_QTYPE_SUPTYPES:
822685295f4SBill Fenner 			if (needcomma)
823685295f4SBill Fenner 				printf(", ");
824685295f4SBill Fenner 			printf("supported qtypes");
825685295f4SBill Fenner 			i = ntohs(ni6->ni_flags);
826685295f4SBill Fenner 			if (i)
827685295f4SBill Fenner 				printf(" [%s]", (i & 0x01) ? "C" : "");
828685295f4SBill Fenner 			break;
829685295f4SBill Fenner 		case NI_QTYPE_FQDN:
830685295f4SBill Fenner 			if (needcomma)
831685295f4SBill Fenner 				printf(", ");
832685295f4SBill Fenner 			printf("DNS name");
833685295f4SBill Fenner 			cp = (const u_char *)(ni6 + 1) + 4;
834685295f4SBill Fenner 			if (cp[0] == ep - cp - 1) {
835685295f4SBill Fenner 				/* icmp-name-lookup-03, pascal string */
836685295f4SBill Fenner 				if (vflag)
837685295f4SBill Fenner 					printf(", 03 draft");
838685295f4SBill Fenner 				cp++;
839685295f4SBill Fenner 				printf(", \"");
840685295f4SBill Fenner 				while (cp < ep) {
841685295f4SBill Fenner 					safeputchar(*cp);
842685295f4SBill Fenner 					cp++;
843685295f4SBill Fenner 				}
844685295f4SBill Fenner 				printf("\"");
845685295f4SBill Fenner 			} else
846685295f4SBill Fenner 				dnsname_print(cp, ep);
847685295f4SBill Fenner 			if ((ntohs(ni6->ni_flags) & 0x01) != 0)
848685295f4SBill Fenner 				printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
849685295f4SBill Fenner 			break;
850685295f4SBill Fenner 		case NI_QTYPE_NODEADDR:
851685295f4SBill Fenner 			if (needcomma)
852685295f4SBill Fenner 				printf(", ");
853685295f4SBill Fenner 			printf("node addresses");
854685295f4SBill Fenner 			i = sizeof(*ni6);
855685295f4SBill Fenner 			while (i < siz) {
856685295f4SBill Fenner 				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
857685295f4SBill Fenner 					break;
858685295f4SBill Fenner 				printf(" %s", getname6(bp + i));
859685295f4SBill Fenner 				i += sizeof(struct in6_addr);
860a90e161bSBill Fenner 				printf("(%d)", (int32_t)ntohl(*(int32_t *)(bp + i)));
861685295f4SBill Fenner 				i += sizeof(int32_t);
862685295f4SBill Fenner 			}
863685295f4SBill Fenner 			i = ni6->ni_flags;
864685295f4SBill Fenner 			if (!i)
865685295f4SBill Fenner 				break;
866685295f4SBill Fenner 			printf(" [%s%s%s%s%s%s%s]",
867685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
868685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
869685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
870685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
871685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
872685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
873685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
874685295f4SBill Fenner 			break;
875685295f4SBill Fenner 		default:
876685295f4SBill Fenner 			if (needcomma)
877685295f4SBill Fenner 				printf(", ");
878685295f4SBill Fenner 			printf("unknown");
879685295f4SBill Fenner 			break;
880685295f4SBill Fenner 		}
881685295f4SBill Fenner 
882685295f4SBill Fenner 		/*(*/
883685295f4SBill Fenner 		printf(")");
884685295f4SBill Fenner 		break;
885685295f4SBill Fenner 	}
886685295f4SBill Fenner 	return;
887685295f4SBill Fenner 
888685295f4SBill Fenner trunc:
889685295f4SBill Fenner 	fputs("[|icmp6]", stdout);
890685295f4SBill Fenner }
891685295f4SBill Fenner 
892685295f4SBill Fenner void
893685295f4SBill Fenner icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
894685295f4SBill Fenner {
895685295f4SBill Fenner 	struct icmp6_router_renum *rr6;
896685295f4SBill Fenner 	struct icmp6_hdr *dp;
897685295f4SBill Fenner 	size_t siz;
898685295f4SBill Fenner 	const char *cp;
899685295f4SBill Fenner 	struct rr_pco_match *match;
900685295f4SBill Fenner 	struct rr_pco_use *use;
901685295f4SBill Fenner 	char hbuf[NI_MAXHOST];
902685295f4SBill Fenner 	int n;
903685295f4SBill Fenner 
904685295f4SBill Fenner 	dp = (struct icmp6_hdr *)bp;
905685295f4SBill Fenner 	rr6 = (struct icmp6_router_renum *)bp;
906685295f4SBill Fenner 	siz = ep - bp;
907685295f4SBill Fenner 	cp = (const char *)(rr6 + 1);
908685295f4SBill Fenner 
909685295f4SBill Fenner 	TCHECK(rr6->rr_reserved);
910685295f4SBill Fenner 	switch (rr6->rr_code) {
911685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
912685295f4SBill Fenner 		printf("router renum: command");
913685295f4SBill Fenner 		break;
914685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_RESULT:
915685295f4SBill Fenner 		printf("router renum: result");
916685295f4SBill Fenner 		break;
917685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
918685295f4SBill Fenner 		printf("router renum: sequence number reset");
919685295f4SBill Fenner 		break;
920685295f4SBill Fenner 	default:
921685295f4SBill Fenner 		printf("router renum: code-#%d", rr6->rr_code);
922685295f4SBill Fenner 		break;
923685295f4SBill Fenner 	}
924685295f4SBill Fenner 
925685295f4SBill Fenner 	printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum));
926685295f4SBill Fenner 
927685295f4SBill Fenner 	if (vflag) {
928685295f4SBill Fenner #define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
929685295f4SBill Fenner 		printf("[");	/*]*/
930685295f4SBill Fenner 		if (rr6->rr_flags) {
931685295f4SBill Fenner 			printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
932685295f4SBill Fenner 			    F(ICMP6_RR_FLAGS_REQRESULT, "R"),
933a90e161bSBill Fenner 			    F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
934685295f4SBill Fenner 			    F(ICMP6_RR_FLAGS_SPECSITE, "S"),
935685295f4SBill Fenner 			    F(ICMP6_RR_FLAGS_PREVDONE, "P"));
936685295f4SBill Fenner 		}
937685295f4SBill Fenner 		printf("seg=%u,", rr6->rr_segnum);
938685295f4SBill Fenner 		printf("maxdelay=%u", rr6->rr_maxdelay);
939685295f4SBill Fenner 		if (rr6->rr_reserved)
940685295f4SBill Fenner 			printf("rsvd=0x%x", (u_int16_t)ntohs(rr6->rr_reserved));
941685295f4SBill Fenner 		/*[*/
942685295f4SBill Fenner 		printf("]");
943685295f4SBill Fenner #undef F
944685295f4SBill Fenner 	}
945685295f4SBill Fenner 
946685295f4SBill Fenner 	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
947685295f4SBill Fenner 		match = (struct rr_pco_match *)cp;
948685295f4SBill Fenner 		cp = (const char *)(match + 1);
949685295f4SBill Fenner 
950685295f4SBill Fenner 		TCHECK(match->rpm_prefix);
951685295f4SBill Fenner 
952a90e161bSBill Fenner 		if (vflag > 1)
953685295f4SBill Fenner 			printf("\n\t");
954685295f4SBill Fenner 		else
955685295f4SBill Fenner 			printf(" ");
956685295f4SBill Fenner 		printf("match(");	/*)*/
957685295f4SBill Fenner 		switch (match->rpm_code) {
958685295f4SBill Fenner 		case RPM_PCO_ADD:	printf("add"); break;
959685295f4SBill Fenner 		case RPM_PCO_CHANGE:	printf("change"); break;
960685295f4SBill Fenner 		case RPM_PCO_SETGLOBAL:	printf("setglobal"); break;
961685295f4SBill Fenner 		default:		printf("#%u", match->rpm_code); break;
962685295f4SBill Fenner 		}
963685295f4SBill Fenner 
964685295f4SBill Fenner 		if (vflag) {
965685295f4SBill Fenner 			printf(",ord=%u", match->rpm_ordinal);
966685295f4SBill Fenner 			printf(",min=%u", match->rpm_minlen);
967685295f4SBill Fenner 			printf(",max=%u", match->rpm_maxlen);
968685295f4SBill Fenner 		}
969685295f4SBill Fenner 		if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
970685295f4SBill Fenner 			printf(",%s/%u", hbuf, match->rpm_matchlen);
971685295f4SBill Fenner 		else
972685295f4SBill Fenner 			printf(",?/%u", match->rpm_matchlen);
973685295f4SBill Fenner 		/*(*/
974685295f4SBill Fenner 		printf(")");
975685295f4SBill Fenner 
976685295f4SBill Fenner 		n = match->rpm_len - 3;
977685295f4SBill Fenner 		if (n % 4)
978685295f4SBill Fenner 			goto trunc;
979685295f4SBill Fenner 		n /= 4;
980685295f4SBill Fenner 		while (n-- > 0) {
981685295f4SBill Fenner 			use = (struct rr_pco_use *)cp;
982685295f4SBill Fenner 			cp = (const char *)(use + 1);
983685295f4SBill Fenner 
984685295f4SBill Fenner 			TCHECK(use->rpu_prefix);
985685295f4SBill Fenner 
986a90e161bSBill Fenner 			if (vflag > 1)
987685295f4SBill Fenner 				printf("\n\t");
988685295f4SBill Fenner 			else
989685295f4SBill Fenner 				printf(" ");
990685295f4SBill Fenner 			printf("use(");	/*)*/
991685295f4SBill Fenner 			if (use->rpu_flags) {
992685295f4SBill Fenner #define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
993685295f4SBill Fenner 				printf("%s%s,",
994685295f4SBill Fenner 				    F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
995685295f4SBill Fenner 				    F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
996685295f4SBill Fenner #undef F
997685295f4SBill Fenner 			}
998685295f4SBill Fenner 			if (vflag) {
999685295f4SBill Fenner 				printf("mask=0x%x,", use->rpu_ramask);
1000685295f4SBill Fenner 				printf("raflags=0x%x,", use->rpu_raflags);
1001685295f4SBill Fenner 				if (~use->rpu_vltime == 0)
1002685295f4SBill Fenner 					printf("vltime=infty,");
1003685295f4SBill Fenner 				else
1004685295f4SBill Fenner 					printf("vltime=%u,",
1005685295f4SBill Fenner 					    (u_int32_t)ntohl(use->rpu_vltime));
1006685295f4SBill Fenner 				if (~use->rpu_pltime == 0)
1007685295f4SBill Fenner 					printf("pltime=infty,");
1008685295f4SBill Fenner 				else
1009685295f4SBill Fenner 					printf("pltime=%u,",
1010685295f4SBill Fenner 					    (u_int32_t)ntohl(use->rpu_pltime));
1011685295f4SBill Fenner 			}
1012685295f4SBill Fenner 			if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
1013685295f4SBill Fenner 			    sizeof(hbuf)))
1014685295f4SBill Fenner 				printf("%s/%u/%u", hbuf, use->rpu_uselen,
1015685295f4SBill Fenner 				    use->rpu_keeplen);
1016685295f4SBill Fenner 			else
1017685295f4SBill Fenner 				printf("?/%u/%u", use->rpu_uselen,
1018685295f4SBill Fenner 				    use->rpu_keeplen);
1019685295f4SBill Fenner 			/*(*/
1020685295f4SBill Fenner 			printf(")");
1021685295f4SBill Fenner 		}
1022685295f4SBill Fenner 	}
1023b0453382SBill Fenner 
1024b0453382SBill Fenner 	return;
1025685295f4SBill Fenner 
1026685295f4SBill Fenner trunc:
1027685295f4SBill Fenner 	fputs("[|icmp6]", stdout);
1028b0453382SBill Fenner }
1029685295f4SBill Fenner 
1030b0453382SBill Fenner #endif /* INET6 */
1031