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