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