xref: /freebsd/contrib/tcpdump/print-icmp6.c (revision b0453382235492c8e30b09659b52d784128ca7d0)
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[] =
24b0453382SBill Fenner     "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.2.2.1 2000/01/11 06:58:24 fenner 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 #include <net/if.h>
41b0453382SBill Fenner 
42b0453382SBill Fenner #include <netinet/in.h>
43b0453382SBill Fenner #include <netinet/if_ether.h>
44b0453382SBill Fenner #include <netinet/in_systm.h>
45b0453382SBill Fenner #include <netinet/ip.h>
46b0453382SBill Fenner #include <netinet/ip_icmp.h>
47b0453382SBill Fenner #include <netinet/ip_var.h>
48b0453382SBill Fenner #include <netinet/udp.h>
49b0453382SBill Fenner #include <netinet/udp_var.h>
50b0453382SBill Fenner #include <netinet/tcp.h>
51b0453382SBill Fenner 
52b0453382SBill Fenner #include <arpa/inet.h>
53b0453382SBill Fenner 
54b0453382SBill Fenner #include <stdio.h>
55b0453382SBill Fenner 
56b0453382SBill Fenner #include <netinet/ip6.h>
57b0453382SBill Fenner #include <netinet/icmp6.h>
58b0453382SBill Fenner 
59b0453382SBill Fenner #include "interface.h"
60b0453382SBill Fenner #include "addrtoname.h"
61b0453382SBill Fenner 
62b0453382SBill Fenner void icmp6_opt_print(const u_char *, int);
63b0453382SBill Fenner void mld6_print(const u_char *);
64b0453382SBill Fenner 
65b0453382SBill Fenner void
66b0453382SBill Fenner icmp6_print(register const u_char *bp, register const u_char *bp2)
67b0453382SBill Fenner {
68b0453382SBill Fenner 	register const struct icmp6_hdr *dp;
69b0453382SBill Fenner 	register const struct ip6_hdr *ip;
70b0453382SBill Fenner 	register const char *str;
71b0453382SBill Fenner 	register const struct ip6_hdr *oip;
72b0453382SBill Fenner 	register const struct udphdr *ouh;
73b0453382SBill Fenner 	register int hlen, dport;
74b0453382SBill Fenner 	register const u_char *ep;
75b0453382SBill Fenner 	char buf[256];
76b0453382SBill Fenner 	int icmp6len;
77b0453382SBill Fenner 
78b0453382SBill Fenner #if 0
79b0453382SBill Fenner #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
80b0453382SBill Fenner #endif
81b0453382SBill Fenner 
82b0453382SBill Fenner 	dp = (struct icmp6_hdr *)bp;
83b0453382SBill Fenner 	ip = (struct ip6_hdr *)bp2;
84b0453382SBill Fenner 	oip = (struct ip6_hdr *)(dp + 1);
85b0453382SBill Fenner 	str = buf;
86b0453382SBill Fenner 	/* 'ep' points to the end of avaible data. */
87b0453382SBill Fenner 	ep = snapend;
88b0453382SBill Fenner 	if (ip->ip6_plen)
89b0453382SBill Fenner 		icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
90b0453382SBill Fenner 			    (bp - bp2));
91b0453382SBill Fenner 	else			/* XXX: jumbo payload case... */
92b0453382SBill Fenner 		icmp6len = snapend - bp;
93b0453382SBill Fenner 
94b0453382SBill Fenner #if 0
95b0453382SBill Fenner         (void)printf("%s > %s: ",
96b0453382SBill Fenner 		ip6addr_string(&ip->ip6_src),
97b0453382SBill Fenner 		ip6addr_string(&ip->ip6_dst));
98b0453382SBill Fenner #endif
99b0453382SBill Fenner 
100b0453382SBill Fenner 	TCHECK(dp->icmp6_code);
101b0453382SBill Fenner 	switch(dp->icmp6_type) {
102b0453382SBill Fenner 	case ICMP6_DST_UNREACH:
103b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
104b0453382SBill Fenner 		switch (dp->icmp6_code) {
105b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOROUTE:
106b0453382SBill Fenner 			printf("icmp6: %s unreachable route",
107b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
108b0453382SBill Fenner 			break;
109b0453382SBill Fenner 		case ICMP6_DST_UNREACH_ADMIN:
110b0453382SBill Fenner 			printf("icmp6: %s unreachable prohibited",
111b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
112b0453382SBill Fenner 			break;
113b0453382SBill Fenner #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
114b0453382SBill Fenner 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
115b0453382SBill Fenner #else
116b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOTNEIGHBOR:
117b0453382SBill Fenner #endif
118b0453382SBill Fenner 			printf("icmp6: %s beyond scope of source address %s",
119b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst),
120b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_src));
121b0453382SBill Fenner 			break;
122b0453382SBill Fenner 		case ICMP6_DST_UNREACH_ADDR:
123b0453382SBill Fenner 			printf("icmp6: %s unreachable address",
124b0453382SBill Fenner 			       ip6addr_string(&oip->ip6_dst));
125b0453382SBill Fenner 			break;
126b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOPORT:
127b0453382SBill Fenner 			TCHECK(oip->ip6_nxt);
128b0453382SBill Fenner 			hlen = sizeof(struct ip6_hdr);
129b0453382SBill Fenner 			ouh = (struct udphdr *)(((u_char *)oip) + hlen);
130b0453382SBill Fenner 			dport = ntohs(ouh->uh_dport);
131b0453382SBill Fenner 			switch (oip->ip6_nxt) {
132b0453382SBill Fenner 			case IPPROTO_TCP:
133b0453382SBill Fenner 				printf("icmp6: %s tcp port %s unreachable",
134b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
135b0453382SBill Fenner 					tcpport_string(dport));
136b0453382SBill Fenner 				break;
137b0453382SBill Fenner 			case IPPROTO_UDP:
138b0453382SBill Fenner 				printf("icmp6: %s udp port %s unreachable",
139b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
140b0453382SBill Fenner 					udpport_string(dport));
141b0453382SBill Fenner 				break;
142b0453382SBill Fenner 			default:
143b0453382SBill Fenner 				printf("icmp6: %s protocol %d port %d unreachable",
144b0453382SBill Fenner 					ip6addr_string(&oip->ip6_dst),
145b0453382SBill Fenner 					oip->ip6_nxt, dport);
146b0453382SBill Fenner 				break;
147b0453382SBill Fenner 			}
148b0453382SBill Fenner 			break;
149b0453382SBill Fenner 		default:
150b0453382SBill Fenner 			printf("icmp6: %s unreachable code-#%d",
151b0453382SBill Fenner 				ip6addr_string(&oip->ip6_dst),
152b0453382SBill Fenner 				dp->icmp6_code);
153b0453382SBill Fenner 			break;
154b0453382SBill Fenner 		}
155b0453382SBill Fenner 		break;
156b0453382SBill Fenner 	case ICMP6_PACKET_TOO_BIG:
157b0453382SBill Fenner 		TCHECK(dp->icmp6_mtu);
158b0453382SBill Fenner 		printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu));
159b0453382SBill Fenner 		break;
160b0453382SBill Fenner 	case ICMP6_TIME_EXCEEDED:
161b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
162b0453382SBill Fenner 		switch (dp->icmp6_code) {
163b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_TRANSIT:
164b0453382SBill Fenner 			printf("icmp6: time exceeded in-transit for %s",
165b0453382SBill Fenner 				ip6addr_string(&oip->ip6_dst));
166b0453382SBill Fenner 			break;
167b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_REASSEMBLY:
168b0453382SBill Fenner 			printf("icmp6: ip6 reassembly time exceeded");
169b0453382SBill Fenner 			break;
170b0453382SBill Fenner 		default:
171b0453382SBill Fenner 			printf("icmp6: time exceeded code-#%d",
172b0453382SBill Fenner 				dp->icmp6_code);
173b0453382SBill Fenner 			break;
174b0453382SBill Fenner 		}
175b0453382SBill Fenner 		break;
176b0453382SBill Fenner 	case ICMP6_PARAM_PROB:
177b0453382SBill Fenner 		TCHECK(oip->ip6_dst);
178b0453382SBill Fenner 		switch (dp->icmp6_code) {
179b0453382SBill Fenner 		case ICMP6_PARAMPROB_HEADER:
180b0453382SBill Fenner 			printf("icmp6: parameter problem errorneous - octet %u\n",
181b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
182b0453382SBill Fenner 			break;
183b0453382SBill Fenner 		case ICMP6_PARAMPROB_NEXTHEADER:
184b0453382SBill Fenner 			printf("icmp6: parameter problem next header - octet %u\n",
185b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
186b0453382SBill Fenner 			break;
187b0453382SBill Fenner 		case ICMP6_PARAMPROB_OPTION:
188b0453382SBill Fenner 			printf("icmp6: parameter problem option - octet %u\n",
189b0453382SBill Fenner 				(u_int32_t)ntohl(dp->icmp6_pptr));
190b0453382SBill Fenner 			break;
191b0453382SBill Fenner 		default:
192b0453382SBill Fenner 			printf("icmp6: parameter problem code-#%d",
193b0453382SBill Fenner 			       dp->icmp6_code);
194b0453382SBill Fenner 			break;
195b0453382SBill Fenner 		}
196b0453382SBill Fenner 		break;
197b0453382SBill Fenner 	case ICMP6_ECHO_REQUEST:
198b0453382SBill Fenner 		printf("icmp6: echo request");
199b0453382SBill Fenner 		break;
200b0453382SBill Fenner 	case ICMP6_ECHO_REPLY:
201b0453382SBill Fenner 		printf("icmp6: echo reply");
202b0453382SBill Fenner 		break;
203b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_QUERY:
204b0453382SBill Fenner 		printf("icmp6: multicast listener query ");
205b0453382SBill Fenner 		mld6_print((const u_char *)dp);
206b0453382SBill Fenner 		break;
207b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REPORT:
208b0453382SBill Fenner 		printf("icmp6: multicast listener report ");
209b0453382SBill Fenner 		mld6_print((const u_char *)dp);
210b0453382SBill Fenner 		break;
211b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REDUCTION:
212b0453382SBill Fenner 		printf("icmp6: multicast listener done ");
213b0453382SBill Fenner 		mld6_print((const u_char *)dp);
214b0453382SBill Fenner 		break;
215b0453382SBill Fenner 	case ND_ROUTER_SOLICIT:
216b0453382SBill Fenner 		printf("icmp6: router solicitation ");
217b0453382SBill Fenner 		if (vflag) {
218b0453382SBill Fenner #define RTSOLLEN 8
219b0453382SBill Fenner 		        icmp6_opt_print((const u_char *)dp + RTSOLLEN,
220b0453382SBill Fenner 					icmp6len - RTSOLLEN);
221b0453382SBill Fenner 		}
222b0453382SBill Fenner 		break;
223b0453382SBill Fenner 	case ND_ROUTER_ADVERT:
224b0453382SBill Fenner 		printf("icmp6: router advertisement");
225b0453382SBill Fenner 		if (vflag) {
226b0453382SBill Fenner 			struct nd_router_advert *p;
227b0453382SBill Fenner 
228b0453382SBill Fenner 			p = (struct nd_router_advert *)dp;
229b0453382SBill Fenner 			TCHECK(p->nd_ra_retransmit);
230b0453382SBill Fenner 			printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
231b0453382SBill Fenner 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
232b0453382SBill Fenner 				printf("M");
233b0453382SBill Fenner 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
234b0453382SBill Fenner 				printf("O");
235b0453382SBill Fenner 			if (p->nd_ra_flags_reserved != 0)
236b0453382SBill Fenner 				printf(" ");
237b0453382SBill Fenner 			printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
238b0453382SBill Fenner 			printf("reachable_time=%u, ",
239b0453382SBill Fenner 				(u_int32_t)ntohl(p->nd_ra_reachable));
240b0453382SBill Fenner 			printf("retrans_time=%u)",
241b0453382SBill Fenner 				(u_int32_t)ntohl(p->nd_ra_retransmit));
242b0453382SBill Fenner #define RTADVLEN 16
243b0453382SBill Fenner 		        icmp6_opt_print((const u_char *)dp + RTADVLEN,
244b0453382SBill Fenner 					icmp6len - RTADVLEN);
245b0453382SBill Fenner 		}
246b0453382SBill Fenner 		break;
247b0453382SBill Fenner 	case ND_NEIGHBOR_SOLICIT:
248b0453382SBill Fenner 	    {
249b0453382SBill Fenner 		struct nd_neighbor_solicit *p;
250b0453382SBill Fenner 		p = (struct nd_neighbor_solicit *)dp;
251b0453382SBill Fenner 		TCHECK(p->nd_ns_target);
252b0453382SBill Fenner 		printf("icmp6: neighbor sol: who has %s",
253b0453382SBill Fenner 			ip6addr_string(&p->nd_ns_target));
254b0453382SBill Fenner 		if (vflag) {
255b0453382SBill Fenner #define NDSOLLEN 24
256b0453382SBill Fenner 		        icmp6_opt_print((const u_char *)dp + NDSOLLEN,
257b0453382SBill Fenner 					icmp6len - NDSOLLEN);
258b0453382SBill Fenner 		}
259b0453382SBill Fenner 	    }
260b0453382SBill Fenner 		break;
261b0453382SBill Fenner 	case ND_NEIGHBOR_ADVERT:
262b0453382SBill Fenner 	    {
263b0453382SBill Fenner 		struct nd_neighbor_advert *p;
264b0453382SBill Fenner 
265b0453382SBill Fenner 		p = (struct nd_neighbor_advert *)dp;
266b0453382SBill Fenner 		TCHECK(p->nd_na_target);
267b0453382SBill Fenner 		printf("icmp6: neighbor adv: tgt is %s",
268b0453382SBill Fenner 			ip6addr_string(&p->nd_na_target));
269b0453382SBill Fenner                 if (vflag) {
270b0453382SBill Fenner #define ND_NA_FLAG_ALL	\
271b0453382SBill Fenner 	(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
272b0453382SBill Fenner 			/* we don't need ntohl() here.  see advanced-api-04. */
273b0453382SBill Fenner 			if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
274b0453382SBill Fenner #undef ND_NA_FLAG_ALL
275b0453382SBill Fenner 				u_int32_t flags;
276b0453382SBill Fenner 
277b0453382SBill Fenner 				flags = p->nd_na_flags_reserved;
278b0453382SBill Fenner 				printf("(");
279b0453382SBill Fenner 				if (flags & ND_NA_FLAG_ROUTER)
280b0453382SBill Fenner 					printf("R");
281b0453382SBill Fenner 				if (flags & ND_NA_FLAG_SOLICITED)
282b0453382SBill Fenner 					printf("S");
283b0453382SBill Fenner 				if (flags & ND_NA_FLAG_OVERRIDE)
284b0453382SBill Fenner 					printf("O");
285b0453382SBill Fenner 				printf(")");
286b0453382SBill Fenner 			}
287b0453382SBill Fenner #define NDADVLEN 24
288b0453382SBill Fenner 		        icmp6_opt_print((const u_char *)dp + NDADVLEN,
289b0453382SBill Fenner 					icmp6len - NDADVLEN);
290b0453382SBill Fenner 		}
291b0453382SBill Fenner 	    }
292b0453382SBill Fenner 		break;
293b0453382SBill Fenner 	case ND_REDIRECT:
294b0453382SBill Fenner 	{
295b0453382SBill Fenner #define RDR(i) ((struct nd_redirect *)(i))
296b0453382SBill Fenner 		char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
297b0453382SBill Fenner 
298b0453382SBill Fenner 		TCHECK(RDR(dp)->nd_rd_dst);
299b0453382SBill Fenner 		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
300b0453382SBill Fenner 			  tgtbuf, INET6_ADDRSTRLEN);
301b0453382SBill Fenner 		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
302b0453382SBill Fenner 			  dstbuf, INET6_ADDRSTRLEN);
303b0453382SBill Fenner 		printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
304b0453382SBill Fenner #define REDIRECTLEN 40
305b0453382SBill Fenner 		if (vflag) {
306b0453382SBill Fenner 			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
307b0453382SBill Fenner 					icmp6len - REDIRECTLEN);
308b0453382SBill Fenner 		}
309b0453382SBill Fenner 		break;
310b0453382SBill Fenner 	}
311b0453382SBill Fenner 	case ICMP6_ROUTER_RENUMBERING:
312b0453382SBill Fenner 		switch (dp->icmp6_code) {
313b0453382SBill Fenner 		case ICMP6_ROUTER_RENUMBERING_COMMAND:
314b0453382SBill Fenner 			printf("icmp6: router renum command");
315b0453382SBill Fenner 			break;
316b0453382SBill Fenner 		case ICMP6_ROUTER_RENUMBERING_RESULT:
317b0453382SBill Fenner 			printf("icmp6: router renum result");
318b0453382SBill Fenner 			break;
319b0453382SBill Fenner 		default:
320b0453382SBill Fenner 			printf("icmp6: router renum code-#%d", dp->icmp6_code);
321b0453382SBill Fenner 			break;
322b0453382SBill Fenner 		}
323b0453382SBill Fenner 		break;
324b0453382SBill Fenner #ifdef ICMP6_WRUREQUEST
325b0453382SBill Fenner 	case ICMP6_WRUREQUEST:	/*ICMP6_FQDN_QUERY*/
326b0453382SBill Fenner 	    {
327b0453382SBill Fenner 		int siz;
328b0453382SBill Fenner 		siz = ep - (u_char *)(dp + 1);
329b0453382SBill Fenner 		if (siz == 4)
330b0453382SBill Fenner 			printf("icmp6: who-are-you request");
331b0453382SBill Fenner 		else {
332b0453382SBill Fenner 			printf("icmp6: FQDN request");
333b0453382SBill Fenner 			if (vflag) {
334b0453382SBill Fenner 				if (siz < 8)
335b0453382SBill Fenner 					printf("?(icmp6_data %d bytes)", siz);
336b0453382SBill Fenner 				else if (8 < siz)
337b0453382SBill Fenner 					printf("?(extra %d bytes)", siz - 8);
338b0453382SBill Fenner 			}
339b0453382SBill Fenner 		}
340b0453382SBill Fenner 		break;
341b0453382SBill Fenner 	    }
342b0453382SBill Fenner #endif /*ICMP6_WRUREQUEST*/
343b0453382SBill Fenner #ifdef ICMP6_WRUREPLY
344b0453382SBill Fenner 	case ICMP6_WRUREPLY:	/*ICMP6_FQDN_REPLY*/
345b0453382SBill Fenner 	    {
346b0453382SBill Fenner 		enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
347b0453382SBill Fenner 		u_char const *buf;
348b0453382SBill Fenner 		u_char const *cp = NULL;
349b0453382SBill Fenner 
350b0453382SBill Fenner 		buf = (u_char *)(dp + 1);
351b0453382SBill Fenner 
352b0453382SBill Fenner 		/* fair guess */
353b0453382SBill Fenner 		if (buf[12] == ep - buf - 13)
354b0453382SBill Fenner 			mode = FQDN;
355b0453382SBill Fenner 		else if (dp->icmp6_code == 1)
356b0453382SBill Fenner 			mode = FQDN;
357b0453382SBill Fenner 
358b0453382SBill Fenner 		/* wild guess */
359b0453382SBill Fenner 		if (mode == UNKNOWN) {
360b0453382SBill Fenner 			cp = buf + 4;
361b0453382SBill Fenner 			while (cp < ep) {
362b0453382SBill Fenner 				if (!isprint(*cp++))
363b0453382SBill Fenner 					mode = FQDN;
364b0453382SBill Fenner 			}
365b0453382SBill Fenner 		}
366b0453382SBill Fenner #ifndef abs
367b0453382SBill Fenner #define abs(a)	((0 < (a)) ? (a) : -(a))
368b0453382SBill Fenner #endif
369b0453382SBill Fenner 		if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13)))
370b0453382SBill Fenner 			mode = WRU;
371b0453382SBill Fenner 		if (mode == UNKNOWN)
372b0453382SBill Fenner 			mode = FQDN;
373b0453382SBill Fenner 
374b0453382SBill Fenner 		if (mode == WRU) {
375b0453382SBill Fenner 			cp = buf + 4;
376b0453382SBill Fenner 			printf("icmp6: who-are-you reply(\"");
377b0453382SBill Fenner 		} else if (mode == FQDN) {
378b0453382SBill Fenner 			cp = buf + 13;
379b0453382SBill Fenner 			printf("icmp6: FQDN reply(\"");
380b0453382SBill Fenner 		}
381b0453382SBill Fenner 		for (; cp < ep; cp++)
382b0453382SBill Fenner 			printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
383b0453382SBill Fenner 		printf("\"");
384b0453382SBill Fenner 		if (vflag) {
385b0453382SBill Fenner 			printf(",%s", mode == FQDN ? "FQDN" : "WRU");
386b0453382SBill Fenner 			if (mode == FQDN) {
387b0453382SBill Fenner 				long ttl;
388b0453382SBill Fenner 				ttl = (long)ntohl(*(u_long *)&buf[8]);
389b0453382SBill Fenner 				if (dp->icmp6_code == 1)
390b0453382SBill Fenner 					printf(",TTL=unknown");
391b0453382SBill Fenner 				else if (ttl < 0)
392b0453382SBill Fenner 					printf(",TTL=%ld:invalid", ttl);
393b0453382SBill Fenner 				else
394b0453382SBill Fenner 					printf(",TTL=%ld", ttl);
395b0453382SBill Fenner 				if (buf[12] != ep - buf - 13) {
396b0453382SBill Fenner 					(void)printf(",invalid namelen:%d/%u",
397b0453382SBill Fenner 						buf[12],
398b0453382SBill Fenner 						(unsigned int)(ep - buf - 13));
399b0453382SBill Fenner 				}
400b0453382SBill Fenner 			}
401b0453382SBill Fenner 		}
402b0453382SBill Fenner 		printf(")");
403b0453382SBill Fenner 		break;
404b0453382SBill Fenner 	    }
405b0453382SBill Fenner #endif /*ICMP6_WRUREPLY*/
406b0453382SBill Fenner 	default:
407b0453382SBill Fenner 		printf("icmp6: type-#%d", dp->icmp6_type);
408b0453382SBill Fenner 		break;
409b0453382SBill Fenner 	}
410b0453382SBill Fenner 	return;
411b0453382SBill Fenner trunc:
412b0453382SBill Fenner 	fputs("[|icmp6]", stdout);
413b0453382SBill Fenner #if 0
414b0453382SBill Fenner #undef TCHECK
415b0453382SBill Fenner #endif
416b0453382SBill Fenner }
417b0453382SBill Fenner 
418b0453382SBill Fenner void
419b0453382SBill Fenner icmp6_opt_print(register const u_char *bp, int resid)
420b0453382SBill Fenner {
421b0453382SBill Fenner 	register const struct nd_opt_hdr *op;
422b0453382SBill Fenner 	register const struct nd_opt_hdr *opl;	/* why there's no struct? */
423b0453382SBill Fenner 	register const struct nd_opt_prefix_info *opp;
424b0453382SBill Fenner 	register const struct icmp6_opts_redirect *opr;
425b0453382SBill Fenner 	register const struct nd_opt_mtu *opm;
426b0453382SBill Fenner 	register const u_char *ep;
427b0453382SBill Fenner 	int	opts_len;
428b0453382SBill Fenner #if 0
429b0453382SBill Fenner 	register const struct ip6_hdr *ip;
430b0453382SBill Fenner 	register const char *str;
431b0453382SBill Fenner 	register const struct ip6_hdr *oip;
432b0453382SBill Fenner 	register const struct udphdr *ouh;
433b0453382SBill Fenner 	register int hlen, dport;
434b0453382SBill Fenner 	char buf[256];
435b0453382SBill Fenner #endif
436b0453382SBill Fenner 
437b0453382SBill Fenner #if 0
438b0453382SBill Fenner #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
439b0453382SBill Fenner #endif
440b0453382SBill Fenner #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
441b0453382SBill Fenner 
442b0453382SBill Fenner 	op = (struct nd_opt_hdr *)bp;
443b0453382SBill Fenner #if 0
444b0453382SBill Fenner 	ip = (struct ip6_hdr *)bp2;
445b0453382SBill Fenner 	oip = &dp->icmp6_ip6;
446b0453382SBill Fenner 	str = buf;
447b0453382SBill Fenner #endif
448b0453382SBill Fenner 	/* 'ep' points to the end of avaible data. */
449b0453382SBill Fenner 	ep = snapend;
450b0453382SBill Fenner 
451b0453382SBill Fenner 	ECHECK(op->nd_opt_len);
452b0453382SBill Fenner 	if (resid <= 0)
453b0453382SBill Fenner 		return;
454b0453382SBill Fenner 	switch(op->nd_opt_type) {
455b0453382SBill Fenner 	case ND_OPT_SOURCE_LINKADDR:
456b0453382SBill Fenner 		opl = (struct nd_opt_hdr *)op;
457b0453382SBill Fenner #if 1
458b0453382SBill Fenner 		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
459b0453382SBill Fenner 			goto trunc;
460b0453382SBill Fenner #else
461b0453382SBill Fenner 		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
462b0453382SBill Fenner #endif
463b0453382SBill Fenner 		printf("(src lladdr: %s",
464b0453382SBill Fenner 			etheraddr_string((u_char *)(opl + 1)));
465b0453382SBill Fenner 		if (opl->nd_opt_len != 1)
466b0453382SBill Fenner 			printf("!");
467b0453382SBill Fenner 		printf(")");
468b0453382SBill Fenner 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
469b0453382SBill Fenner 				resid - (op->nd_opt_len << 3));
470b0453382SBill Fenner 		break;
471b0453382SBill Fenner 	case ND_OPT_TARGET_LINKADDR:
472b0453382SBill Fenner 		opl = (struct nd_opt_hdr *)op;
473b0453382SBill Fenner #if 1
474b0453382SBill Fenner 		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
475b0453382SBill Fenner 			goto trunc;
476b0453382SBill Fenner #else
477b0453382SBill Fenner 		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
478b0453382SBill Fenner #endif
479b0453382SBill Fenner 		printf("(tgt lladdr: %s",
480b0453382SBill Fenner 			etheraddr_string((u_char *)(opl + 1)));
481b0453382SBill Fenner 		if (opl->nd_opt_len != 1)
482b0453382SBill Fenner 			printf("!");
483b0453382SBill Fenner 		printf(")");
484b0453382SBill Fenner 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
485b0453382SBill Fenner 				resid - (op->nd_opt_len << 3));
486b0453382SBill Fenner 		break;
487b0453382SBill Fenner 	case ND_OPT_PREFIX_INFORMATION:
488b0453382SBill Fenner 		opp = (struct nd_opt_prefix_info *)op;
489b0453382SBill Fenner 		TCHECK(opp->nd_opt_pi_prefix);
490b0453382SBill Fenner 		printf("(prefix info: ");
491b0453382SBill Fenner 		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
492b0453382SBill Fenner 		       printf("L");
493b0453382SBill Fenner 		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
494b0453382SBill Fenner 		       printf("A");
495b0453382SBill Fenner 		if (opp->nd_opt_pi_flags_reserved)
496b0453382SBill Fenner 			printf(" ");
497b0453382SBill Fenner 		printf("valid_ltime=");
498b0453382SBill Fenner 		if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
499b0453382SBill Fenner 			printf("infinity");
500b0453382SBill Fenner 		else {
501b0453382SBill Fenner 			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
502b0453382SBill Fenner 		}
503b0453382SBill Fenner 		printf(", ");
504b0453382SBill Fenner 		printf("preffered_ltime=");
505b0453382SBill Fenner 		if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
506b0453382SBill Fenner 			printf("infinity");
507b0453382SBill Fenner 		else {
508b0453382SBill Fenner 			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
509b0453382SBill Fenner 		}
510b0453382SBill Fenner 		printf(", ");
511b0453382SBill Fenner 		printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
512b0453382SBill Fenner 			opp->nd_opt_pi_prefix_len);
513b0453382SBill Fenner 		if (opp->nd_opt_pi_len != 4)
514b0453382SBill Fenner 			printf("!");
515b0453382SBill Fenner 		printf(")");
516b0453382SBill Fenner 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
517b0453382SBill Fenner 				resid - (op->nd_opt_len << 3));
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 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
524b0453382SBill Fenner 				resid - (op->nd_opt_len << 3));
525b0453382SBill Fenner 		break;
526b0453382SBill Fenner 	case ND_OPT_MTU:
527b0453382SBill Fenner 		opm = (struct nd_opt_mtu *)op;
528b0453382SBill Fenner 		TCHECK(opm->nd_opt_mtu_mtu);
529b0453382SBill Fenner 		printf("(mtu: ");
530b0453382SBill Fenner 		printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
531b0453382SBill Fenner 		if (opm->nd_opt_mtu_len != 1)
532b0453382SBill Fenner 			printf("!");
533b0453382SBill Fenner 		printf(")");
534b0453382SBill Fenner 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
535b0453382SBill Fenner 				resid - (op->nd_opt_len << 3));
536b0453382SBill Fenner 		break;
537b0453382SBill Fenner 	default:
538b0453382SBill Fenner 		opts_len = op->nd_opt_len;
539b0453382SBill Fenner 		printf("(unknwon opt_type=%d, opt_len=%d)",
540b0453382SBill Fenner 		       op->nd_opt_type, opts_len);
541b0453382SBill Fenner 		if (opts_len == 0)
542b0453382SBill Fenner 			opts_len = 1; /* XXX */
543b0453382SBill Fenner 		icmp6_opt_print((const u_char *)op + (opts_len << 3),
544b0453382SBill Fenner 				resid - (opts_len << 3));
545b0453382SBill Fenner 		break;
546b0453382SBill Fenner 	}
547b0453382SBill Fenner 	return;
548b0453382SBill Fenner  trunc:
549b0453382SBill Fenner 	fputs("[ndp opt]", stdout);
550b0453382SBill Fenner 	return;
551b0453382SBill Fenner #if 0
552b0453382SBill Fenner #undef TCHECK
553b0453382SBill Fenner #endif
554b0453382SBill Fenner #undef ECHECK
555b0453382SBill Fenner }
556b0453382SBill Fenner 
557b0453382SBill Fenner void
558b0453382SBill Fenner mld6_print(register const u_char *bp)
559b0453382SBill Fenner {
560b0453382SBill Fenner 	register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
561b0453382SBill Fenner 	register const u_char *ep;
562b0453382SBill Fenner 
563b0453382SBill Fenner 	/* 'ep' points to the end of avaible data. */
564b0453382SBill Fenner 	ep = snapend;
565b0453382SBill Fenner 
566b0453382SBill Fenner 	if ((u_char *)mp + sizeof(*mp) > ep)
567b0453382SBill Fenner 		return;
568b0453382SBill Fenner 
569b0453382SBill Fenner 	printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
570b0453382SBill Fenner 	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
571b0453382SBill Fenner 
572b0453382SBill Fenner 	return;
573b0453382SBill Fenner }
574b0453382SBill Fenner #endif /* INET6 */
575