xref: /netbsd-src/external/bsd/tcpdump/dist/print-icmp6.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-icmp6.c,v 1.15 2023/08/17 20:19:40 christos Exp $");
25 #endif
26 
27 /* \summary: IPv6 Internet Control Message Protocol (ICMPv6) printer */
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #include "netdissect-stdinc.h"
34 
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "netdissect.h"
39 #include "addrtoname.h"
40 #include "addrtostr.h"
41 #include "extract.h"
42 
43 #include "ip6.h"
44 #include "ipproto.h"
45 
46 #include "udp.h"
47 #include "ah.h"
48 
49 /*	NetBSD: icmp6.h,v 1.13 2000/08/03 16:30:37 itojun Exp	*/
50 /*	$KAME: icmp6.h,v 1.22 2000/08/03 15:25:16 jinmei Exp $	*/
51 
52 /*
53  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
54  * All rights reserved.
55  *
56  * Redistribution and use in source and binary forms, with or without
57  * modification, are permitted provided that the following conditions
58  * are met:
59  * 1. Redistributions of source code must retain the above copyright
60  *    notice, this list of conditions and the following disclaimer.
61  * 2. Redistributions in binary form must reproduce the above copyright
62  *    notice, this list of conditions and the following disclaimer in the
63  *    documentation and/or other materials provided with the distribution.
64  * 3. Neither the name of the project nor the names of its contributors
65  *    may be used to endorse or promote products derived from this software
66  *    without specific prior written permission.
67  *
68  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
69  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
72  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78  * SUCH DAMAGE.
79  */
80 
81 struct icmp6_hdr {
82 	nd_uint8_t	icmp6_type;	/* type field */
83 	nd_uint8_t	icmp6_code;	/* code field */
84 	nd_uint16_t	icmp6_cksum;	/* checksum field */
85 	union {
86 		nd_uint32_t	icmp6_un_data32[1]; /* type-specific field */
87 		nd_uint16_t	icmp6_un_data16[2]; /* type-specific field */
88 		nd_uint8_t	icmp6_un_data8[4];  /* type-specific field */
89 		nd_byte		icmp6_un_data[1];   /* type-specific field */
90 	} icmp6_dataun;
91 };
92 
93 #define icmp6_data32	icmp6_dataun.icmp6_un_data32
94 #define icmp6_data16	icmp6_dataun.icmp6_un_data16
95 #define icmp6_data8	icmp6_dataun.icmp6_un_data8
96 #define icmp6_data	icmp6_dataun.icmp6_un_data
97 #define icmp6_pptr	icmp6_data32[0]		/* parameter prob */
98 #define icmp6_mtu	icmp6_data32[0]		/* packet too big */
99 #define icmp6_id	icmp6_data16[0]		/* echo request/reply */
100 #define icmp6_seq	icmp6_data16[1]		/* echo request/reply */
101 #define icmp6_maxdelay	icmp6_data16[0]		/* mcast group membership */
102 
103 #define ICMP6_DST_UNREACH		1	/* dest unreachable, codes: */
104 #define ICMP6_PACKET_TOO_BIG		2	/* packet too big */
105 #define ICMP6_TIME_EXCEEDED		3	/* time exceeded, code: */
106 #define ICMP6_PARAM_PROB		4	/* ip6 header bad */
107 
108 #define ICMP6_ECHO_REQUEST		128	/* echo service */
109 #define ICMP6_ECHO_REPLY		129	/* echo reply */
110 #define ICMP6_MEMBERSHIP_QUERY		130	/* group membership query */
111 #define MLD6_LISTENER_QUERY		130	/* multicast listener query */
112 #define ICMP6_MEMBERSHIP_REPORT		131	/* group membership report */
113 #define MLD6_LISTENER_REPORT		131	/* multicast listener report */
114 #define ICMP6_MEMBERSHIP_REDUCTION	132	/* group membership termination */
115 #define MLD6_LISTENER_DONE		132	/* multicast listener done */
116 
117 #define ND_ROUTER_SOLICIT		133	/* router solicitation */
118 #define ND_ROUTER_ADVERT		134	/* router advertisement */
119 #define ND_NEIGHBOR_SOLICIT		135	/* neighbor solicitation */
120 #define ND_NEIGHBOR_ADVERT		136	/* neighbor advertisement */
121 #define ND_REDIRECT			137	/* redirect */
122 
123 #define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */
124 
125 #define ICMP6_WRUREQUEST		139	/* who are you request */
126 #define ICMP6_WRUREPLY			140	/* who are you reply */
127 #define ICMP6_FQDN_QUERY		139	/* FQDN query */
128 #define ICMP6_FQDN_REPLY		140	/* FQDN reply */
129 #define ICMP6_NI_QUERY			139	/* node information request - RFC 4620 */
130 #define ICMP6_NI_REPLY			140	/* node information reply - RFC 4620 */
131 #define IND_SOLICIT			141	/* inverse neighbor solicitation */
132 #define IND_ADVERT			142	/* inverse neighbor advertisement */
133 
134 #define ICMP6_V2_MEMBERSHIP_REPORT	143	/* v2 membership report */
135 #define MLDV2_LISTENER_REPORT		143	/* v2 multicast listener report */
136 #define ICMP6_HADISCOV_REQUEST		144
137 #define ICMP6_HADISCOV_REPLY		145
138 #define ICMP6_MOBILEPREFIX_SOLICIT	146
139 #define ICMP6_MOBILEPREFIX_ADVERT	147
140 
141 #define MLD6_MTRACE_RESP		200	/* mtrace response(to sender) */
142 #define MLD6_MTRACE			201	/* mtrace messages */
143 
144 #define ICMP6_MAXTYPE			201
145 
146 #define ICMP6_DST_UNREACH_NOROUTE	0	/* no route to destination */
147 #define ICMP6_DST_UNREACH_ADMIN		1	/* administratively prohibited */
148 #define ICMP6_DST_UNREACH_NOTNEIGHBOR	2	/* not a neighbor(obsolete) */
149 #define ICMP6_DST_UNREACH_BEYONDSCOPE	2	/* beyond scope of source address */
150 #define ICMP6_DST_UNREACH_ADDR		3	/* address unreachable */
151 #define ICMP6_DST_UNREACH_NOPORT	4	/* port unreachable */
152 
153 #define ICMP6_TIME_EXCEED_TRANSIT	0	/* ttl==0 in transit */
154 #define ICMP6_TIME_EXCEED_REASSEMBLY	1	/* ttl==0 in reass */
155 
156 #define ICMP6_PARAMPROB_HEADER		0	/* erroneous header field */
157 #define ICMP6_PARAMPROB_NEXTHEADER	1	/* unrecognized next header */
158 #define ICMP6_PARAMPROB_OPTION		2	/* unrecognized option */
159 #define ICMP6_PARAMPROB_FRAGHDRCHAIN	3	/* incomplete header chain */
160 
161 #define ICMP6_INFOMSG_MASK		0x80	/* all informational messages */
162 
163 #define ICMP6_NI_SUBJ_IPV6	0	/* Query Subject is an IPv6 address */
164 #define ICMP6_NI_SUBJ_FQDN	1	/* Query Subject is a Domain name */
165 #define ICMP6_NI_SUBJ_IPV4	2	/* Query Subject is an IPv4 address */
166 
167 #define ICMP6_NI_SUCCESS	0	/* node information successful reply */
168 #define ICMP6_NI_REFUSED	1	/* node information request is refused */
169 #define ICMP6_NI_UNKNOWN	2	/* unknown Qtype */
170 
171 #define ICMP6_ROUTER_RENUMBERING_COMMAND  0	/* rr command */
172 #define ICMP6_ROUTER_RENUMBERING_RESULT   1	/* rr result */
173 #define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET   255	/* rr seq num reset */
174 
175 /* Used in kernel only */
176 #define ND_REDIRECT_ONLINK	0	/* redirect to an on-link node */
177 #define ND_REDIRECT_ROUTER	1	/* redirect to a better router */
178 
179 /*
180  * Multicast Listener Discovery
181  */
182 struct mld6_hdr {
183 	struct icmp6_hdr	mld6_hdr;
184 	nd_ipv6			mld6_addr; /* multicast address */
185 };
186 
187 #define mld6_type	mld6_hdr.icmp6_type
188 #define mld6_code	mld6_hdr.icmp6_code
189 #define mld6_cksum	mld6_hdr.icmp6_cksum
190 #define mld6_maxdelay	mld6_hdr.icmp6_data16[0]
191 #define mld6_reserved	mld6_hdr.icmp6_data16[1]
192 
193 #define MLD_MINLEN	24
194 #define MLDV2_MINLEN	28
195 
196 /*
197  * Neighbor Discovery
198  */
199 
200 struct nd_router_solicit {	/* router solicitation */
201 	struct icmp6_hdr	nd_rs_hdr;
202 	/* could be followed by options */
203 };
204 
205 #define nd_rs_type	nd_rs_hdr.icmp6_type
206 #define nd_rs_code	nd_rs_hdr.icmp6_code
207 #define nd_rs_cksum	nd_rs_hdr.icmp6_cksum
208 #define nd_rs_reserved	nd_rs_hdr.icmp6_data32[0]
209 
210 struct nd_router_advert {	/* router advertisement */
211 	struct icmp6_hdr	nd_ra_hdr;
212 	nd_uint32_t		nd_ra_reachable;	/* reachable time */
213 	nd_uint32_t		nd_ra_retransmit;	/* retransmit timer */
214 	/* could be followed by options */
215 };
216 
217 #define nd_ra_type		nd_ra_hdr.icmp6_type
218 #define nd_ra_code		nd_ra_hdr.icmp6_code
219 #define nd_ra_cksum		nd_ra_hdr.icmp6_cksum
220 #define nd_ra_curhoplimit	nd_ra_hdr.icmp6_data8[0]
221 #define nd_ra_flags_reserved	nd_ra_hdr.icmp6_data8[1]
222 #define ND_RA_FLAG_MANAGED	0x80
223 #define ND_RA_FLAG_OTHER	0x40
224 #define ND_RA_FLAG_HOME_AGENT	0x20
225 #define ND_RA_FLAG_IPV6ONLY	0x02
226 
227 /*
228  * Router preference values based on draft-draves-ipngwg-router-selection-01.
229  * These are non-standard definitions.
230  */
231 #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
232 
233 #define ND_RA_FLAG_RTPREF_HIGH	0x08 /* 00001000 */
234 #define ND_RA_FLAG_RTPREF_MEDIUM	0x00 /* 00000000 */
235 #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
236 #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
237 
238 #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
239 
240 struct nd_neighbor_solicit {	/* neighbor solicitation */
241 	struct icmp6_hdr	nd_ns_hdr;
242 	nd_ipv6			nd_ns_target;	/*target address */
243 	/* could be followed by options */
244 };
245 
246 #define nd_ns_type		nd_ns_hdr.icmp6_type
247 #define nd_ns_code		nd_ns_hdr.icmp6_code
248 #define nd_ns_cksum		nd_ns_hdr.icmp6_cksum
249 #define nd_ns_reserved		nd_ns_hdr.icmp6_data32[0]
250 
251 struct nd_neighbor_advert {	/* neighbor advertisement */
252 	struct icmp6_hdr	nd_na_hdr;
253 	nd_ipv6			nd_na_target;	/* target address */
254 	/* could be followed by options */
255 };
256 
257 #define nd_na_type		nd_na_hdr.icmp6_type
258 #define nd_na_code		nd_na_hdr.icmp6_code
259 #define nd_na_cksum		nd_na_hdr.icmp6_cksum
260 #define nd_na_flags_reserved	nd_na_hdr.icmp6_data32[0]
261 
262 #define ND_NA_FLAG_ROUTER		0x80000000
263 #define ND_NA_FLAG_SOLICITED		0x40000000
264 #define ND_NA_FLAG_OVERRIDE		0x20000000
265 
266 struct nd_redirect {		/* redirect */
267 	struct icmp6_hdr	nd_rd_hdr;
268 	nd_ipv6			nd_rd_target;	/* target address */
269 	nd_ipv6			nd_rd_dst;	/* destination address */
270 	/* could be followed by options */
271 };
272 
273 #define nd_rd_type		nd_rd_hdr.icmp6_type
274 #define nd_rd_code		nd_rd_hdr.icmp6_code
275 #define nd_rd_cksum		nd_rd_hdr.icmp6_cksum
276 #define nd_rd_reserved		nd_rd_hdr.icmp6_data32[0]
277 
278 struct nd_opt_hdr {		/* Neighbor discovery option header */
279 	nd_uint8_t	nd_opt_type;
280 	nd_uint8_t	nd_opt_len;
281 	/* followed by option specific data*/
282 };
283 
284 #define ND_OPT_SOURCE_LINKADDR		1
285 #define ND_OPT_TARGET_LINKADDR		2
286 #define ND_OPT_PREFIX_INFORMATION	3
287 #define ND_OPT_REDIRECTED_HEADER	4
288 #define ND_OPT_MTU			5
289 #define ND_OPT_ADVINTERVAL		7
290 #define ND_OPT_HOMEAGENT_INFO		8
291 #define ND_OPT_ROUTE_INFO		24	/* RFC4191 */
292 #define ND_OPT_RDNSS			25
293 #define ND_OPT_DNSSL			31
294 
295 struct nd_opt_prefix_info {	/* prefix information */
296 	nd_uint8_t	nd_opt_pi_type;
297 	nd_uint8_t	nd_opt_pi_len;
298 	nd_uint8_t	nd_opt_pi_prefix_len;
299 	nd_uint8_t	nd_opt_pi_flags_reserved;
300 	nd_uint32_t	nd_opt_pi_valid_time;
301 	nd_uint32_t	nd_opt_pi_preferred_time;
302 	nd_uint32_t	nd_opt_pi_reserved2;
303 	nd_ipv6		nd_opt_pi_prefix;
304 };
305 
306 #define ND_OPT_PI_FLAG_ONLINK		0x80
307 #define ND_OPT_PI_FLAG_AUTO		0x40
308 #define ND_OPT_PI_FLAG_ROUTER		0x20	/*2292bis*/
309 
310 struct nd_opt_rd_hdr {         /* redirected header */
311 	nd_uint8_t	nd_opt_rh_type;
312 	nd_uint8_t	nd_opt_rh_len;
313 	nd_uint16_t	nd_opt_rh_reserved1;
314 	nd_uint32_t	nd_opt_rh_reserved2;
315 	/* followed by IP header and data */
316 };
317 
318 struct nd_opt_mtu {		/* MTU option */
319 	nd_uint8_t	nd_opt_mtu_type;
320 	nd_uint8_t	nd_opt_mtu_len;
321 	nd_uint16_t	nd_opt_mtu_reserved;
322 	nd_uint32_t	nd_opt_mtu_mtu;
323 };
324 
325 struct nd_opt_rdnss {		/* RDNSS RFC 6106 5.1 */
326 	nd_uint8_t	nd_opt_rdnss_type;
327 	nd_uint8_t	nd_opt_rdnss_len;
328 	nd_uint16_t	nd_opt_rdnss_reserved;
329 	nd_uint32_t	nd_opt_rdnss_lifetime;
330 	nd_ipv6		nd_opt_rdnss_addr[1];	/* variable-length */
331 };
332 
333 struct nd_opt_dnssl {		/* DNSSL RFC 6106 5.2 */
334 	nd_uint8_t  nd_opt_dnssl_type;
335 	nd_uint8_t  nd_opt_dnssl_len;
336 	nd_uint16_t nd_opt_dnssl_reserved;
337 	nd_uint32_t nd_opt_dnssl_lifetime;
338 	/* followed by list of DNS search domains, variable-length */
339 };
340 
341 struct nd_opt_advinterval {	/* Advertisement interval option */
342 	nd_uint8_t	nd_opt_adv_type;
343 	nd_uint8_t	nd_opt_adv_len;
344 	nd_uint16_t	nd_opt_adv_reserved;
345 	nd_uint32_t	nd_opt_adv_interval;
346 };
347 
348 struct nd_opt_homeagent_info {	/* Home Agent info */
349 	nd_uint8_t	nd_opt_hai_type;
350 	nd_uint8_t	nd_opt_hai_len;
351 	nd_uint16_t	nd_opt_hai_reserved;
352 	nd_uint16_t	nd_opt_hai_preference;
353 	nd_uint16_t	nd_opt_hai_lifetime;
354 };
355 
356 struct nd_opt_route_info {	/* route info */
357 	nd_uint8_t	nd_opt_rti_type;
358 	nd_uint8_t	nd_opt_rti_len;
359 	nd_uint8_t	nd_opt_rti_prefixlen;
360 	nd_uint8_t	nd_opt_rti_flags;
361 	nd_uint32_t	nd_opt_rti_lifetime;
362 	/* prefix follows */
363 };
364 
365 /*
366  * icmp6 namelookup
367  */
368 
369 struct icmp6_namelookup {
370 	struct icmp6_hdr	icmp6_nl_hdr;
371 	nd_byte			icmp6_nl_nonce[8];
372 	nd_int32_t		icmp6_nl_ttl;
373 #if 0
374 	nd_uint8_t		icmp6_nl_len;
375 	nd_byte			icmp6_nl_name[3];
376 #endif
377 	/* could be followed by options */
378 };
379 
380 /*
381  * icmp6 node information
382  */
383 struct icmp6_nodeinfo {
384 	struct icmp6_hdr icmp6_ni_hdr;
385 	nd_byte icmp6_ni_nonce[8];
386 	/* could be followed by reply data */
387 };
388 
389 #define ni_type		icmp6_ni_hdr.icmp6_type
390 #define ni_code		icmp6_ni_hdr.icmp6_code
391 #define ni_cksum	icmp6_ni_hdr.icmp6_cksum
392 #define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
393 #define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
394 
395 #define NI_QTYPE_NOOP		0 /* NOOP  */
396 #define NI_QTYPE_SUPTYPES	1 /* Supported Qtypes (drafts up to 09) */
397 #define NI_QTYPE_FQDN		2 /* FQDN (draft 04) */
398 #define NI_QTYPE_DNSNAME	2 /* DNS Name */
399 #define NI_QTYPE_NODEADDR	3 /* Node Addresses */
400 #define NI_QTYPE_IPV4ADDR	4 /* IPv4 Addresses */
401 
402 #define NI_NODEADDR_FLAG_TRUNCATE	0x0001
403 #define NI_NODEADDR_FLAG_ALL		0x0002
404 #define NI_NODEADDR_FLAG_COMPAT		0x0004
405 #define NI_NODEADDR_FLAG_LINKLOCAL	0x0008
406 #define NI_NODEADDR_FLAG_SITELOCAL	0x0010
407 #define NI_NODEADDR_FLAG_GLOBAL		0x0020
408 #define NI_NODEADDR_FLAG_ANYCAST	0x0040 /* just experimental. not in spec */
409 
410 struct ni_reply_fqdn {
411 	nd_uint32_t ni_fqdn_ttl;	/* TTL */
412 	nd_uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */
413 	nd_byte ni_fqdn_name[3]; /* XXX: alignment */
414 };
415 
416 /*
417  * Router Renumbering. as router-renum-08.txt
418  */
419 struct icmp6_router_renum {	/* router renumbering header */
420 	struct icmp6_hdr	rr_hdr;
421 	nd_uint8_t		rr_segnum;
422 	nd_uint8_t		rr_flags;
423 	nd_uint16_t		rr_maxdelay;
424 	nd_uint32_t		rr_reserved;
425 };
426 #define ICMP6_RR_FLAGS_TEST		0x80
427 #define ICMP6_RR_FLAGS_REQRESULT	0x40
428 #define ICMP6_RR_FLAGS_FORCEAPPLY	0x20
429 #define ICMP6_RR_FLAGS_SPECSITE		0x10
430 #define ICMP6_RR_FLAGS_PREVDONE		0x08
431 
432 #define rr_type		rr_hdr.icmp6_type
433 #define rr_code		rr_hdr.icmp6_code
434 #define rr_cksum	rr_hdr.icmp6_cksum
435 #define rr_seqnum	rr_hdr.icmp6_data32[0]
436 
437 struct rr_pco_match {		/* match prefix part */
438 	nd_uint8_t		rpm_code;
439 	nd_uint8_t		rpm_len;
440 	nd_uint8_t		rpm_ordinal;
441 	nd_uint8_t		rpm_matchlen;
442 	nd_uint8_t		rpm_minlen;
443 	nd_uint8_t		rpm_maxlen;
444 	nd_uint16_t		rpm_reserved;
445 	nd_ipv6			rpm_prefix;
446 };
447 
448 #define RPM_PCO_ADD		1
449 #define RPM_PCO_CHANGE		2
450 #define RPM_PCO_SETGLOBAL	3
451 #define RPM_PCO_MAX		4
452 
453 struct rr_pco_use {		/* use prefix part */
454 	nd_uint8_t	rpu_uselen;
455 	nd_uint8_t	rpu_keeplen;
456 	nd_uint8_t	rpu_ramask;
457 	nd_uint8_t	rpu_raflags;
458 	nd_uint32_t	rpu_vltime;
459 	nd_uint32_t	rpu_pltime;
460 	nd_uint32_t	rpu_flags;
461 	nd_ipv6		rpu_prefix;
462 };
463 #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK	0x80
464 #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO	0x40
465 
466 /* network endian */
467 #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME     ((uint32_t)htonl(0x80000000))
468 #define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME     ((uint32_t)htonl(0x40000000))
469 
470 struct rr_result {		/* router renumbering result message */
471 	nd_uint16_t	rrr_flags;
472 	nd_uint8_t	rrr_ordinal;
473 	nd_uint8_t	rrr_matchedlen;
474 	nd_uint32_t	rrr_ifid;
475 	nd_ipv6		rrr_prefix;
476 };
477 /* network endian */
478 #define ICMP6_RR_RESULT_FLAGS_OOB		((uint16_t)htons(0x0002))
479 #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		((uint16_t)htons(0x0001))
480 
481 static const char *get_rtpref(u_int);
482 static const char *get_lifetime(uint32_t);
483 static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
484 static int icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
485 static void mld6_print(netdissect_options *ndo, const u_char *);
486 static void mldv2_report_print(netdissect_options *ndo, const u_char *, u_int);
487 static void mldv2_query_print(netdissect_options *ndo, const u_char *, u_int);
488 static const struct udphdr *get_upperlayer(netdissect_options *ndo, const u_char *, u_int *);
489 static void dnsname_print(netdissect_options *ndo, const u_char *, const u_char *);
490 static void icmp6_nodeinfo_print(netdissect_options *ndo, u_int, const u_char *, const u_char *);
491 static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_char *);
492 
493 /*
494  * DIO: Updated to RFC6550, as published in 2012: section 6. (page 30)
495  */
496 
497 #define ND_RPL_MESSAGE 155  /* 0x9B */
498 
499 enum ND_RPL_CODE {
500     ND_RPL_DAG_IS=0x00,
501     ND_RPL_DAG_IO=0x01,
502     ND_RPL_DAO   =0x02,
503     ND_RPL_DAO_ACK=0x03,
504     ND_RPL_SEC_DAG_IS = 0x80,
505     ND_RPL_SEC_DAG_IO = 0x81,
506     ND_RPL_SEC_DAG    = 0x82,
507     ND_RPL_SEC_DAG_ACK= 0x83,
508     ND_RPL_SEC_CONSIST= 0x8A
509 };
510 
511 enum ND_RPL_DIO_FLAGS {
512         ND_RPL_DIO_GROUNDED = 0x80,
513         ND_RPL_DIO_DATRIG   = 0x40,
514         ND_RPL_DIO_DASUPPORT= 0x20,
515         ND_RPL_DIO_RES4     = 0x10,
516         ND_RPL_DIO_RES3     = 0x08,
517         ND_RPL_DIO_PRF_MASK = 0x07  /* 3-bit preference */
518 };
519 
520 #define DAGID_LEN 16
521 
522 /* section 6 of draft-ietf-roll-rpl-19 */
523 struct nd_rpl_security {
524     nd_uint8_t  rpl_sec_t_reserved;     /* bit 7 is T-bit */
525     nd_uint8_t  rpl_sec_algo;
526     nd_uint16_t rpl_sec_kim_lvl_flags;  /* bit 15/14, KIM */
527                                       /* bit 10-8, LVL, bit 7-0 flags */
528     nd_uint32_t rpl_sec_counter;
529 #if 0
530     nd_byte     rpl_sec_ki[0];          /* depends upon kim */
531 #endif
532 };
533 
534 /* section 6.2.1, DODAG Information Solication (DIS_IS) */
535 struct nd_rpl_dis_is {
536     nd_uint8_t rpl_dis_flags;
537     nd_uint8_t rpl_dis_reserved;
538 #if 0
539     nd_byte    rpl_dis_options[0];
540 #endif
541 };
542 
543 /* section 6.3.1, DODAG Information Object (DIO) */
544 struct nd_rpl_dio {
545     nd_uint8_t  rpl_instanceid;
546     nd_uint8_t  rpl_version;
547     nd_uint16_t rpl_dagrank;
548     nd_uint8_t  rpl_mopprf;   /* bit 7=G, 5-3=MOP, 2-0=PRF */
549     nd_uint8_t  rpl_dtsn;     /* Dest. Advertisement Trigger Sequence Number */
550     nd_uint8_t  rpl_flags;    /* no flags defined yet */
551     nd_uint8_t  rpl_resv1;
552     nd_byte     rpl_dagid[DAGID_LEN];
553 };
554 #define RPL_DIO_GROUND_FLAG 0x80
555 #define RPL_DIO_MOP_SHIFT   3
556 #define RPL_DIO_MOP_MASK    (7 << RPL_DIO_MOP_SHIFT)
557 #define RPL_DIO_PRF_SHIFT   0
558 #define RPL_DIO_PRF_MASK    (7 << RPL_DIO_PRF_SHIFT)
559 #define RPL_DIO_GROUNDED(X) ((X)&RPL_DIO_GROUND_FLAG)
560 #define RPL_DIO_MOP(X)      (enum RPL_DIO_MOP)(((X)&RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT)
561 #define RPL_DIO_PRF(X)      (((X)&RPL_DIO_PRF_MASK) >> RPL_DIO_PRF_SHIFT)
562 
563 enum RPL_DIO_MOP {
564     RPL_DIO_NONSTORING= 0x0,
565     RPL_DIO_STORING   = 0x1,
566     RPL_DIO_NONSTORING_MULTICAST = 0x2,
567     RPL_DIO_STORING_MULTICAST    = 0x3
568 };
569 
570 enum RPL_SUBOPT {
571         RPL_OPT_PAD1        = 0,
572         RPL_OPT_PADN        = 1,
573         RPL_DIO_METRICS     = 2,
574         RPL_DIO_ROUTINGINFO = 3,
575         RPL_DIO_CONFIG      = 4,
576         RPL_DAO_RPLTARGET   = 5,
577         RPL_DAO_TRANSITINFO = 6,
578         RPL_DIO_DESTPREFIX  = 8,
579         RPL_DAO_RPLTARGET_DESC=9
580 };
581 
582 struct rpl_genoption {
583     nd_uint8_t rpl_dio_type;
584     nd_uint8_t rpl_dio_len;        /* suboption length, not including type/len */
585 };
586 #define RPL_GENOPTION_LEN	2
587 
588 #define RPL_DIO_LIFETIME_INFINITE   0xffffffff
589 #define RPL_DIO_LIFETIME_DISCONNECT 0
590 
591 struct rpl_dio_destprefix {
592     nd_uint8_t rpl_dio_type;
593     nd_uint8_t rpl_dio_len;
594     nd_uint8_t rpl_dio_prefixlen;        /* in bits */
595     nd_uint8_t rpl_dio_prf;              /* flags, including Route Preference */
596     nd_uint32_t rpl_dio_prefixlifetime;  /* in seconds */
597 #if 0
598     nd_byte     rpl_dio_prefix[0];       /* variable number of bytes */
599 #endif
600 };
601 
602 /* section 6.4.1, DODAG Information Object (DIO) */
603 struct nd_rpl_dao {
604     nd_uint8_t  rpl_instanceid;
605     nd_uint8_t  rpl_flags;      /* bit 7=K, 6=D */
606     nd_uint8_t  rpl_resv;
607     nd_uint8_t  rpl_daoseq;
608     nd_byte     rpl_dagid[DAGID_LEN];   /* present when D set. */
609 };
610 #define ND_RPL_DAO_MIN_LEN	4	/* length without DAGID */
611 
612 /* indicates if this DAO is to be acK'ed */
613 #define RPL_DAO_K_SHIFT   7
614 #define RPL_DAO_K_MASK    (1 << RPL_DAO_K_SHIFT)
615 #define RPL_DAO_K(X)      (((X)&RPL_DAO_K_MASK) >> RPL_DAO_K_SHIFT)
616 
617 /* indicates if the DAGID is present */
618 #define RPL_DAO_D_SHIFT   6
619 #define RPL_DAO_D_MASK    (1 << RPL_DAO_D_SHIFT)
620 #define RPL_DAO_D(X)      (((X)&RPL_DAO_D_MASK) >> RPL_DAO_D_SHIFT)
621 
622 struct rpl_dao_target {
623     nd_uint8_t rpl_dao_type;
624     nd_uint8_t rpl_dao_len;
625     nd_uint8_t rpl_dao_flags;            /* unused */
626     nd_uint8_t rpl_dao_prefixlen;        /* in bits */
627 #if 0
628     nd_byte    rpl_dao_prefix[0];        /* variable number of bytes */
629 #endif
630 };
631 
632 /* section 6.5.1, Destination Advertisement Object Acknowledgement (DAO-ACK) */
633 struct nd_rpl_daoack {
634     nd_uint8_t  rpl_instanceid;
635     nd_uint8_t  rpl_flags;      /* bit 7=D */
636     nd_uint8_t  rpl_daoseq;
637     nd_uint8_t  rpl_status;
638     nd_byte     rpl_dagid[DAGID_LEN];   /* present when D set. */
639 };
640 #define ND_RPL_DAOACK_MIN_LEN	4	/* length without DAGID */
641 /* indicates if the DAGID is present */
642 #define RPL_DAOACK_D_SHIFT   7
643 #define RPL_DAOACK_D_MASK    (1 << RPL_DAOACK_D_SHIFT)
644 #define RPL_DAOACK_D(X)      (((X)&RPL_DAOACK_D_MASK) >> RPL_DAOACK_D_SHIFT)
645 
646 static const struct tok icmp6_type_values[] = {
647     { ICMP6_DST_UNREACH, "destination unreachable"},
648     { ICMP6_PACKET_TOO_BIG, "packet too big"},
649     { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
650     { ICMP6_PARAM_PROB, "parameter problem"},
651     { ICMP6_ECHO_REQUEST, "echo request"},
652     { ICMP6_ECHO_REPLY, "echo reply"},
653     { MLD6_LISTENER_QUERY, "multicast listener query"},
654     { MLD6_LISTENER_REPORT, "multicast listener report"},
655     { MLD6_LISTENER_DONE, "multicast listener done"},
656     { ND_ROUTER_SOLICIT, "router solicitation"},
657     { ND_ROUTER_ADVERT, "router advertisement"},
658     { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
659     { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
660     { ND_REDIRECT, "redirect"},
661     { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
662     { IND_SOLICIT, "inverse neighbor solicitation"},
663     { IND_ADVERT, "inverse neighbor advertisement"},
664     { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
665     { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
666     { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
667     { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
668     { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
669     { ICMP6_WRUREQUEST, "who-are-you request"},
670     { ICMP6_WRUREPLY, "who-are-you reply"},
671     { ICMP6_NI_QUERY, "node information query"},
672     { ICMP6_NI_REPLY, "node information reply"},
673     { MLD6_MTRACE, "mtrace message"},
674     { MLD6_MTRACE_RESP, "mtrace response"},
675     { ND_RPL_MESSAGE,   "RPL"},
676     { 0,	NULL }
677 };
678 
679 static const struct tok icmp6_dst_unreach_code_values[] = {
680     { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
681     { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
682     { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
683     { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
684     { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
685     { 0,	NULL }
686 };
687 
688 static const struct tok icmp6_opt_pi_flag_values[] = {
689     { ND_OPT_PI_FLAG_ONLINK, "onlink" },
690     { ND_OPT_PI_FLAG_AUTO, "auto" },
691     { ND_OPT_PI_FLAG_ROUTER, "router" },
692     { 0,	NULL }
693 };
694 
695 static const struct tok icmp6_opt_ra_flag_values[] = {
696     { ND_RA_FLAG_MANAGED, "managed" },
697     { ND_RA_FLAG_OTHER, "other stateful"},
698     { ND_RA_FLAG_HOME_AGENT, "home agent"},
699     { ND_RA_FLAG_IPV6ONLY, "ipv6 only"},
700     { 0,	NULL }
701 };
702 
703 static const struct tok icmp6_nd_na_flag_values[] = {
704     { ND_NA_FLAG_ROUTER, "router" },
705     { ND_NA_FLAG_SOLICITED, "solicited" },
706     { ND_NA_FLAG_OVERRIDE, "override" },
707     { 0,	NULL }
708 };
709 
710 static const struct tok icmp6_opt_values[] = {
711    { ND_OPT_SOURCE_LINKADDR, "source link-address"},
712    { ND_OPT_TARGET_LINKADDR, "destination link-address"},
713    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
714    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
715    { ND_OPT_MTU, "mtu"},
716    { ND_OPT_RDNSS, "rdnss"},
717    { ND_OPT_DNSSL, "dnssl"},
718    { ND_OPT_ADVINTERVAL, "advertisement interval"},
719    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
720    { ND_OPT_ROUTE_INFO, "route info"},
721    { 0,	NULL }
722 };
723 
724 /* mldv2 report types */
725 static const struct tok mldv2report2str[] = {
726 	{ 1,	"is_in" },
727 	{ 2,	"is_ex" },
728 	{ 3,	"to_in" },
729 	{ 4,	"to_ex" },
730 	{ 5,	"allow" },
731 	{ 6,	"block" },
732 	{ 0,	NULL }
733 };
734 
735 static const char *
736 get_rtpref(u_int v)
737 {
738 	static const char *rtpref_str[] = {
739 		"medium",		/* 00 */
740 		"high",			/* 01 */
741 		"rsv",			/* 10 */
742 		"low"			/* 11 */
743 	};
744 
745 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
746 }
747 
748 static const char *
749 get_lifetime(uint32_t v)
750 {
751 	static char buf[20];
752 
753 	if (v == (uint32_t)~0UL)
754 		return "infinity";
755 	else {
756 		snprintf(buf, sizeof(buf), "%us", v);
757 		return buf;
758 	}
759 }
760 
761 static void
762 print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
763 {
764 	const uint8_t *ep, *q;
765 
766 	q = p;
767 	ep = p + l;
768 	while (l > 0 && q < ep) {
769 		if (q > p)
770                         ND_PRINT(":");
771 		ND_PRINT("%02x", GET_U_1(q));
772 		q++;
773 		l--;
774 	}
775 }
776 
777 static uint16_t icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
778 	const struct icmp6_hdr *icp, u_int len)
779 {
780 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len,
781 				IPPROTO_ICMPV6);
782 }
783 
784 static const struct tok rpl_mop_values[] = {
785         { RPL_DIO_NONSTORING,         "nonstoring"},
786         { RPL_DIO_STORING,            "storing"},
787         { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"},
788         { RPL_DIO_STORING_MULTICAST,  "storing-multicast"},
789         { 0, NULL},
790 };
791 
792 static const struct tok rpl_subopt_values[] = {
793         { RPL_OPT_PAD1, "pad1"},
794         { RPL_OPT_PADN, "padN"},
795         { RPL_DIO_METRICS, "metrics"},
796         { RPL_DIO_ROUTINGINFO, "routinginfo"},
797         { RPL_DIO_CONFIG,    "config"},
798         { RPL_DAO_RPLTARGET, "rpltarget"},
799         { RPL_DAO_TRANSITINFO, "transitinfo"},
800         { RPL_DIO_DESTPREFIX, "destprefix"},
801         { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"},
802         { 0, NULL},
803 };
804 
805 static void
806 rpl_printopts(netdissect_options *ndo, const uint8_t *opts, u_int length)
807 {
808 	const struct rpl_genoption *opt;
809 	uint8_t dio_type;
810 	u_int optlen;
811 
812 	while (length != 0) {
813 		opt = (const struct rpl_genoption *)opts;
814 		dio_type = GET_U_1(opt->rpl_dio_type);
815 		if (dio_type == RPL_OPT_PAD1) {
816                         optlen = 1;
817                         ND_PRINT(" opt:pad1");
818                 } else {
819 			if (length < RPL_GENOPTION_LEN)
820 				goto trunc;
821 	                optlen = GET_U_1(opt->rpl_dio_len)+RPL_GENOPTION_LEN;
822                         ND_PRINT(" opt:%s len:%u ",
823                                   tok2str(rpl_subopt_values, "subopt:%u", dio_type),
824                                   optlen);
825                         ND_TCHECK_LEN(opt, optlen);
826                         if (length < optlen)
827 				goto trunc;
828                         if (ndo->ndo_vflag > 2) {
829                                 hex_print(ndo,
830                                           " ",
831                                           opts + RPL_GENOPTION_LEN,  /* content of DIO option */
832                                           optlen - RPL_GENOPTION_LEN);
833                         }
834                 }
835                 opts += optlen;
836                 length -= optlen;
837         }
838         return;
839 trunc:
840 	nd_print_trunc(ndo);
841 }
842 
843 static void
844 rpl_dio_print(netdissect_options *ndo,
845               const u_char *bp, u_int length)
846 {
847         const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp;
848 
849         ND_LCHECK_ZU(length, sizeof(struct nd_rpl_dio));
850         ND_PRINT(" [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]",
851                   GET_IP6ADDR_STRING(dio->rpl_dagid),
852                   GET_U_1(dio->rpl_dtsn),
853                   GET_U_1(dio->rpl_instanceid),
854                   GET_BE_U_2(dio->rpl_dagrank),
855                   RPL_DIO_GROUNDED(GET_U_1(dio->rpl_mopprf)) ? "grounded,":"",
856                   tok2str(rpl_mop_values, "mop%u",
857                           RPL_DIO_MOP(GET_U_1(dio->rpl_mopprf))),
858                   RPL_DIO_PRF(GET_U_1(dio->rpl_mopprf)));
859 
860         if(ndo->ndo_vflag > 1) {
861                 rpl_printopts(ndo, bp + sizeof(struct nd_rpl_dio),
862                               length - sizeof(struct nd_rpl_dio));
863         }
864         return;
865 invalid:
866         nd_print_invalid(ndo);
867 }
868 
869 static void
870 rpl_dao_print(netdissect_options *ndo,
871               const u_char *bp, u_int length)
872 {
873         const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp;
874         const char *dagid_str = "<elided>";
875         uint8_t rpl_flags;
876 
877         ND_TCHECK_SIZE(dao);
878         if (length < ND_RPL_DAO_MIN_LEN)
879 		goto tooshort;
880 
881         bp += ND_RPL_DAO_MIN_LEN;
882         length -= ND_RPL_DAO_MIN_LEN;
883         rpl_flags = GET_U_1(dao->rpl_flags);
884         if(RPL_DAO_D(rpl_flags)) {
885                 ND_TCHECK_LEN(dao->rpl_dagid, DAGID_LEN);
886                 if (length < DAGID_LEN)
887                         goto tooshort;
888                 dagid_str = ip6addr_string (ndo, dao->rpl_dagid);
889                 bp += DAGID_LEN;
890                 length -= DAGID_LEN;
891         }
892 
893         ND_PRINT(" [dagid:%s,seq:%u,instance:%u%s%s,flags:%02x]",
894                   dagid_str,
895                   GET_U_1(dao->rpl_daoseq),
896                   GET_U_1(dao->rpl_instanceid),
897                   RPL_DAO_K(rpl_flags) ? ",acK":"",
898                   RPL_DAO_D(rpl_flags) ? ",Dagid":"",
899                   rpl_flags);
900 
901         if(ndo->ndo_vflag > 1) {
902                 rpl_printopts(ndo, bp, length);
903         }
904 	return;
905 
906 trunc:
907 	nd_print_trunc(ndo);
908 	return;
909 
910 tooshort:
911 	ND_PRINT(" [|length too short]");
912 }
913 
914 static void
915 rpl_daoack_print(netdissect_options *ndo,
916                  const u_char *bp, u_int length)
917 {
918         const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp;
919         const char *dagid_str = "<elided>";
920 
921         ND_TCHECK_LEN(daoack, ND_RPL_DAOACK_MIN_LEN);
922         if (length < ND_RPL_DAOACK_MIN_LEN)
923 		goto tooshort;
924 
925         bp += ND_RPL_DAOACK_MIN_LEN;
926         length -= ND_RPL_DAOACK_MIN_LEN;
927         if(RPL_DAOACK_D(GET_U_1(daoack->rpl_flags))) {
928                 ND_TCHECK_LEN(daoack->rpl_dagid, DAGID_LEN);
929                 if (length < DAGID_LEN)
930                         goto tooshort;
931                 dagid_str = ip6addr_string (ndo, daoack->rpl_dagid);
932                 bp += DAGID_LEN;
933                 length -= DAGID_LEN;
934         }
935 
936         ND_PRINT(" [dagid:%s,seq:%u,instance:%u,status:%u]",
937                   dagid_str,
938                   GET_U_1(daoack->rpl_daoseq),
939                   GET_U_1(daoack->rpl_instanceid),
940                   GET_U_1(daoack->rpl_status));
941 
942         /* no officially defined options for DAOACK, but print any we find */
943         if(ndo->ndo_vflag > 1) {
944                 rpl_printopts(ndo, bp, length);
945         }
946 	return;
947 
948 trunc:
949 	nd_print_trunc(ndo);
950 	return;
951 
952 tooshort:
953 	ND_PRINT(" [|dao-length too short]");
954 }
955 
956 UNALIGNED_OK
957 static void
958 rpl_print(netdissect_options *ndo,
959           uint8_t icmp6_code,
960           const u_char *bp, u_int length)
961 {
962         int secured = icmp6_code & 0x80;
963         int basecode= icmp6_code & 0x7f;
964 
965         if(secured) {
966                 ND_PRINT(", (SEC) [worktodo]");
967                 /* XXX
968                  * the next header pointer needs to move forward to
969                  * skip the secure part.
970                  */
971                 return;
972         } else {
973                 ND_PRINT(", (CLR)");
974         }
975 
976         switch(basecode) {
977         case ND_RPL_DAG_IS:
978                 ND_PRINT("DODAG Information Solicitation");
979                 if(ndo->ndo_vflag) {
980                 }
981                 break;
982         case ND_RPL_DAG_IO:
983                 ND_PRINT("DODAG Information Object");
984                 if(ndo->ndo_vflag) {
985                         rpl_dio_print(ndo, bp, length);
986                 }
987                 break;
988         case ND_RPL_DAO:
989                 ND_PRINT("Destination Advertisement Object");
990                 if(ndo->ndo_vflag) {
991                         rpl_dao_print(ndo, bp, length);
992                 }
993                 break;
994         case ND_RPL_DAO_ACK:
995                 ND_PRINT("Destination Advertisement Object Ack");
996                 if(ndo->ndo_vflag) {
997                         rpl_daoack_print(ndo, bp, length);
998                 }
999                 break;
1000         default:
1001                 ND_PRINT("RPL message, unknown code %u",icmp6_code);
1002                 break;
1003         }
1004 	return;
1005 
1006 #if 0
1007 trunc:
1008 	nd_print_trunc(ndo);
1009 	return;
1010 #endif
1011 
1012 }
1013 
1014 void
1015 icmp6_print(netdissect_options *ndo,
1016             const u_char *bp, u_int length, const u_char *bp2, int fragmented)
1017 {
1018 	const struct icmp6_hdr *dp;
1019 	uint8_t icmp6_type, icmp6_code;
1020 	const struct ip6_hdr *ip;
1021 	const struct ip6_hdr *oip;
1022 	const struct udphdr *ouh;
1023 	uint16_t dport;
1024 	const u_char *ep;
1025 	u_int prot;
1026 
1027 	ndo->ndo_protocol = "icmp6";
1028 	dp = (const struct icmp6_hdr *)bp;
1029 	ip = (const struct ip6_hdr *)bp2;
1030 	oip = (const struct ip6_hdr *)(dp + 1);
1031 	/* 'ep' points to the end of available data. */
1032 	ep = ndo->ndo_snapend;
1033 	if (length == 0) {
1034 		ND_PRINT("ICMP6, length 0");
1035 		nd_print_invalid(ndo);
1036 		return;
1037 	}
1038 
1039 	if (ndo->ndo_vflag && !fragmented) {
1040 		uint16_t sum, udp_sum;
1041 
1042 		if (ND_TTEST_LEN(bp, length)) {
1043 			udp_sum = GET_BE_U_2(dp->icmp6_cksum);
1044 			sum = icmp6_cksum(ndo, ip, dp, length);
1045 			if (sum != 0)
1046 				ND_PRINT("[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
1047                                                 udp_sum,
1048                                                 in_cksum_shouldbe(udp_sum, sum));
1049 			else
1050 				ND_PRINT("[icmp6 sum ok] ");
1051 		}
1052 	}
1053 
1054 	icmp6_type = GET_U_1(dp->icmp6_type);
1055 	ND_PRINT("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",icmp6_type));
1056 
1057         /* display cosmetics: print the packet length for printer that use the vflag now */
1058         if (ndo->ndo_vflag && (icmp6_type == ND_ROUTER_SOLICIT ||
1059                       icmp6_type == ND_ROUTER_ADVERT ||
1060                       icmp6_type == ND_NEIGHBOR_ADVERT ||
1061                       icmp6_type == ND_NEIGHBOR_SOLICIT ||
1062                       icmp6_type == ND_REDIRECT ||
1063                       icmp6_type == ICMP6_HADISCOV_REPLY ||
1064                       icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
1065                 ND_PRINT(", length %u", length);
1066 
1067 	icmp6_code = GET_U_1(dp->icmp6_code);
1068 
1069 	switch (icmp6_type) {
1070 	case ICMP6_DST_UNREACH:
1071                 ND_PRINT(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",icmp6_code));
1072 		switch (icmp6_code) {
1073 
1074 		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
1075 		case ICMP6_DST_UNREACH_ADMIN:
1076 		case ICMP6_DST_UNREACH_ADDR:
1077                         ND_PRINT(" %s",GET_IP6ADDR_STRING(oip->ip6_dst));
1078                         break;
1079 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
1080 			ND_PRINT(" %s, source address %s",
1081 			       GET_IP6ADDR_STRING(oip->ip6_dst),
1082                                   GET_IP6ADDR_STRING(oip->ip6_src));
1083 			break;
1084 		case ICMP6_DST_UNREACH_NOPORT:
1085 			if ((ouh = get_upperlayer(ndo, (const u_char *)oip, &prot))
1086 			    == NULL)
1087 				goto trunc;
1088 
1089 			dport = GET_BE_U_2(ouh->uh_dport);
1090 			switch (prot) {
1091 			case IPPROTO_TCP:
1092 				ND_PRINT(", %s tcp port %s",
1093 					GET_IP6ADDR_STRING(oip->ip6_dst),
1094                                           tcpport_string(ndo, dport));
1095 				break;
1096 			case IPPROTO_UDP:
1097 				ND_PRINT(", %s udp port %s",
1098 					GET_IP6ADDR_STRING(oip->ip6_dst),
1099                                           udpport_string(ndo, dport));
1100 				break;
1101 			default:
1102 				ND_PRINT(", %s protocol %u port %u unreachable",
1103 					GET_IP6ADDR_STRING(oip->ip6_dst),
1104                                           prot, dport);
1105 				break;
1106 			}
1107 			break;
1108 		default:
1109                   if (ndo->ndo_vflag <= 1) {
1110                     print_unknown_data(ndo, bp,"\n\t",length);
1111                     return;
1112                   }
1113                     break;
1114 		}
1115 		break;
1116 	case ICMP6_PACKET_TOO_BIG:
1117 		ND_PRINT(", mtu %u", GET_BE_U_4(dp->icmp6_mtu));
1118 		break;
1119 	case ICMP6_TIME_EXCEEDED:
1120 		switch (icmp6_code) {
1121 		case ICMP6_TIME_EXCEED_TRANSIT:
1122 			ND_PRINT(" for %s",
1123                                   GET_IP6ADDR_STRING(oip->ip6_dst));
1124 			break;
1125 		case ICMP6_TIME_EXCEED_REASSEMBLY:
1126 			ND_PRINT(" (reassembly)");
1127 			break;
1128 		default:
1129                         ND_PRINT(", unknown code (%u)", icmp6_code);
1130 			break;
1131 		}
1132 		break;
1133 	case ICMP6_PARAM_PROB:
1134 		ND_TCHECK_16(oip->ip6_dst);
1135 		switch (icmp6_code) {
1136 		case ICMP6_PARAMPROB_HEADER:
1137                         ND_PRINT(", erroneous - octet %u",
1138 				 GET_BE_U_4(dp->icmp6_pptr));
1139                         break;
1140 		case ICMP6_PARAMPROB_NEXTHEADER:
1141                         ND_PRINT(", next header - octet %u",
1142 				 GET_BE_U_4(dp->icmp6_pptr));
1143                         break;
1144 		case ICMP6_PARAMPROB_OPTION:
1145                         ND_PRINT(", option - octet %u",
1146 				 GET_BE_U_4(dp->icmp6_pptr));
1147                         break;
1148 		case ICMP6_PARAMPROB_FRAGHDRCHAIN:
1149                         ND_PRINT(", incomplete header chain - octet %u",
1150 				 GET_BE_U_4(dp->icmp6_pptr));
1151                         break;
1152 		default:
1153                         ND_PRINT(", code-#%u",
1154                                   icmp6_code);
1155                         break;
1156 		}
1157 		break;
1158 	case ICMP6_ECHO_REQUEST:
1159 	case ICMP6_ECHO_REPLY:
1160                 ND_PRINT(", id %u, seq %u", GET_BE_U_2(dp->icmp6_id),
1161 			 GET_BE_U_2(dp->icmp6_seq));
1162 		break;
1163 	case ICMP6_MEMBERSHIP_QUERY:
1164 		if (length == MLD_MINLEN) {
1165 			mld6_print(ndo, (const u_char *)dp);
1166 		} else if (length >= MLDV2_MINLEN) {
1167 			ND_PRINT(" v2");
1168 			mldv2_query_print(ndo, (const u_char *)dp, length);
1169 		} else {
1170                         ND_PRINT(" unknown-version (len %u) ", length);
1171 		}
1172 		break;
1173 	case ICMP6_MEMBERSHIP_REPORT:
1174 		mld6_print(ndo, (const u_char *)dp);
1175 		break;
1176 	case ICMP6_MEMBERSHIP_REDUCTION:
1177 		mld6_print(ndo, (const u_char *)dp);
1178 		break;
1179 	case ND_ROUTER_SOLICIT:
1180 #define RTSOLLEN 8
1181 		if (ndo->ndo_vflag) {
1182 			if (icmp6_opt_print(ndo, (const u_char *)dp + RTSOLLEN,
1183 					    length - RTSOLLEN) == -1)
1184 				goto trunc;
1185 		}
1186 		break;
1187 	case ND_ROUTER_ADVERT:
1188 #define RTADVLEN 16
1189 		if (ndo->ndo_vflag) {
1190 			const struct nd_router_advert *p;
1191 
1192 			p = (const struct nd_router_advert *)dp;
1193 			ND_PRINT("\n\thop limit %u, Flags [%s]"
1194                                   ", pref %s, router lifetime %us, reachable time %ums, retrans timer %ums",
1195                                   GET_U_1(p->nd_ra_curhoplimit),
1196                                   bittok2str(icmp6_opt_ra_flag_values,"none",GET_U_1(p->nd_ra_flags_reserved)),
1197                                   get_rtpref(GET_U_1(p->nd_ra_flags_reserved)),
1198                                   GET_BE_U_2(p->nd_ra_router_lifetime),
1199                                   GET_BE_U_4(p->nd_ra_reachable),
1200                                   GET_BE_U_4(p->nd_ra_retransmit));
1201 
1202 			if (icmp6_opt_print(ndo, (const u_char *)dp + RTADVLEN,
1203 					    length - RTADVLEN) == -1)
1204 				goto trunc;
1205 		}
1206 		break;
1207 	case ND_NEIGHBOR_SOLICIT:
1208 	    {
1209 		const struct nd_neighbor_solicit *p;
1210 		p = (const struct nd_neighbor_solicit *)dp;
1211 		ND_PRINT(", who has %s", GET_IP6ADDR_STRING(p->nd_ns_target));
1212 		if (ndo->ndo_vflag) {
1213 #define NDSOLLEN 24
1214 			if (icmp6_opt_print(ndo, (const u_char *)dp + NDSOLLEN,
1215 					    length - NDSOLLEN) == -1)
1216 				goto trunc;
1217 		}
1218 	    }
1219 		break;
1220 	case ND_NEIGHBOR_ADVERT:
1221 	    {
1222 		const struct nd_neighbor_advert *p;
1223 
1224 		p = (const struct nd_neighbor_advert *)dp;
1225 		ND_PRINT(", tgt is %s",
1226                           GET_IP6ADDR_STRING(p->nd_na_target));
1227 		if (ndo->ndo_vflag) {
1228                         ND_PRINT(", Flags [%s]",
1229                                   bittok2str(icmp6_nd_na_flag_values,
1230                                              "none",
1231                                              GET_BE_U_4(p->nd_na_flags_reserved)));
1232 #define NDADVLEN 24
1233 			if (icmp6_opt_print(ndo, (const u_char *)dp + NDADVLEN,
1234 					    length - NDADVLEN) == -1)
1235 				goto trunc;
1236 #undef NDADVLEN
1237 		}
1238 	    }
1239 		break;
1240 	case ND_REDIRECT:
1241 	    {
1242 		const struct nd_redirect *p;
1243 
1244 		p = (const struct nd_redirect *)dp;
1245 		ND_PRINT(", %s", GET_IP6ADDR_STRING(p->nd_rd_dst));
1246 		ND_PRINT(" to %s", GET_IP6ADDR_STRING(p->nd_rd_target));
1247 #define REDIRECTLEN 40
1248 		if (ndo->ndo_vflag) {
1249 			if (icmp6_opt_print(ndo, (const u_char *)dp + REDIRECTLEN,
1250 					    length - REDIRECTLEN) == -1)
1251 				goto trunc;
1252 #undef REDIRECTLEN
1253 		}
1254 	    }
1255 		break;
1256 	case ICMP6_ROUTER_RENUMBERING:
1257 		icmp6_rrenum_print(ndo, bp, ep);
1258 		break;
1259 	case ICMP6_NI_QUERY:
1260 	case ICMP6_NI_REPLY:
1261 		icmp6_nodeinfo_print(ndo, length, bp, ep);
1262 		break;
1263 	case IND_SOLICIT:
1264 	case IND_ADVERT:
1265 		break;
1266 	case ICMP6_V2_MEMBERSHIP_REPORT:
1267 		mldv2_report_print(ndo, (const u_char *) dp, length);
1268 		break;
1269 	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
1270 	case ICMP6_HADISCOV_REQUEST:
1271                 ND_PRINT(", id 0x%04x", GET_BE_U_2(dp->icmp6_data16[0]));
1272                 break;
1273 	case ICMP6_HADISCOV_REPLY:
1274 		if (ndo->ndo_vflag) {
1275 			const u_char *cp;
1276 			const u_char *p;
1277 
1278 			ND_PRINT(", id 0x%04x",
1279 				 GET_BE_U_2(dp->icmp6_data16[0]));
1280 			cp = (const u_char *)dp + length;
1281 			p = (const u_char *)(dp + 1);
1282 			while (p < cp) {
1283 				ND_PRINT(", %s", GET_IP6ADDR_STRING(p));
1284 				p += 16;
1285 			}
1286 		}
1287 		break;
1288 	case ICMP6_MOBILEPREFIX_ADVERT:
1289 		if (ndo->ndo_vflag) {
1290 			uint16_t flags;
1291 
1292 			ND_PRINT(", id 0x%04x",
1293 				 GET_BE_U_2(dp->icmp6_data16[0]));
1294 			flags = GET_BE_U_2(dp->icmp6_data16[1]);
1295 			if (flags & 0xc000)
1296 				ND_PRINT(" ");
1297 			if (flags & 0x8000)
1298 				ND_PRINT("M");
1299 			if (flags & 0x4000)
1300 				ND_PRINT("O");
1301 #define MPADVLEN 8
1302 			if (icmp6_opt_print(ndo, (const u_char *)dp + MPADVLEN,
1303 					    length - MPADVLEN) == -1)
1304 				goto trunc;
1305 		}
1306 		break;
1307         case ND_RPL_MESSAGE:
1308                 /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */
1309                 rpl_print(ndo, icmp6_code, dp->icmp6_data, length-sizeof(struct icmp6_hdr)+4);
1310                 break;
1311 	default:
1312                 ND_PRINT(", length %u", length);
1313                 if (ndo->ndo_vflag <= 1)
1314                         print_unknown_data(ndo, bp,"\n\t", length);
1315                 return;
1316         }
1317         if (!ndo->ndo_vflag)
1318                 ND_PRINT(", length %u", length);
1319 	return;
1320 trunc:
1321 	nd_print_trunc(ndo);
1322 }
1323 
1324 static const struct udphdr *
1325 get_upperlayer(netdissect_options *ndo, const u_char *bp, u_int *prot)
1326 {
1327 	const u_char *ep;
1328 	const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
1329 	const struct udphdr *uh;
1330 	const struct ip6_hbh *hbh;
1331 	const struct ip6_frag *fragh;
1332 	const struct ah *ah;
1333 	u_int nh;
1334 	int hlen;
1335 
1336 	/* 'ep' points to the end of available data. */
1337 	ep = ndo->ndo_snapend;
1338 
1339 	if (!ND_TTEST_1(ip6->ip6_nxt))
1340 		return NULL;
1341 
1342 	nh = GET_U_1(ip6->ip6_nxt);
1343 	hlen = sizeof(struct ip6_hdr);
1344 
1345 	while (bp < ep) {
1346 		bp += hlen;
1347 
1348 		switch(nh) {
1349 		case IPPROTO_UDP:
1350 		case IPPROTO_TCP:
1351 			uh = (const struct udphdr *)bp;
1352 			if (ND_TTEST_2(uh->uh_dport)) {
1353 				*prot = nh;
1354 				return(uh);
1355 			}
1356 			else
1357 				return(NULL);
1358 			/* NOTREACHED */
1359 
1360 		case IPPROTO_HOPOPTS:
1361 		case IPPROTO_DSTOPTS:
1362 		case IPPROTO_ROUTING:
1363 			hbh = (const struct ip6_hbh *)bp;
1364 			if (!ND_TTEST_1(hbh->ip6h_len))
1365 				return(NULL);
1366 			nh = GET_U_1(hbh->ip6h_nxt);
1367 			hlen = (GET_U_1(hbh->ip6h_len) + 1) << 3;
1368 			break;
1369 
1370 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
1371 			fragh = (const struct ip6_frag *)bp;
1372 			if (!ND_TTEST_2(fragh->ip6f_offlg))
1373 				return(NULL);
1374 			/* fragments with non-zero offset are meaningless */
1375 			if ((GET_BE_U_2(fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
1376 				return(NULL);
1377 			nh = GET_U_1(fragh->ip6f_nxt);
1378 			hlen = sizeof(struct ip6_frag);
1379 			break;
1380 
1381 		case IPPROTO_AH:
1382 			ah = (const struct ah *)bp;
1383 			if (!ND_TTEST_1(ah->ah_len))
1384 				return(NULL);
1385 			nh = GET_U_1(ah->ah_nxt);
1386 			hlen = (GET_U_1(ah->ah_len) + 2) << 2;
1387 			break;
1388 
1389 		default:	/* unknown or undecodable header */
1390 			*prot = nh; /* meaningless, but set here anyway */
1391 			return(NULL);
1392 		}
1393 	}
1394 
1395 	return(NULL);		/* should be notreached, though */
1396 }
1397 
1398 static int
1399 icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
1400 {
1401 	const struct nd_opt_hdr *op;
1402 	uint8_t opt_type;
1403 	u_int opt_len;
1404 	const struct nd_opt_prefix_info *opp;
1405 	const struct nd_opt_mtu *opm;
1406 	const struct nd_opt_rdnss *oprd;
1407 	const struct nd_opt_dnssl *opds;
1408 	const struct nd_opt_advinterval *opa;
1409 	const struct nd_opt_homeagent_info *oph;
1410 	const struct nd_opt_route_info *opri;
1411 	const u_char *cp, *ep, *domp;
1412 	nd_ipv6 in6;
1413 	size_t l;
1414 	u_int i;
1415 
1416 	cp = bp;
1417 	/* 'ep' points to the end of available data. */
1418 	ep = ndo->ndo_snapend;
1419 
1420 	while (cp < ep) {
1421 		op = (const struct nd_opt_hdr *)cp;
1422 
1423 		ND_TCHECK_1(op->nd_opt_len);
1424 		if (resid <= 0)
1425 			return 0;
1426 		opt_type = GET_U_1(op->nd_opt_type);
1427 		opt_len = GET_U_1(op->nd_opt_len);
1428 		if (opt_len == 0)
1429 			goto trunc;
1430 		if (cp + (opt_len << 3) > ep)
1431 			goto trunc;
1432 
1433                 ND_PRINT("\n\t  %s option (%u), length %u (%u): ",
1434                           tok2str(icmp6_opt_values, "unknown", opt_type),
1435                           opt_type,
1436                           opt_len << 3,
1437                           opt_len);
1438 
1439 		switch (opt_type) {
1440 		case ND_OPT_SOURCE_LINKADDR:
1441 			l = (opt_len << 3) - 2;
1442 			print_lladdr(ndo, cp + 2, l);
1443 			break;
1444 		case ND_OPT_TARGET_LINKADDR:
1445 			l = (opt_len << 3) - 2;
1446 			print_lladdr(ndo, cp + 2, l);
1447 			break;
1448 		case ND_OPT_PREFIX_INFORMATION:
1449 			opp = (const struct nd_opt_prefix_info *)op;
1450                         ND_PRINT("%s/%u%s, Flags [%s], valid time %s",
1451                                   GET_IP6ADDR_STRING(opp->nd_opt_pi_prefix),
1452                                   GET_U_1(opp->nd_opt_pi_prefix_len),
1453                                   (opt_len != 4) ? "badlen" : "",
1454                                   bittok2str(icmp6_opt_pi_flag_values, "none", GET_U_1(opp->nd_opt_pi_flags_reserved)),
1455                                   get_lifetime(GET_BE_U_4(opp->nd_opt_pi_valid_time)));
1456                         ND_PRINT(", pref. time %s",
1457 				 get_lifetime(GET_BE_U_4(opp->nd_opt_pi_preferred_time)));
1458 			break;
1459 		case ND_OPT_REDIRECTED_HEADER:
1460                         print_unknown_data(ndo, bp,"\n\t    ",opt_len<<3);
1461 			/* xxx */
1462 			break;
1463 		case ND_OPT_MTU:
1464 			opm = (const struct nd_opt_mtu *)op;
1465 			ND_PRINT(" %u%s",
1466                                GET_BE_U_4(opm->nd_opt_mtu_mtu),
1467                                (opt_len != 1) ? "bad option length" : "" );
1468                         break;
1469 		case ND_OPT_RDNSS:
1470 			oprd = (const struct nd_opt_rdnss *)op;
1471 			l = (opt_len - 1) / 2;
1472 			ND_PRINT(" lifetime %us,",
1473                                   GET_BE_U_4(oprd->nd_opt_rdnss_lifetime));
1474 			for (i = 0; i < l; i++) {
1475 				ND_PRINT(" addr: %s",
1476                                           GET_IP6ADDR_STRING(oprd->nd_opt_rdnss_addr[i]));
1477 			}
1478 			break;
1479 		case ND_OPT_DNSSL:
1480 			opds = (const struct nd_opt_dnssl *)op;
1481 			ND_PRINT(" lifetime %us, domain(s):",
1482                                   GET_BE_U_4(opds->nd_opt_dnssl_lifetime));
1483 			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
1484 			while (domp < cp + (opt_len << 3) && GET_U_1(domp) != '\0')
1485 			{
1486 				ND_PRINT(" ");
1487 				if ((domp = fqdn_print(ndo, domp, bp)) == NULL)
1488 					goto trunc;
1489 			}
1490 			break;
1491 		case ND_OPT_ADVINTERVAL:
1492 			opa = (const struct nd_opt_advinterval *)op;
1493 			ND_PRINT(" %ums",
1494 				 GET_BE_U_4(opa->nd_opt_adv_interval));
1495 			break;
1496                 case ND_OPT_HOMEAGENT_INFO:
1497 			oph = (const struct nd_opt_homeagent_info *)op;
1498 			ND_PRINT(" preference %u, lifetime %u",
1499                                   GET_BE_U_2(oph->nd_opt_hai_preference),
1500                                   GET_BE_U_2(oph->nd_opt_hai_lifetime));
1501 			break;
1502 		case ND_OPT_ROUTE_INFO:
1503 			opri = (const struct nd_opt_route_info *)op;
1504 			ND_TCHECK_4(opri->nd_opt_rti_lifetime);
1505 			memset(&in6, 0, sizeof(in6));
1506 			switch (opt_len) {
1507 			case 1:
1508 				break;
1509 			case 2:
1510 				GET_CPY_BYTES(&in6, opri + 1, 8);
1511 				break;
1512 			case 3:
1513 				GET_CPY_BYTES(&in6, opri + 1, 16);
1514 				break;
1515 			default:
1516 				goto trunc;
1517 			}
1518 			ND_PRINT(" %s/%u", ip6addr_string(ndo, (const u_char *)&in6), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */
1519                                   GET_U_1(opri->nd_opt_rti_prefixlen));
1520 			ND_PRINT(", pref=%s",
1521 				 get_rtpref(GET_U_1(opri->nd_opt_rti_flags)));
1522 			ND_PRINT(", lifetime=%s",
1523                                   get_lifetime(GET_BE_U_4(opri->nd_opt_rti_lifetime)));
1524 			break;
1525 		default:
1526                         if (ndo->ndo_vflag <= 1) {
1527                                 print_unknown_data(ndo,cp+2,"\n\t  ", (opt_len << 3) - 2); /* skip option header */
1528                             return 0;
1529                         }
1530                         break;
1531 		}
1532                 /* do we want to see an additional hexdump ? */
1533                 if (ndo->ndo_vflag> 1)
1534                         print_unknown_data(ndo, cp+2,"\n\t    ", (opt_len << 3) - 2); /* skip option header */
1535 
1536 		cp += opt_len << 3;
1537 		resid -= opt_len << 3;
1538 	}
1539 	return 0;
1540 
1541 trunc:
1542 	return -1;
1543 }
1544 
1545 UNALIGNED_OK
1546 static void
1547 mld6_print(netdissect_options *ndo, const u_char *bp)
1548 {
1549 	const struct mld6_hdr *mp = (const struct mld6_hdr *)bp;
1550 	const u_char *ep;
1551 
1552 	/* 'ep' points to the end of available data. */
1553 	ep = ndo->ndo_snapend;
1554 
1555 	if ((const u_char *)mp + sizeof(*mp) > ep)
1556 		return;
1557 
1558 	ND_PRINT("max resp delay: %u ", GET_BE_U_2(mp->mld6_maxdelay));
1559 	ND_PRINT("addr: %s", GET_IP6ADDR_STRING(mp->mld6_addr));
1560 }
1561 
1562 UNALIGNED_OK
1563 static void
1564 mldv2_report_print(netdissect_options *ndo, const u_char *bp, u_int len)
1565 {
1566     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1567     u_int group, nsrcs, ngroups;
1568     u_int i, j;
1569 
1570     /* Minimum len is 8 */
1571     if (len < 8) {
1572             ND_PRINT(" [invalid len %u]", len);
1573             return;
1574     }
1575 
1576     ngroups = GET_BE_U_2(icp->icmp6_data16[1]);
1577     ND_PRINT(", %u group record(s)", ngroups);
1578     if (ndo->ndo_vflag > 0) {
1579 	/* Print the group records */
1580 	group = 8;
1581         for (i = 0; i < ngroups; i++) {
1582 	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
1583 	    if (len < group + 20) {
1584                     ND_PRINT(" [invalid number of groups]");
1585                     return;
1586 	    }
1587             ND_PRINT(" [gaddr %s", GET_IP6ADDR_STRING(bp + group + 4));
1588 	    ND_PRINT(" %s", tok2str(mldv2report2str, " [v2-report-#%u]",
1589                                          GET_U_1(bp + group)));
1590             nsrcs = GET_BE_U_2(bp + group + 2);
1591 	    /* Check the number of sources and print them */
1592 	    if (len < group + 20 + (nsrcs * sizeof(nd_ipv6))) {
1593                     ND_PRINT(" [invalid number of sources %u]", nsrcs);
1594                     return;
1595 	    }
1596             if (ndo->ndo_vflag == 1)
1597                     ND_PRINT(", %u source(s)", nsrcs);
1598             else {
1599 		/* Print the sources */
1600                     ND_PRINT(" {");
1601                 for (j = 0; j < nsrcs; j++) {
1602 		    ND_PRINT(" %s", GET_IP6ADDR_STRING(bp + group + 20 + (j * sizeof(nd_ipv6))));
1603 		}
1604                 ND_PRINT(" }");
1605             }
1606 	    /* Next group record */
1607             group += 20 + nsrcs * sizeof(nd_ipv6);
1608 	    ND_PRINT("]");
1609         }
1610     }
1611 }
1612 
1613 UNALIGNED_OK
1614 static void
1615 mldv2_query_print(netdissect_options *ndo, const u_char *bp, u_int len)
1616 {
1617     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1618     u_int mrc;
1619     u_int mrt, qqi;
1620     u_int nsrcs;
1621     u_int i;
1622 
1623     /* Minimum len is 28 */
1624     if (len < 28) {
1625         ND_PRINT(" [invalid len %u]", len);
1626 	return;
1627     }
1628     mrc = GET_BE_U_2(icp->icmp6_data16[0]);
1629     if (mrc < 32768) {
1630 	mrt = mrc;
1631     } else {
1632         mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
1633     }
1634     if (ndo->ndo_vflag) {
1635             ND_PRINT(" [max resp delay=%u]", mrt);
1636     }
1637     ND_PRINT(" [gaddr %s", GET_IP6ADDR_STRING(bp + 8));
1638 
1639     if (ndo->ndo_vflag) {
1640 	if (GET_U_1(bp + 24) & 0x08) {
1641 		ND_PRINT(" sflag");
1642 	}
1643 	if (GET_U_1(bp + 24) & 0x07) {
1644 		ND_PRINT(" robustness=%u", GET_U_1(bp + 24) & 0x07);
1645 	}
1646 	if (GET_U_1(bp + 25) < 128) {
1647 		qqi = GET_U_1(bp + 25);
1648 	} else {
1649 		qqi = ((GET_U_1(bp + 25) & 0x0f) | 0x10) <<
1650 		       (((GET_U_1(bp + 25) & 0x70) >> 4) + 3);
1651 	}
1652 	ND_PRINT(" qqi=%u", qqi);
1653     }
1654 
1655     nsrcs = GET_BE_U_2(bp + 26);
1656     if (nsrcs > 0) {
1657 	if (len < 28 + nsrcs * sizeof(nd_ipv6))
1658 	    ND_PRINT(" [invalid number of sources]");
1659 	else if (ndo->ndo_vflag > 1) {
1660 	    ND_PRINT(" {");
1661 	    for (i = 0; i < nsrcs; i++) {
1662 		ND_PRINT(" %s", GET_IP6ADDR_STRING(bp + 28 + (i * sizeof(nd_ipv6))));
1663 	    }
1664 	    ND_PRINT(" }");
1665 	} else
1666                 ND_PRINT(", %u source(s)", nsrcs);
1667     }
1668     ND_PRINT("]");
1669 }
1670 
1671 static void
1672 dnsname_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
1673 {
1674 	int i;
1675 
1676 	/* DNS name decoding - no decompression */
1677 	ND_PRINT(", \"");
1678 	while (cp < ep) {
1679 		i = GET_U_1(cp);
1680 		cp++;
1681 		if (i) {
1682 			if (i > ep - cp) {
1683 				ND_PRINT("???");
1684 				break;
1685 			}
1686 			while (i-- && cp < ep) {
1687 				fn_print_char(ndo, GET_U_1(cp));
1688 				cp++;
1689 			}
1690 			if (cp + 1 < ep && GET_U_1(cp))
1691 				ND_PRINT(".");
1692 		} else {
1693 			if (cp == ep) {
1694 				/* FQDN */
1695 				ND_PRINT(".");
1696 			} else if (cp + 1 == ep && GET_U_1(cp) == '\0') {
1697 				/* truncated */
1698 			} else {
1699 				/* invalid */
1700 				ND_PRINT("???");
1701 			}
1702 			break;
1703 		}
1704 	}
1705 	ND_PRINT("\"");
1706 }
1707 
1708 static void
1709 icmp6_nodeinfo_print(netdissect_options *ndo, u_int icmp6len, const u_char *bp, const u_char *ep)
1710 {
1711 	const struct icmp6_nodeinfo *ni6;
1712 	const struct icmp6_hdr *dp;
1713 	const u_char *cp;
1714 	size_t siz, i;
1715 	int needcomma;
1716 
1717 	if (ep < bp)
1718 		return;
1719 	dp = (const struct icmp6_hdr *)bp;
1720 	ni6 = (const struct icmp6_nodeinfo *)bp;
1721 	siz = ep - bp;
1722 
1723 	switch (GET_U_1(ni6->ni_type)) {
1724 	case ICMP6_NI_QUERY:
1725 		if (siz == sizeof(*dp) + 4) {
1726 			/* KAME who-are-you */
1727 			ND_PRINT(" who-are-you request");
1728 			break;
1729 		}
1730 		ND_PRINT(" node information query");
1731 
1732 		ND_TCHECK_LEN(dp, sizeof(*ni6));
1733 		ni6 = (const struct icmp6_nodeinfo *)dp;
1734 		ND_PRINT(" (");	/*)*/
1735 		switch (GET_BE_U_2(ni6->ni_qtype)) {
1736 		case NI_QTYPE_NOOP:
1737 			ND_PRINT("noop");
1738 			break;
1739 		case NI_QTYPE_SUPTYPES:
1740 			ND_PRINT("supported qtypes");
1741 			i = GET_BE_U_2(ni6->ni_flags);
1742 			if (i)
1743 				ND_PRINT(" [%s]", (i & 0x01) ? "C" : "");
1744 			break;
1745 		case NI_QTYPE_FQDN:
1746 			ND_PRINT("DNS name");
1747 			break;
1748 		case NI_QTYPE_NODEADDR:
1749 			ND_PRINT("node addresses");
1750 			i = GET_BE_U_2(ni6->ni_flags);
1751 			if (!i)
1752 				break;
1753 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
1754 			ND_PRINT(" [%s%s%s%s%s%s]",
1755 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1756 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1757 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1758 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1759 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1760 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
1761 			break;
1762 		default:
1763 			ND_PRINT("unknown");
1764 			break;
1765 		}
1766 
1767 		if (GET_BE_U_2(ni6->ni_qtype) == NI_QTYPE_NOOP ||
1768 		    GET_BE_U_2(ni6->ni_qtype) == NI_QTYPE_SUPTYPES) {
1769 			if (siz != sizeof(*ni6))
1770 				if (ndo->ndo_vflag)
1771 					ND_PRINT(", invalid len");
1772 			/*(*/
1773 			ND_PRINT(")");
1774 			break;
1775 		}
1776 
1777 		/* XXX backward compat, icmp-name-lookup-03 */
1778 		if (siz == sizeof(*ni6)) {
1779 			ND_PRINT(", 03 draft");
1780 			/*(*/
1781 			ND_PRINT(")");
1782 			break;
1783 		}
1784 
1785 		cp = (const u_char *)(ni6 + 1);
1786 		switch (GET_U_1(ni6->ni_code)) {
1787 		case ICMP6_NI_SUBJ_IPV6:
1788 			if (!ND_TTEST_LEN(dp, sizeof(*ni6) + sizeof(nd_ipv6)))
1789 				break;
1790 			if (siz != sizeof(*ni6) + sizeof(nd_ipv6)) {
1791 				if (ndo->ndo_vflag)
1792 					ND_PRINT(", invalid subject len");
1793 				break;
1794 			}
1795 			ND_PRINT(", subject=%s",
1796                                   GET_IP6ADDR_STRING(cp));
1797 			break;
1798 		case ICMP6_NI_SUBJ_FQDN:
1799 			ND_PRINT(", subject=DNS name");
1800 			if (GET_U_1(cp) == ep - cp - 1) {
1801 				/* icmp-name-lookup-03, pascal string */
1802 				if (ndo->ndo_vflag)
1803 					ND_PRINT(", 03 draft");
1804 				cp++;
1805 				ND_PRINT(", \"");
1806 				while (cp < ep) {
1807 					fn_print_char(ndo, GET_U_1(cp));
1808 					cp++;
1809 				}
1810 				ND_PRINT("\"");
1811 			} else
1812 				dnsname_print(ndo, cp, ep);
1813 			break;
1814 		case ICMP6_NI_SUBJ_IPV4:
1815 			if (!ND_TTEST_LEN(dp, sizeof(*ni6) + sizeof(nd_ipv4)))
1816 				break;
1817 			if (siz != sizeof(*ni6) + sizeof(nd_ipv4)) {
1818 				if (ndo->ndo_vflag)
1819 					ND_PRINT(", invalid subject len");
1820 				break;
1821 			}
1822 			ND_PRINT(", subject=%s",
1823                                   GET_IPADDR_STRING(cp));
1824 			break;
1825 		default:
1826 			ND_PRINT(", unknown subject");
1827 			break;
1828 		}
1829 
1830 		/*(*/
1831 		ND_PRINT(")");
1832 		break;
1833 
1834 	case ICMP6_NI_REPLY:
1835 		if (icmp6len > siz)
1836 			goto trunc;
1837 
1838 		needcomma = 0;
1839 
1840 		ND_TCHECK_LEN(dp, sizeof(*ni6));
1841 		ni6 = (const struct icmp6_nodeinfo *)dp;
1842 		ND_PRINT(" node information reply");
1843 		ND_PRINT(" (");	/*)*/
1844 		switch (GET_U_1(ni6->ni_code)) {
1845 		case ICMP6_NI_SUCCESS:
1846 			if (ndo->ndo_vflag) {
1847 				ND_PRINT("success");
1848 				needcomma++;
1849 			}
1850 			break;
1851 		case ICMP6_NI_REFUSED:
1852 			ND_PRINT("refused");
1853 			needcomma++;
1854 			if (siz != sizeof(*ni6))
1855 				if (ndo->ndo_vflag)
1856 					ND_PRINT(", invalid length");
1857 			break;
1858 		case ICMP6_NI_UNKNOWN:
1859 			ND_PRINT("unknown");
1860 			needcomma++;
1861 			if (siz != sizeof(*ni6))
1862 				if (ndo->ndo_vflag)
1863 					ND_PRINT(", invalid length");
1864 			break;
1865 		}
1866 
1867 		if (GET_U_1(ni6->ni_code) != ICMP6_NI_SUCCESS) {
1868 			/*(*/
1869 			ND_PRINT(")");
1870 			break;
1871 		}
1872 
1873 		switch (GET_BE_U_2(ni6->ni_qtype)) {
1874 		case NI_QTYPE_NOOP:
1875 			if (needcomma)
1876 				ND_PRINT(", ");
1877 			ND_PRINT("noop");
1878 			if (siz != sizeof(*ni6))
1879 				if (ndo->ndo_vflag)
1880 					ND_PRINT(", invalid length");
1881 			break;
1882 		case NI_QTYPE_SUPTYPES:
1883 			if (needcomma)
1884 				ND_PRINT(", ");
1885 			ND_PRINT("supported qtypes");
1886 			i = GET_BE_U_2(ni6->ni_flags);
1887 			if (i)
1888 				ND_PRINT(" [%s]", (i & 0x01) ? "C" : "");
1889 			break;
1890 		case NI_QTYPE_FQDN:
1891 			if (needcomma)
1892 				ND_PRINT(", ");
1893 			ND_PRINT("DNS name");
1894 			cp = (const u_char *)(ni6 + 1) + 4;
1895 			if (GET_U_1(cp) == ep - cp - 1) {
1896 				/* icmp-name-lookup-03, pascal string */
1897 				if (ndo->ndo_vflag)
1898 					ND_PRINT(", 03 draft");
1899 				cp++;
1900 				ND_PRINT(", \"");
1901 				while (cp < ep) {
1902 					fn_print_char(ndo, GET_U_1(cp));
1903 					cp++;
1904 				}
1905 				ND_PRINT("\"");
1906 			} else
1907 				dnsname_print(ndo, cp, ep);
1908 			if ((GET_BE_U_2(ni6->ni_flags) & 0x01) != 0)
1909 				ND_PRINT(" [TTL=%u]", GET_BE_U_4(ni6 + 1));
1910 			break;
1911 		case NI_QTYPE_NODEADDR:
1912 			if (needcomma)
1913 				ND_PRINT(", ");
1914 			ND_PRINT("node addresses");
1915 			i = sizeof(*ni6);
1916 			while (i < siz) {
1917 				if (i + sizeof(uint32_t) + sizeof(nd_ipv6) > siz)
1918 					break;
1919 				ND_PRINT(" %s(%u)",
1920 				    GET_IP6ADDR_STRING(bp + i + sizeof(uint32_t)),
1921 				    GET_BE_U_4(bp + i));
1922 				i += sizeof(uint32_t) + sizeof(nd_ipv6);
1923 			}
1924 			i = GET_BE_U_2(ni6->ni_flags);
1925 			if (!i)
1926 				break;
1927 			ND_PRINT(" [%s%s%s%s%s%s%s]",
1928                                   (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1929                                   (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1930                                   (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1931                                   (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1932                                   (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1933                                   (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
1934                                   (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
1935 			break;
1936 		default:
1937 			if (needcomma)
1938 				ND_PRINT(", ");
1939 			ND_PRINT("unknown");
1940 			break;
1941 		}
1942 
1943 		/*(*/
1944 		ND_PRINT(")");
1945 		break;
1946 	}
1947 	return;
1948 
1949 trunc:
1950 	nd_print_trunc(ndo);
1951 }
1952 
1953 static void
1954 icmp6_rrenum_print(netdissect_options *ndo, const u_char *bp, const u_char *ep)
1955 {
1956 	const struct icmp6_router_renum *rr6;
1957 	const char *cp;
1958 	const struct rr_pco_match *match;
1959 	const struct rr_pco_use *use;
1960 	char hbuf[NI_MAXHOST];
1961 	int n;
1962 
1963 	if (ep < bp)
1964 		return;
1965 	rr6 = (const struct icmp6_router_renum *)bp;
1966 	cp = (const char *)(rr6 + 1);
1967 
1968 	ND_TCHECK_4(rr6->rr_reserved);
1969 	switch (GET_U_1(rr6->rr_code)) {
1970 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
1971 		ND_PRINT(", command");
1972 		break;
1973 	case ICMP6_ROUTER_RENUMBERING_RESULT:
1974 		ND_PRINT(", result");
1975 		break;
1976 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
1977 		ND_PRINT(", sequence number reset");
1978 		break;
1979 	default:
1980 		ND_PRINT(", code-#%u", GET_U_1(rr6->rr_code));
1981 		break;
1982 	}
1983 
1984         ND_PRINT(", seq=%u", GET_BE_U_4(rr6->rr_seqnum));
1985 
1986 	if (ndo->ndo_vflag) {
1987 		uint8_t rr_flags = GET_U_1(rr6->rr_flags);
1988 #define F(x, y)	(rr_flags & (x) ? (y) : "")
1989 		ND_PRINT("[");	/*]*/
1990 		if (rr_flags) {
1991 			ND_PRINT("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1992                                   F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1993                                   F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1994                                   F(ICMP6_RR_FLAGS_SPECSITE, "S"),
1995                                   F(ICMP6_RR_FLAGS_PREVDONE, "P"));
1996 		}
1997                 ND_PRINT("seg=%u,", GET_U_1(rr6->rr_segnum));
1998                 ND_PRINT("maxdelay=%u", GET_BE_U_2(rr6->rr_maxdelay));
1999 		if (GET_BE_U_4(rr6->rr_reserved))
2000 			ND_PRINT("rsvd=0x%x", GET_BE_U_4(rr6->rr_reserved));
2001 		/*[*/
2002 		ND_PRINT("]");
2003 #undef F
2004 	}
2005 
2006 	if (GET_U_1(rr6->rr_code) == ICMP6_ROUTER_RENUMBERING_COMMAND) {
2007 		match = (const struct rr_pco_match *)cp;
2008 		cp = (const char *)(match + 1);
2009 
2010 		ND_TCHECK_16(match->rpm_prefix);
2011 
2012 		if (ndo->ndo_vflag > 1)
2013 			ND_PRINT("\n\t");
2014 		else
2015 			ND_PRINT(" ");
2016 		ND_PRINT("match(");	/*)*/
2017 		switch (GET_U_1(match->rpm_code)) {
2018 		case RPM_PCO_ADD:	ND_PRINT("add"); break;
2019 		case RPM_PCO_CHANGE:	ND_PRINT("change"); break;
2020 		case RPM_PCO_SETGLOBAL:	ND_PRINT("setglobal"); break;
2021 		default:		ND_PRINT("#%u",
2022 						 GET_U_1(match->rpm_code)); break;
2023 		}
2024 
2025 		if (ndo->ndo_vflag) {
2026 			ND_PRINT(",ord=%u", GET_U_1(match->rpm_ordinal));
2027 			ND_PRINT(",min=%u", GET_U_1(match->rpm_minlen));
2028 			ND_PRINT(",max=%u", GET_U_1(match->rpm_maxlen));
2029 		}
2030 		if (addrtostr6(match->rpm_prefix, hbuf, sizeof(hbuf)))
2031 			ND_PRINT(",%s/%u", hbuf, GET_U_1(match->rpm_matchlen));
2032 		else
2033 			ND_PRINT(",?/%u", GET_U_1(match->rpm_matchlen));
2034 		/*(*/
2035 		ND_PRINT(")");
2036 
2037 		n = GET_U_1(match->rpm_len) - 3;
2038 		if (n % 4)
2039 			goto trunc;
2040 		n /= 4;
2041 		while (n-- > 0) {
2042 			use = (const struct rr_pco_use *)cp;
2043 			cp = (const char *)(use + 1);
2044 
2045 			ND_TCHECK_16(use->rpu_prefix);
2046 
2047 			if (ndo->ndo_vflag > 1)
2048 				ND_PRINT("\n\t");
2049 			else
2050 				ND_PRINT(" ");
2051 			ND_PRINT("use(");	/*)*/
2052 			if (GET_U_1(use->rpu_flags)) {
2053 #define F(x, y)	(GET_U_1(use->rpu_flags) & (x) ? (y) : "")
2054 				ND_PRINT("%s%s,",
2055                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
2056                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
2057 #undef F
2058 			}
2059 			if (ndo->ndo_vflag) {
2060 				ND_PRINT("mask=0x%x,",
2061 					 GET_U_1(use->rpu_ramask));
2062 				ND_PRINT("raflags=0x%x,",
2063 					 GET_U_1(use->rpu_raflags));
2064 				if (GET_BE_U_4(use->rpu_vltime) == 0xffffffff)
2065 					ND_PRINT("vltime=infty,");
2066 				else
2067 					ND_PRINT("vltime=%u,",
2068                                                   GET_BE_U_4(use->rpu_vltime));
2069 				if (GET_BE_U_4(use->rpu_pltime) == 0xffffffff)
2070 					ND_PRINT("pltime=infty,");
2071 				else
2072 					ND_PRINT("pltime=%u,",
2073                                                   GET_BE_U_4(use->rpu_pltime));
2074 			}
2075 			if (addrtostr6(use->rpu_prefix, hbuf, sizeof(hbuf)))
2076 				ND_PRINT("%s/%u/%u", hbuf,
2077                                           GET_U_1(use->rpu_uselen),
2078                                           GET_U_1(use->rpu_keeplen));
2079 			else
2080 				ND_PRINT("?/%u/%u", GET_U_1(use->rpu_uselen),
2081                                           GET_U_1(use->rpu_keeplen));
2082 			/*(*/
2083                         ND_PRINT(")");
2084 		}
2085 	}
2086 
2087 	return;
2088 
2089 trunc:
2090 	nd_print_trunc(ndo);
2091 }
2092