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