xref: /freebsd/contrib/tcpdump/print-icmp6.c (revision 3340d77368116708ab5b5b95acf6c9c710528300)
1b0453382SBill Fenner /*
2b0453382SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
3b0453382SBill Fenner  *	The Regents of the University of California.  All rights reserved.
4b0453382SBill Fenner  *
5b0453382SBill Fenner  * Redistribution and use in source and binary forms, with or without
6b0453382SBill Fenner  * modification, are permitted provided that: (1) source code distributions
7b0453382SBill Fenner  * retain the above copyright notice and this paragraph in its entirety, (2)
8b0453382SBill Fenner  * distributions including binary code include the above copyright notice and
9b0453382SBill Fenner  * this paragraph in its entirety in the documentation or other materials
10b0453382SBill Fenner  * provided with the distribution, and (3) all advertising materials mentioning
11b0453382SBill Fenner  * features or use of this software display the following acknowledgement:
12b0453382SBill Fenner  * ``This product includes software developed by the University of California,
13b0453382SBill Fenner  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14b0453382SBill Fenner  * the University nor the names of its contributors may be used to endorse
15b0453382SBill Fenner  * or promote products derived from this software without specific prior
16b0453382SBill Fenner  * written permission.
17b0453382SBill Fenner  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18b0453382SBill Fenner  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19b0453382SBill Fenner  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20b0453382SBill Fenner  */
21b0453382SBill Fenner 
22*3340d773SGleb Smirnoff /* \summary: IPv6 Internet Control Message Protocol (ICMPv6) printer */
23*3340d773SGleb Smirnoff 
24b0453382SBill Fenner #ifdef HAVE_CONFIG_H
25b0453382SBill Fenner #include "config.h"
26b0453382SBill Fenner #endif
27b0453382SBill Fenner 
28*3340d773SGleb Smirnoff #include <netdissect-stdinc.h>
29b0453382SBill Fenner 
30b0453382SBill Fenner #include <stdio.h>
31a90e161bSBill Fenner #include <string.h>
32b0453382SBill Fenner 
33*3340d773SGleb Smirnoff #include "netdissect.h"
34b0453382SBill Fenner #include "addrtoname.h"
35*3340d773SGleb Smirnoff #include "addrtostr.h"
365b0fe478SBruce M Simpson #include "extract.h"
37b0453382SBill Fenner 
38f4d0c64aSSam Leffler #include "ip6.h"
39f4d0c64aSSam Leffler #include "ipproto.h"
40f4d0c64aSSam Leffler 
41685295f4SBill Fenner #include "udp.h"
42685295f4SBill Fenner #include "ah.h"
43685295f4SBill Fenner 
443c602fabSXin LI /*	NetBSD: icmp6.h,v 1.13 2000/08/03 16:30:37 itojun Exp 	*/
453c602fabSXin LI /*	$KAME: icmp6.h,v 1.22 2000/08/03 15:25:16 jinmei Exp $	*/
463c602fabSXin LI 
473c602fabSXin LI /*
483c602fabSXin LI  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
493c602fabSXin LI  * All rights reserved.
503c602fabSXin LI  *
513c602fabSXin LI  * Redistribution and use in source and binary forms, with or without
523c602fabSXin LI  * modification, are permitted provided that the following conditions
533c602fabSXin LI  * are met:
543c602fabSXin LI  * 1. Redistributions of source code must retain the above copyright
553c602fabSXin LI  *    notice, this list of conditions and the following disclaimer.
563c602fabSXin LI  * 2. Redistributions in binary form must reproduce the above copyright
573c602fabSXin LI  *    notice, this list of conditions and the following disclaimer in the
583c602fabSXin LI  *    documentation and/or other materials provided with the distribution.
593c602fabSXin LI  * 3. Neither the name of the project nor the names of its contributors
603c602fabSXin LI  *    may be used to endorse or promote products derived from this software
613c602fabSXin LI  *    without specific prior written permission.
623c602fabSXin LI  *
633c602fabSXin LI  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
643c602fabSXin LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
653c602fabSXin LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
663c602fabSXin LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
673c602fabSXin LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
683c602fabSXin LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
693c602fabSXin LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
703c602fabSXin LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
713c602fabSXin LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
723c602fabSXin LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
733c602fabSXin LI  * SUCH DAMAGE.
743c602fabSXin LI  */
753c602fabSXin LI 
763c602fabSXin LI struct icmp6_hdr {
773c602fabSXin LI 	uint8_t		icmp6_type;	/* type field */
783c602fabSXin LI 	uint8_t		icmp6_code;	/* code field */
793c602fabSXin LI 	uint16_t	icmp6_cksum;	/* checksum field */
803c602fabSXin LI 	union {
813c602fabSXin LI 		uint32_t	icmp6_un_data32[1]; /* type-specific field */
823c602fabSXin LI 		uint16_t	icmp6_un_data16[2]; /* type-specific field */
833c602fabSXin LI 		uint8_t		icmp6_un_data8[4];  /* type-specific field */
843c602fabSXin LI 	} icmp6_dataun;
853c602fabSXin LI };
863c602fabSXin LI 
873c602fabSXin LI #define icmp6_data32	icmp6_dataun.icmp6_un_data32
883c602fabSXin LI #define icmp6_data16	icmp6_dataun.icmp6_un_data16
893c602fabSXin LI #define icmp6_data8	icmp6_dataun.icmp6_un_data8
903c602fabSXin LI #define icmp6_pptr	icmp6_data32[0]		/* parameter prob */
913c602fabSXin LI #define icmp6_mtu	icmp6_data32[0]		/* packet too big */
923c602fabSXin LI #define icmp6_id	icmp6_data16[0]		/* echo request/reply */
933c602fabSXin LI #define icmp6_seq	icmp6_data16[1]		/* echo request/reply */
943c602fabSXin LI #define icmp6_maxdelay	icmp6_data16[0]		/* mcast group membership */
953c602fabSXin LI 
963c602fabSXin LI #define ICMP6_DST_UNREACH		1	/* dest unreachable, codes: */
973c602fabSXin LI #define ICMP6_PACKET_TOO_BIG		2	/* packet too big */
983c602fabSXin LI #define ICMP6_TIME_EXCEEDED		3	/* time exceeded, code: */
993c602fabSXin LI #define ICMP6_PARAM_PROB		4	/* ip6 header bad */
1003c602fabSXin LI 
1013c602fabSXin LI #define ICMP6_ECHO_REQUEST		128	/* echo service */
1023c602fabSXin LI #define ICMP6_ECHO_REPLY		129	/* echo reply */
1033c602fabSXin LI #define ICMP6_MEMBERSHIP_QUERY		130	/* group membership query */
1043c602fabSXin LI #define MLD6_LISTENER_QUERY		130 	/* multicast listener query */
1053c602fabSXin LI #define ICMP6_MEMBERSHIP_REPORT		131	/* group membership report */
1063c602fabSXin LI #define MLD6_LISTENER_REPORT		131	/* multicast listener report */
1073c602fabSXin LI #define ICMP6_MEMBERSHIP_REDUCTION	132	/* group membership termination */
1083c602fabSXin LI #define MLD6_LISTENER_DONE		132	/* multicast listener done */
1093c602fabSXin LI 
1103c602fabSXin LI #define ND_ROUTER_SOLICIT		133	/* router solicitation */
1113c602fabSXin LI #define ND_ROUTER_ADVERT		134	/* router advertisement */
1123c602fabSXin LI #define ND_NEIGHBOR_SOLICIT		135	/* neighbor solicitation */
1133c602fabSXin LI #define ND_NEIGHBOR_ADVERT		136	/* neighbor advertisement */
1143c602fabSXin LI #define ND_REDIRECT			137	/* redirect */
1153c602fabSXin LI 
1163c602fabSXin LI #define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */
1173c602fabSXin LI 
1183c602fabSXin LI #define ICMP6_WRUREQUEST		139	/* who are you request */
1193c602fabSXin LI #define ICMP6_WRUREPLY			140	/* who are you reply */
1203c602fabSXin LI #define ICMP6_FQDN_QUERY		139	/* FQDN query */
1213c602fabSXin LI #define ICMP6_FQDN_REPLY		140	/* FQDN reply */
1223c602fabSXin LI #define ICMP6_NI_QUERY			139	/* node information request */
1233c602fabSXin LI #define ICMP6_NI_REPLY			140	/* node information reply */
1243c602fabSXin LI #define IND_SOLICIT			141	/* inverse neighbor solicitation */
1253c602fabSXin LI #define IND_ADVERT			142	/* inverse neighbor advertisement */
1263c602fabSXin LI 
1273c602fabSXin LI #define ICMP6_V2_MEMBERSHIP_REPORT	143	/* v2 membership report */
1283c602fabSXin LI #define MLDV2_LISTENER_REPORT		143	/* v2 multicast listener report */
1293c602fabSXin LI #define ICMP6_HADISCOV_REQUEST		144
1303c602fabSXin LI #define ICMP6_HADISCOV_REPLY		145
1313c602fabSXin LI #define ICMP6_MOBILEPREFIX_SOLICIT	146
1323c602fabSXin LI #define ICMP6_MOBILEPREFIX_ADVERT	147
1333c602fabSXin LI 
1343c602fabSXin LI #define MLD6_MTRACE_RESP		200	/* mtrace response(to sender) */
1353c602fabSXin LI #define MLD6_MTRACE			201	/* mtrace messages */
1363c602fabSXin LI 
1373c602fabSXin LI #define ICMP6_MAXTYPE			201
1383c602fabSXin LI 
1393c602fabSXin LI #define ICMP6_DST_UNREACH_NOROUTE	0	/* no route to destination */
1403c602fabSXin LI #define ICMP6_DST_UNREACH_ADMIN	 	1	/* administratively prohibited */
1413c602fabSXin LI #define ICMP6_DST_UNREACH_NOTNEIGHBOR	2	/* not a neighbor(obsolete) */
1423c602fabSXin LI #define ICMP6_DST_UNREACH_BEYONDSCOPE	2	/* beyond scope of source address */
1433c602fabSXin LI #define ICMP6_DST_UNREACH_ADDR		3	/* address unreachable */
1443c602fabSXin LI #define ICMP6_DST_UNREACH_NOPORT	4	/* port unreachable */
1453c602fabSXin LI 
1463c602fabSXin LI #define ICMP6_TIME_EXCEED_TRANSIT 	0	/* ttl==0 in transit */
1473c602fabSXin LI #define ICMP6_TIME_EXCEED_REASSEMBLY	1	/* ttl==0 in reass */
1483c602fabSXin LI 
1493c602fabSXin LI #define ICMP6_PARAMPROB_HEADER 	 	0	/* erroneous header field */
1503c602fabSXin LI #define ICMP6_PARAMPROB_NEXTHEADER	1	/* unrecognized next header */
1513c602fabSXin LI #define ICMP6_PARAMPROB_OPTION		2	/* unrecognized option */
1523c602fabSXin LI 
1533c602fabSXin LI #define ICMP6_INFOMSG_MASK		0x80	/* all informational messages */
1543c602fabSXin LI 
1553c602fabSXin LI #define ICMP6_NI_SUBJ_IPV6	0	/* Query Subject is an IPv6 address */
1563c602fabSXin LI #define ICMP6_NI_SUBJ_FQDN	1	/* Query Subject is a Domain name */
1573c602fabSXin LI #define ICMP6_NI_SUBJ_IPV4	2	/* Query Subject is an IPv4 address */
1583c602fabSXin LI 
1593c602fabSXin LI #define ICMP6_NI_SUCCESS	0	/* node information successful reply */
1603c602fabSXin LI #define ICMP6_NI_REFUSED	1	/* node information request is refused */
1613c602fabSXin LI #define ICMP6_NI_UNKNOWN	2	/* unknown Qtype */
1623c602fabSXin LI 
1633c602fabSXin LI #define ICMP6_ROUTER_RENUMBERING_COMMAND  0	/* rr command */
1643c602fabSXin LI #define ICMP6_ROUTER_RENUMBERING_RESULT   1	/* rr result */
1653c602fabSXin LI #define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET   255	/* rr seq num reset */
1663c602fabSXin LI 
1673c602fabSXin LI /* Used in kernel only */
1683c602fabSXin LI #define ND_REDIRECT_ONLINK	0	/* redirect to an on-link node */
1693c602fabSXin LI #define ND_REDIRECT_ROUTER	1	/* redirect to a better router */
1703c602fabSXin LI 
1713c602fabSXin LI /*
1723c602fabSXin LI  * Multicast Listener Discovery
1733c602fabSXin LI  */
1743c602fabSXin LI struct mld6_hdr {
1753c602fabSXin LI 	struct icmp6_hdr	mld6_hdr;
1763c602fabSXin LI 	struct in6_addr		mld6_addr; /* multicast address */
1773c602fabSXin LI };
1783c602fabSXin LI 
1793c602fabSXin LI #define mld6_type	mld6_hdr.icmp6_type
1803c602fabSXin LI #define mld6_code	mld6_hdr.icmp6_code
1813c602fabSXin LI #define mld6_cksum	mld6_hdr.icmp6_cksum
1823c602fabSXin LI #define mld6_maxdelay	mld6_hdr.icmp6_data16[0]
1833c602fabSXin LI #define mld6_reserved	mld6_hdr.icmp6_data16[1]
1843c602fabSXin LI 
1853c602fabSXin LI #define MLD_MINLEN	24
1863c602fabSXin LI #define MLDV2_MINLEN	28
1873c602fabSXin LI 
1883c602fabSXin LI /*
1893c602fabSXin LI  * Neighbor Discovery
1903c602fabSXin LI  */
1913c602fabSXin LI 
1923c602fabSXin LI struct nd_router_solicit {	/* router solicitation */
1933c602fabSXin LI 	struct icmp6_hdr 	nd_rs_hdr;
1943c602fabSXin LI 	/* could be followed by options */
1953c602fabSXin LI };
1963c602fabSXin LI 
1973c602fabSXin LI #define nd_rs_type	nd_rs_hdr.icmp6_type
1983c602fabSXin LI #define nd_rs_code	nd_rs_hdr.icmp6_code
1993c602fabSXin LI #define nd_rs_cksum	nd_rs_hdr.icmp6_cksum
2003c602fabSXin LI #define nd_rs_reserved	nd_rs_hdr.icmp6_data32[0]
2013c602fabSXin LI 
2023c602fabSXin LI struct nd_router_advert {	/* router advertisement */
2033c602fabSXin LI 	struct icmp6_hdr	nd_ra_hdr;
2043c602fabSXin LI 	uint32_t		nd_ra_reachable;	/* reachable time */
2053c602fabSXin LI 	uint32_t		nd_ra_retransmit;	/* retransmit timer */
2063c602fabSXin LI 	/* could be followed by options */
2073c602fabSXin LI };
2083c602fabSXin LI 
2093c602fabSXin LI #define nd_ra_type		nd_ra_hdr.icmp6_type
2103c602fabSXin LI #define nd_ra_code		nd_ra_hdr.icmp6_code
2113c602fabSXin LI #define nd_ra_cksum		nd_ra_hdr.icmp6_cksum
2123c602fabSXin LI #define nd_ra_curhoplimit	nd_ra_hdr.icmp6_data8[0]
2133c602fabSXin LI #define nd_ra_flags_reserved	nd_ra_hdr.icmp6_data8[1]
2143c602fabSXin LI #define ND_RA_FLAG_MANAGED	0x80
2153c602fabSXin LI #define ND_RA_FLAG_OTHER	0x40
2163c602fabSXin LI #define ND_RA_FLAG_HOME_AGENT	0x20
2173c602fabSXin LI 
2183c602fabSXin LI /*
2193c602fabSXin LI  * Router preference values based on draft-draves-ipngwg-router-selection-01.
2203c602fabSXin LI  * These are non-standard definitions.
2213c602fabSXin LI  */
2223c602fabSXin LI #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
2233c602fabSXin LI 
2243c602fabSXin LI #define ND_RA_FLAG_RTPREF_HIGH	0x08 /* 00001000 */
2253c602fabSXin LI #define ND_RA_FLAG_RTPREF_MEDIUM	0x00 /* 00000000 */
2263c602fabSXin LI #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
2273c602fabSXin LI #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
2283c602fabSXin LI 
2293c602fabSXin LI #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
2303c602fabSXin LI 
2313c602fabSXin LI struct nd_neighbor_solicit {	/* neighbor solicitation */
2323c602fabSXin LI 	struct icmp6_hdr	nd_ns_hdr;
2333c602fabSXin LI 	struct in6_addr		nd_ns_target;	/*target address */
2343c602fabSXin LI 	/* could be followed by options */
2353c602fabSXin LI };
2363c602fabSXin LI 
2373c602fabSXin LI #define nd_ns_type		nd_ns_hdr.icmp6_type
2383c602fabSXin LI #define nd_ns_code		nd_ns_hdr.icmp6_code
2393c602fabSXin LI #define nd_ns_cksum		nd_ns_hdr.icmp6_cksum
2403c602fabSXin LI #define nd_ns_reserved		nd_ns_hdr.icmp6_data32[0]
2413c602fabSXin LI 
2423c602fabSXin LI struct nd_neighbor_advert {	/* neighbor advertisement */
2433c602fabSXin LI 	struct icmp6_hdr	nd_na_hdr;
2443c602fabSXin LI 	struct in6_addr		nd_na_target;	/* target address */
2453c602fabSXin LI 	/* could be followed by options */
2463c602fabSXin LI };
2473c602fabSXin LI 
2483c602fabSXin LI #define nd_na_type		nd_na_hdr.icmp6_type
2493c602fabSXin LI #define nd_na_code		nd_na_hdr.icmp6_code
2503c602fabSXin LI #define nd_na_cksum		nd_na_hdr.icmp6_cksum
2513c602fabSXin LI #define nd_na_flags_reserved	nd_na_hdr.icmp6_data32[0]
2523c602fabSXin LI 
2533c602fabSXin LI #define ND_NA_FLAG_ROUTER		0x80000000
2543c602fabSXin LI #define ND_NA_FLAG_SOLICITED		0x40000000
2553c602fabSXin LI #define ND_NA_FLAG_OVERRIDE		0x20000000
2563c602fabSXin LI 
2573c602fabSXin LI struct nd_redirect {		/* redirect */
2583c602fabSXin LI 	struct icmp6_hdr	nd_rd_hdr;
2593c602fabSXin LI 	struct in6_addr		nd_rd_target;	/* target address */
2603c602fabSXin LI 	struct in6_addr		nd_rd_dst;	/* destination address */
2613c602fabSXin LI 	/* could be followed by options */
2623c602fabSXin LI };
2633c602fabSXin LI 
2643c602fabSXin LI #define nd_rd_type		nd_rd_hdr.icmp6_type
2653c602fabSXin LI #define nd_rd_code		nd_rd_hdr.icmp6_code
2663c602fabSXin LI #define nd_rd_cksum		nd_rd_hdr.icmp6_cksum
2673c602fabSXin LI #define nd_rd_reserved		nd_rd_hdr.icmp6_data32[0]
2683c602fabSXin LI 
2693c602fabSXin LI struct nd_opt_hdr {		/* Neighbor discovery option header */
2703c602fabSXin LI 	uint8_t		nd_opt_type;
2713c602fabSXin LI 	uint8_t		nd_opt_len;
2723c602fabSXin LI 	/* followed by option specific data*/
2733c602fabSXin LI };
2743c602fabSXin LI 
2753c602fabSXin LI #define ND_OPT_SOURCE_LINKADDR		1
2763c602fabSXin LI #define ND_OPT_TARGET_LINKADDR		2
2773c602fabSXin LI #define ND_OPT_PREFIX_INFORMATION	3
2783c602fabSXin LI #define ND_OPT_REDIRECTED_HEADER	4
2793c602fabSXin LI #define ND_OPT_MTU			5
2803c602fabSXin LI #define ND_OPT_ADVINTERVAL		7
2813c602fabSXin LI #define ND_OPT_HOMEAGENT_INFO		8
2823c602fabSXin LI #define ND_OPT_ROUTE_INFO		24	/* RFC4191 */
2833c602fabSXin LI #define ND_OPT_RDNSS			25
2843c602fabSXin LI #define ND_OPT_DNSSL			31
2853c602fabSXin LI 
2863c602fabSXin LI struct nd_opt_prefix_info {	/* prefix information */
287*3340d773SGleb Smirnoff 	nd_uint8_t		nd_opt_pi_type;
288*3340d773SGleb Smirnoff 	nd_uint8_t		nd_opt_pi_len;
289*3340d773SGleb Smirnoff 	nd_uint8_t		nd_opt_pi_prefix_len;
290*3340d773SGleb Smirnoff 	nd_uint8_t		nd_opt_pi_flags_reserved;
291*3340d773SGleb Smirnoff 	nd_uint32_t		nd_opt_pi_valid_time;
292*3340d773SGleb Smirnoff 	nd_uint32_t		nd_opt_pi_preferred_time;
293*3340d773SGleb Smirnoff 	nd_uint32_t		nd_opt_pi_reserved2;
2943c602fabSXin LI 	struct in6_addr	nd_opt_pi_prefix;
2953c602fabSXin LI };
2963c602fabSXin LI 
2973c602fabSXin LI #define ND_OPT_PI_FLAG_ONLINK		0x80
2983c602fabSXin LI #define ND_OPT_PI_FLAG_AUTO		0x40
2993c602fabSXin LI #define ND_OPT_PI_FLAG_ROUTER		0x20	/*2292bis*/
3003c602fabSXin LI 
3013c602fabSXin LI struct nd_opt_rd_hdr {         /* redirected header */
3023c602fabSXin LI 	uint8_t		nd_opt_rh_type;
3033c602fabSXin LI 	uint8_t		nd_opt_rh_len;
3043c602fabSXin LI 	uint16_t	nd_opt_rh_reserved1;
3053c602fabSXin LI 	uint32_t	nd_opt_rh_reserved2;
3063c602fabSXin LI 	/* followed by IP header and data */
3073c602fabSXin LI };
3083c602fabSXin LI 
3093c602fabSXin LI struct nd_opt_mtu {		/* MTU option */
3103c602fabSXin LI 	uint8_t		nd_opt_mtu_type;
3113c602fabSXin LI 	uint8_t		nd_opt_mtu_len;
3123c602fabSXin LI 	uint16_t	nd_opt_mtu_reserved;
3133c602fabSXin LI 	uint32_t	nd_opt_mtu_mtu;
3143c602fabSXin LI };
3153c602fabSXin LI 
3163c602fabSXin LI struct nd_opt_rdnss {		/* RDNSS RFC 6106 5.1 */
3173c602fabSXin LI 	uint8_t		nd_opt_rdnss_type;
3183c602fabSXin LI 	uint8_t		nd_opt_rdnss_len;
3193c602fabSXin LI 	uint16_t	nd_opt_rdnss_reserved;
3203c602fabSXin LI 	uint32_t	nd_opt_rdnss_lifetime;
3213c602fabSXin LI 	struct in6_addr nd_opt_rdnss_addr[1];	/* variable-length */
3223c602fabSXin LI };
3233c602fabSXin LI 
3243c602fabSXin LI struct nd_opt_dnssl {		/* DNSSL RFC 6106 5.2 */
3253c602fabSXin LI 	uint8_t  nd_opt_dnssl_type;
3263c602fabSXin LI 	uint8_t  nd_opt_dnssl_len;
3273c602fabSXin LI 	uint16_t nd_opt_dnssl_reserved;
3283c602fabSXin LI 	uint32_t nd_opt_dnssl_lifetime;
3293c602fabSXin LI 	/* followed by list of DNS search domains, variable-length */
3303c602fabSXin LI };
3313c602fabSXin LI 
3323c602fabSXin LI struct nd_opt_advinterval {	/* Advertisement interval option */
3333c602fabSXin LI 	uint8_t		nd_opt_adv_type;
3343c602fabSXin LI 	uint8_t		nd_opt_adv_len;
3353c602fabSXin LI 	uint16_t	nd_opt_adv_reserved;
3363c602fabSXin LI 	uint32_t	nd_opt_adv_interval;
3373c602fabSXin LI };
3383c602fabSXin LI 
3393c602fabSXin LI struct nd_opt_homeagent_info {	/* Home Agent info */
3403c602fabSXin LI 	uint8_t		nd_opt_hai_type;
3413c602fabSXin LI 	uint8_t		nd_opt_hai_len;
3423c602fabSXin LI 	uint16_t	nd_opt_hai_reserved;
3433c602fabSXin LI 	int16_t		nd_opt_hai_preference;
3443c602fabSXin LI 	uint16_t	nd_opt_hai_lifetime;
3453c602fabSXin LI };
3463c602fabSXin LI 
3473c602fabSXin LI struct nd_opt_route_info {	/* route info */
3483c602fabSXin LI 	uint8_t		nd_opt_rti_type;
3493c602fabSXin LI 	uint8_t		nd_opt_rti_len;
3503c602fabSXin LI 	uint8_t		nd_opt_rti_prefixlen;
3513c602fabSXin LI 	uint8_t		nd_opt_rti_flags;
3523c602fabSXin LI 	uint32_t	nd_opt_rti_lifetime;
3533c602fabSXin LI 	/* prefix follows */
3543c602fabSXin LI };
3553c602fabSXin LI 
3563c602fabSXin LI /*
3573c602fabSXin LI  * icmp6 namelookup
3583c602fabSXin LI  */
3593c602fabSXin LI 
3603c602fabSXin LI struct icmp6_namelookup {
3613c602fabSXin LI 	struct icmp6_hdr 	icmp6_nl_hdr;
3623c602fabSXin LI 	uint8_t		icmp6_nl_nonce[8];
3633c602fabSXin LI 	int32_t		icmp6_nl_ttl;
3643c602fabSXin LI #if 0
3653c602fabSXin LI 	uint8_t		icmp6_nl_len;
3663c602fabSXin LI 	uint8_t		icmp6_nl_name[3];
3673c602fabSXin LI #endif
3683c602fabSXin LI 	/* could be followed by options */
3693c602fabSXin LI };
3703c602fabSXin LI 
3713c602fabSXin LI /*
3723c602fabSXin LI  * icmp6 node information
3733c602fabSXin LI  */
3743c602fabSXin LI struct icmp6_nodeinfo {
3753c602fabSXin LI 	struct icmp6_hdr icmp6_ni_hdr;
3763c602fabSXin LI 	uint8_t icmp6_ni_nonce[8];
3773c602fabSXin LI 	/* could be followed by reply data */
3783c602fabSXin LI };
3793c602fabSXin LI 
3803c602fabSXin LI #define ni_type		icmp6_ni_hdr.icmp6_type
3813c602fabSXin LI #define ni_code		icmp6_ni_hdr.icmp6_code
3823c602fabSXin LI #define ni_cksum	icmp6_ni_hdr.icmp6_cksum
3833c602fabSXin LI #define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
3843c602fabSXin LI #define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
3853c602fabSXin LI 
3863c602fabSXin LI #define NI_QTYPE_NOOP		0 /* NOOP  */
3873c602fabSXin LI #define NI_QTYPE_SUPTYPES	1 /* Supported Qtypes */
3883c602fabSXin LI #define NI_QTYPE_FQDN		2 /* FQDN (draft 04) */
3893c602fabSXin LI #define NI_QTYPE_DNSNAME	2 /* DNS Name */
3903c602fabSXin LI #define NI_QTYPE_NODEADDR	3 /* Node Addresses */
3913c602fabSXin LI #define NI_QTYPE_IPV4ADDR	4 /* IPv4 Addresses */
3923c602fabSXin LI 
3933c602fabSXin LI /* network endian */
3943c602fabSXin LI #define NI_SUPTYPE_FLAG_COMPRESS	((uint16_t)htons(0x1))
3953c602fabSXin LI #define NI_FQDN_FLAG_VALIDTTL		((uint16_t)htons(0x1))
3963c602fabSXin LI 
3973c602fabSXin LI /* network endian */
3983c602fabSXin LI #define NI_NODEADDR_FLAG_TRUNCATE	((uint16_t)htons(0x1))
3993c602fabSXin LI #define NI_NODEADDR_FLAG_ALL		((uint16_t)htons(0x2))
4003c602fabSXin LI #define NI_NODEADDR_FLAG_COMPAT		((uint16_t)htons(0x4))
4013c602fabSXin LI #define NI_NODEADDR_FLAG_LINKLOCAL	((uint16_t)htons(0x8))
4023c602fabSXin LI #define NI_NODEADDR_FLAG_SITELOCAL	((uint16_t)htons(0x10))
4033c602fabSXin LI #define NI_NODEADDR_FLAG_GLOBAL		((uint16_t)htons(0x20))
4043c602fabSXin LI #define NI_NODEADDR_FLAG_ANYCAST	((uint16_t)htons(0x40)) /* just experimental. not in spec */
4053c602fabSXin LI 
4063c602fabSXin LI struct ni_reply_fqdn {
4073c602fabSXin LI 	uint32_t ni_fqdn_ttl;	/* TTL */
4083c602fabSXin LI 	uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */
4093c602fabSXin LI 	uint8_t ni_fqdn_name[3]; /* XXX: alignment */
4103c602fabSXin LI };
4113c602fabSXin LI 
4123c602fabSXin LI /*
4133c602fabSXin LI  * Router Renumbering. as router-renum-08.txt
4143c602fabSXin LI  */
4153c602fabSXin LI struct icmp6_router_renum {	/* router renumbering header */
4163c602fabSXin LI 	struct icmp6_hdr	rr_hdr;
4173c602fabSXin LI 	uint8_t		rr_segnum;
4183c602fabSXin LI 	uint8_t		rr_flags;
4193c602fabSXin LI 	uint16_t	rr_maxdelay;
4203c602fabSXin LI 	uint32_t	rr_reserved;
4213c602fabSXin LI };
4223c602fabSXin LI #define ICMP6_RR_FLAGS_TEST		0x80
4233c602fabSXin LI #define ICMP6_RR_FLAGS_REQRESULT	0x40
4243c602fabSXin LI #define ICMP6_RR_FLAGS_FORCEAPPLY	0x20
4253c602fabSXin LI #define ICMP6_RR_FLAGS_SPECSITE		0x10
4263c602fabSXin LI #define ICMP6_RR_FLAGS_PREVDONE		0x08
4273c602fabSXin LI 
4283c602fabSXin LI #define rr_type		rr_hdr.icmp6_type
4293c602fabSXin LI #define rr_code		rr_hdr.icmp6_code
4303c602fabSXin LI #define rr_cksum	rr_hdr.icmp6_cksum
4313c602fabSXin LI #define rr_seqnum 	rr_hdr.icmp6_data32[0]
4323c602fabSXin LI 
4333c602fabSXin LI struct rr_pco_match {		/* match prefix part */
4343c602fabSXin LI 	uint8_t		rpm_code;
4353c602fabSXin LI 	uint8_t		rpm_len;
4363c602fabSXin LI 	uint8_t		rpm_ordinal;
4373c602fabSXin LI 	uint8_t		rpm_matchlen;
4383c602fabSXin LI 	uint8_t		rpm_minlen;
4393c602fabSXin LI 	uint8_t		rpm_maxlen;
4403c602fabSXin LI 	uint16_t	rpm_reserved;
4413c602fabSXin LI 	struct	in6_addr	rpm_prefix;
4423c602fabSXin LI };
4433c602fabSXin LI 
4443c602fabSXin LI #define RPM_PCO_ADD		1
4453c602fabSXin LI #define RPM_PCO_CHANGE		2
4463c602fabSXin LI #define RPM_PCO_SETGLOBAL	3
4473c602fabSXin LI #define RPM_PCO_MAX		4
4483c602fabSXin LI 
4493c602fabSXin LI struct rr_pco_use {		/* use prefix part */
4503c602fabSXin LI 	uint8_t		rpu_uselen;
4513c602fabSXin LI 	uint8_t		rpu_keeplen;
4523c602fabSXin LI 	uint8_t		rpu_ramask;
4533c602fabSXin LI 	uint8_t		rpu_raflags;
4543c602fabSXin LI 	uint32_t	rpu_vltime;
4553c602fabSXin LI 	uint32_t	rpu_pltime;
4563c602fabSXin LI 	uint32_t	rpu_flags;
4573c602fabSXin LI 	struct	in6_addr rpu_prefix;
4583c602fabSXin LI };
4593c602fabSXin LI #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK	0x80
4603c602fabSXin LI #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO	0x40
4613c602fabSXin LI 
4623c602fabSXin LI /* network endian */
4633c602fabSXin LI #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME     ((uint32_t)htonl(0x80000000))
4643c602fabSXin LI #define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME     ((uint32_t)htonl(0x40000000))
4653c602fabSXin LI 
4663c602fabSXin LI struct rr_result {		/* router renumbering result message */
4673c602fabSXin LI 	uint16_t	rrr_flags;
4683c602fabSXin LI 	uint8_t		rrr_ordinal;
4693c602fabSXin LI 	uint8_t		rrr_matchedlen;
4703c602fabSXin LI 	uint32_t	rrr_ifid;
4713c602fabSXin LI 	struct	in6_addr rrr_prefix;
4723c602fabSXin LI };
4733c602fabSXin LI /* network endian */
4743c602fabSXin LI #define ICMP6_RR_RESULT_FLAGS_OOB		((uint16_t)htons(0x0002))
4753c602fabSXin LI #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		((uint16_t)htons(0x0001))
4763c602fabSXin LI 
477a90e161bSBill Fenner static const char *get_rtpref(u_int);
4783c602fabSXin LI static const char *get_lifetime(uint32_t);
4793c602fabSXin LI static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
4803c602fabSXin LI static void icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
4813c602fabSXin LI static void mld6_print(netdissect_options *ndo, const u_char *);
4823c602fabSXin LI static void mldv2_report_print(netdissect_options *ndo, const u_char *, u_int);
4833c602fabSXin LI static void mldv2_query_print(netdissect_options *ndo, const u_char *, u_int);
4843c602fabSXin LI static const struct udphdr *get_upperlayer(netdissect_options *ndo, const u_char *, u_int *);
4853c602fabSXin LI static void dnsname_print(netdissect_options *ndo, const u_char *, const u_char *);
4863c602fabSXin LI static void icmp6_nodeinfo_print(netdissect_options *ndo, u_int, const u_char *, const u_char *);
4873c602fabSXin LI static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_char *);
488685295f4SBill Fenner 
489685295f4SBill Fenner #ifndef abs
490685295f4SBill Fenner #define abs(a)	((0 < (a)) ? (a) : -(a))
491685295f4SBill Fenner #endif
492b0453382SBill Fenner 
4933c602fabSXin LI #include "rpl.h"
49427df3f5dSRui Paulo 
4953c602fabSXin LI static const struct tok icmp6_type_values[] = {
4961de50e9fSSam Leffler     { ICMP6_DST_UNREACH, "destination unreachable"},
4971de50e9fSSam Leffler     { ICMP6_PACKET_TOO_BIG, "packet too big"},
4981de50e9fSSam Leffler     { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
4991de50e9fSSam Leffler     { ICMP6_PARAM_PROB, "parameter problem"},
5001de50e9fSSam Leffler     { ICMP6_ECHO_REQUEST, "echo request"},
5011de50e9fSSam Leffler     { ICMP6_ECHO_REPLY, "echo reply"},
5021de50e9fSSam Leffler     { MLD6_LISTENER_QUERY, "multicast listener query"},
5031de50e9fSSam Leffler     { MLD6_LISTENER_REPORT, "multicast listener report"},
5041de50e9fSSam Leffler     { MLD6_LISTENER_DONE, "multicast listener done"},
5051de50e9fSSam Leffler     { ND_ROUTER_SOLICIT, "router solicitation"},
5061de50e9fSSam Leffler     { ND_ROUTER_ADVERT, "router advertisement"},
5071de50e9fSSam Leffler     { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
5082ebc47dbSSam Leffler     { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
5091de50e9fSSam Leffler     { ND_REDIRECT, "redirect"},
5101de50e9fSSam Leffler     { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
5111de50e9fSSam Leffler     { IND_SOLICIT, "inverse neighbor solicitation"},
5121de50e9fSSam Leffler     { IND_ADVERT, "inverse neighbor advertisement"},
5131de50e9fSSam Leffler     { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
5141de50e9fSSam Leffler     { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
5151de50e9fSSam Leffler     { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
5161de50e9fSSam Leffler     { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
5171de50e9fSSam Leffler     { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
5181de50e9fSSam Leffler     { ICMP6_WRUREQUEST, "who-are-you request"},
5191de50e9fSSam Leffler     { ICMP6_WRUREPLY, "who-are-you reply"},
5201de50e9fSSam Leffler     { ICMP6_NI_QUERY, "node information query"},
5211de50e9fSSam Leffler     { ICMP6_NI_REPLY, "node information reply"},
5221de50e9fSSam Leffler     { MLD6_MTRACE, "mtrace message"},
5231de50e9fSSam Leffler     { MLD6_MTRACE_RESP, "mtrace response"},
52427df3f5dSRui Paulo     { ND_RPL_MESSAGE,   "RPL"},
5251de50e9fSSam Leffler     { 0,	NULL }
5261de50e9fSSam Leffler };
5271de50e9fSSam Leffler 
5283c602fabSXin LI static const struct tok icmp6_dst_unreach_code_values[] = {
5291de50e9fSSam Leffler     { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
5301de50e9fSSam Leffler     { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
5311de50e9fSSam Leffler     { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
5321de50e9fSSam Leffler     { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
5331de50e9fSSam Leffler     { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
5341de50e9fSSam Leffler     { 0,	NULL }
5351de50e9fSSam Leffler };
5361de50e9fSSam Leffler 
5373c602fabSXin LI static const struct tok icmp6_opt_pi_flag_values[] = {
5381de50e9fSSam Leffler     { ND_OPT_PI_FLAG_ONLINK, "onlink" },
5391de50e9fSSam Leffler     { ND_OPT_PI_FLAG_AUTO, "auto" },
5401de50e9fSSam Leffler     { ND_OPT_PI_FLAG_ROUTER, "router" },
5411de50e9fSSam Leffler     { 0,	NULL }
5421de50e9fSSam Leffler };
5431de50e9fSSam Leffler 
5443c602fabSXin LI static const struct tok icmp6_opt_ra_flag_values[] = {
5451de50e9fSSam Leffler     { ND_RA_FLAG_MANAGED, "managed" },
5461de50e9fSSam Leffler     { ND_RA_FLAG_OTHER, "other stateful"},
5471de50e9fSSam Leffler     { ND_RA_FLAG_HOME_AGENT, "home agent"},
5481de50e9fSSam Leffler     { 0,	NULL }
5491de50e9fSSam Leffler };
5501de50e9fSSam Leffler 
5513c602fabSXin LI static const struct tok icmp6_nd_na_flag_values[] = {
5521de50e9fSSam Leffler     { ND_NA_FLAG_ROUTER, "router" },
5531de50e9fSSam Leffler     { ND_NA_FLAG_SOLICITED, "solicited" },
5541de50e9fSSam Leffler     { ND_NA_FLAG_OVERRIDE, "override" },
5551de50e9fSSam Leffler     { 0,	NULL }
5561de50e9fSSam Leffler };
5571de50e9fSSam Leffler 
5581de50e9fSSam Leffler 
5593c602fabSXin LI static const struct tok icmp6_opt_values[] = {
5601de50e9fSSam Leffler    { ND_OPT_SOURCE_LINKADDR, "source link-address"},
5611de50e9fSSam Leffler    { ND_OPT_TARGET_LINKADDR, "destination link-address"},
5621de50e9fSSam Leffler    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
5631de50e9fSSam Leffler    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
5641de50e9fSSam Leffler    { ND_OPT_MTU, "mtu"},
56527df3f5dSRui Paulo    { ND_OPT_RDNSS, "rdnss"},
566d03c0883SXin LI    { ND_OPT_DNSSL, "dnssl"},
5672ebc47dbSSam Leffler    { ND_OPT_ADVINTERVAL, "advertisement interval"},
5681de50e9fSSam Leffler    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
5691de50e9fSSam Leffler    { ND_OPT_ROUTE_INFO, "route info"},
5701de50e9fSSam Leffler    { 0,	NULL }
5711de50e9fSSam Leffler };
5721de50e9fSSam Leffler 
5731de50e9fSSam Leffler /* mldv2 report types */
5743c602fabSXin LI static const struct tok mldv2report2str[] = {
5751de50e9fSSam Leffler 	{ 1,	"is_in" },
5761de50e9fSSam Leffler 	{ 2,	"is_ex" },
5771de50e9fSSam Leffler 	{ 3,	"to_in" },
5781de50e9fSSam Leffler 	{ 4,	"to_ex" },
5791de50e9fSSam Leffler 	{ 5,	"allow" },
5801de50e9fSSam Leffler 	{ 6,	"block" },
5811de50e9fSSam Leffler 	{ 0,	NULL }
5821de50e9fSSam Leffler };
5831de50e9fSSam Leffler 
584a90e161bSBill Fenner static const char *
585a90e161bSBill Fenner get_rtpref(u_int v)
586a90e161bSBill Fenner {
587a90e161bSBill Fenner 	static const char *rtpref_str[] = {
588a90e161bSBill Fenner 		"medium",		/* 00 */
589a90e161bSBill Fenner 		"high",			/* 01 */
590a90e161bSBill Fenner 		"rsv",			/* 10 */
591a90e161bSBill Fenner 		"low"			/* 11 */
592a90e161bSBill Fenner 	};
593a90e161bSBill Fenner 
594a90e161bSBill Fenner 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
595a90e161bSBill Fenner }
596a90e161bSBill Fenner 
597a90e161bSBill Fenner static const char *
5983c602fabSXin LI get_lifetime(uint32_t v)
599a90e161bSBill Fenner {
600a90e161bSBill Fenner 	static char buf[20];
601a90e161bSBill Fenner 
6023c602fabSXin LI 	if (v == (uint32_t)~0UL)
603a90e161bSBill Fenner 		return "infinity";
604a90e161bSBill Fenner 	else {
605d03c0883SXin LI 		snprintf(buf, sizeof(buf), "%us", v);
606a90e161bSBill Fenner 		return buf;
607a90e161bSBill Fenner 	}
608a90e161bSBill Fenner }
609a90e161bSBill Fenner 
610a90e161bSBill Fenner static void
6113c602fabSXin LI print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
612a90e161bSBill Fenner {
6133c602fabSXin LI 	const uint8_t *ep, *q;
614a90e161bSBill Fenner 
615a90e161bSBill Fenner 	q = p;
616a90e161bSBill Fenner 	ep = p + l;
617a90e161bSBill Fenner 	while (l > 0 && q < ep) {
618a90e161bSBill Fenner 		if (q > p)
6193c602fabSXin LI                         ND_PRINT((ndo,":"));
6203c602fabSXin LI 		ND_PRINT((ndo,"%02x", *q++));
621a90e161bSBill Fenner 		l--;
622a90e161bSBill Fenner 	}
623a90e161bSBill Fenner }
624a90e161bSBill Fenner 
625*3340d773SGleb Smirnoff static int icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
626*3340d773SGleb Smirnoff 	const struct icmp6_hdr *icp, u_int len)
6275b0fe478SBruce M Simpson {
628*3340d773SGleb Smirnoff 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len,
6293c602fabSXin LI 				IPPROTO_ICMPV6);
6305b0fe478SBruce M Simpson }
6315b0fe478SBruce M Simpson 
632*3340d773SGleb Smirnoff static const struct tok rpl_mop_values[] = {
6333c602fabSXin LI         { RPL_DIO_NONSTORING,         "nonstoring"},
6343c602fabSXin LI         { RPL_DIO_STORING,            "storing"},
6353c602fabSXin LI         { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"},
6363c602fabSXin LI         { RPL_DIO_STORING_MULTICAST,  "storing-multicast"},
6373c602fabSXin LI         { 0, NULL},
63827df3f5dSRui Paulo };
63927df3f5dSRui Paulo 
640*3340d773SGleb Smirnoff static const struct tok rpl_subopt_values[] = {
6413c602fabSXin LI         { RPL_OPT_PAD0, "pad0"},
6423c602fabSXin LI         { RPL_OPT_PADN, "padN"},
6433c602fabSXin LI         { RPL_DIO_METRICS, "metrics"},
6443c602fabSXin LI         { RPL_DIO_ROUTINGINFO, "routinginfo"},
6453c602fabSXin LI         { RPL_DIO_CONFIG,    "config"},
6463c602fabSXin LI         { RPL_DAO_RPLTARGET, "rpltarget"},
6473c602fabSXin LI         { RPL_DAO_TRANSITINFO, "transitinfo"},
6483c602fabSXin LI         { RPL_DIO_DESTPREFIX, "destprefix"},
6493c602fabSXin LI         { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"},
6503c602fabSXin LI         { 0, NULL},
65127df3f5dSRui Paulo };
65227df3f5dSRui Paulo 
6533c602fabSXin LI static void
6543c602fabSXin LI rpl_dio_printopt(netdissect_options *ndo,
6553c602fabSXin LI                  const struct rpl_dio_genoption *opt,
6563c602fabSXin LI                  u_int length)
6573c602fabSXin LI {
6583c602fabSXin LI         if(length < RPL_DIO_GENOPTION_LEN) return;
6593c602fabSXin LI         length -= RPL_DIO_GENOPTION_LEN;
6603c602fabSXin LI 
6613c602fabSXin LI         ND_TCHECK(opt->rpl_dio_len);
6623c602fabSXin LI 
6633c602fabSXin LI         while((opt->rpl_dio_type == RPL_OPT_PAD0 &&
664*3340d773SGleb Smirnoff                (const u_char *)opt < ndo->ndo_snapend) ||
6653c602fabSXin LI               ND_TTEST2(*opt,(opt->rpl_dio_len+2))) {
6663c602fabSXin LI 
6673c602fabSXin LI                 unsigned int optlen = opt->rpl_dio_len+2;
6683c602fabSXin LI                 if(opt->rpl_dio_type == RPL_OPT_PAD0) {
6693c602fabSXin LI                         optlen = 1;
6703c602fabSXin LI                         ND_PRINT((ndo, " opt:pad0"));
6713c602fabSXin LI                 } else {
6723c602fabSXin LI                         ND_PRINT((ndo, " opt:%s len:%u ",
673*3340d773SGleb Smirnoff                                   tok2str(rpl_subopt_values, "subopt:%u", opt->rpl_dio_type),
6743c602fabSXin LI                                   optlen));
6753c602fabSXin LI                         if(ndo->ndo_vflag > 2) {
6763c602fabSXin LI                                 unsigned int paylen = opt->rpl_dio_len;
6773c602fabSXin LI                                 if(paylen > length) paylen = length;
6783c602fabSXin LI                                 hex_print(ndo,
6793c602fabSXin LI                                           " ",
680*3340d773SGleb Smirnoff                                           ((const uint8_t *)opt) + RPL_DIO_GENOPTION_LEN,  /* content of DIO option */
6813c602fabSXin LI                                           paylen);
6823c602fabSXin LI                         }
6833c602fabSXin LI                 }
684*3340d773SGleb Smirnoff                 opt = (const struct rpl_dio_genoption *)(((const char *)opt) + optlen);
6853c602fabSXin LI                 length -= optlen;
6863c602fabSXin LI         }
6873c602fabSXin LI         return;
6883c602fabSXin LI trunc:
6893c602fabSXin LI 	ND_PRINT((ndo," [|truncated]"));
6903c602fabSXin LI 	return;
6913c602fabSXin LI }
6923c602fabSXin LI 
6933c602fabSXin LI static void
6943c602fabSXin LI rpl_dio_print(netdissect_options *ndo,
6953c602fabSXin LI               const u_char *bp, u_int length)
6963c602fabSXin LI {
697*3340d773SGleb Smirnoff         const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp;
698*3340d773SGleb Smirnoff         const char *dagid_str;
6993c602fabSXin LI 
7003c602fabSXin LI         ND_TCHECK(*dio);
701*3340d773SGleb Smirnoff         dagid_str = ip6addr_string (ndo, dio->rpl_dagid);
7023c602fabSXin LI 
7033c602fabSXin LI         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]",
7043c602fabSXin LI                   dagid_str,
7053c602fabSXin LI                   dio->rpl_dtsn,
7063c602fabSXin LI                   dio->rpl_instanceid,
7073c602fabSXin LI                   EXTRACT_16BITS(&dio->rpl_dagrank),
7083c602fabSXin LI                   RPL_DIO_GROUNDED(dio->rpl_mopprf) ? "grounded,":"",
7093c602fabSXin LI                   tok2str(rpl_mop_values, "mop%u", RPL_DIO_MOP(dio->rpl_mopprf)),
7103c602fabSXin LI                   RPL_DIO_PRF(dio->rpl_mopprf)));
7113c602fabSXin LI 
7123c602fabSXin LI         if(ndo->ndo_vflag > 1) {
713*3340d773SGleb Smirnoff                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)&dio[1];
7143c602fabSXin LI                 rpl_dio_printopt(ndo, opt, length);
7153c602fabSXin LI         }
7163c602fabSXin LI 	return;
7173c602fabSXin LI trunc:
7183c602fabSXin LI 	ND_PRINT((ndo," [|truncated]"));
7193c602fabSXin LI 	return;
7203c602fabSXin LI }
7213c602fabSXin LI 
7223c602fabSXin LI static void
7233c602fabSXin LI rpl_dao_print(netdissect_options *ndo,
7243c602fabSXin LI               const u_char *bp, u_int length)
7253c602fabSXin LI {
726*3340d773SGleb Smirnoff         const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp;
727*3340d773SGleb Smirnoff         const char *dagid_str = "<elided>";
7283c602fabSXin LI 
7293c602fabSXin LI         ND_TCHECK(*dao);
7303c602fabSXin LI         if (length < ND_RPL_DAO_MIN_LEN)
7313c602fabSXin LI         	goto tooshort;
7323c602fabSXin LI 
7333c602fabSXin LI         bp += ND_RPL_DAO_MIN_LEN;
7343c602fabSXin LI         length -= ND_RPL_DAO_MIN_LEN;
7353c602fabSXin LI         if(RPL_DAO_D(dao->rpl_flags)) {
7363c602fabSXin LI                 ND_TCHECK2(dao->rpl_dagid, DAGID_LEN);
7373c602fabSXin LI                 if (length < DAGID_LEN)
7383c602fabSXin LI                 	goto tooshort;
739*3340d773SGleb Smirnoff                 dagid_str = ip6addr_string (ndo, dao->rpl_dagid);
7403c602fabSXin LI                 bp += DAGID_LEN;
7413c602fabSXin LI                 length -= DAGID_LEN;
7423c602fabSXin LI         }
7433c602fabSXin LI 
7443c602fabSXin LI         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u%s%s,%02x]",
7453c602fabSXin LI                   dagid_str,
7463c602fabSXin LI                   dao->rpl_daoseq,
7473c602fabSXin LI                   dao->rpl_instanceid,
7483c602fabSXin LI                   RPL_DAO_K(dao->rpl_flags) ? ",acK":"",
7493c602fabSXin LI                   RPL_DAO_D(dao->rpl_flags) ? ",Dagid":"",
7503c602fabSXin LI                   dao->rpl_flags));
7513c602fabSXin LI 
7523c602fabSXin LI         if(ndo->ndo_vflag > 1) {
753*3340d773SGleb Smirnoff                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
7543c602fabSXin LI                 rpl_dio_printopt(ndo, opt, length);
7553c602fabSXin LI         }
7563c602fabSXin LI 	return;
7573c602fabSXin LI 
7583c602fabSXin LI trunc:
7593c602fabSXin LI 	ND_PRINT((ndo," [|truncated]"));
7603c602fabSXin LI 	return;
7613c602fabSXin LI 
7623c602fabSXin LI tooshort:
7633c602fabSXin LI 	ND_PRINT((ndo," [|length too short]"));
7643c602fabSXin LI 	return;
7653c602fabSXin LI }
7663c602fabSXin LI 
7673c602fabSXin LI static void
7683c602fabSXin LI rpl_daoack_print(netdissect_options *ndo,
7693c602fabSXin LI                  const u_char *bp, u_int length)
7703c602fabSXin LI {
771*3340d773SGleb Smirnoff         const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp;
772*3340d773SGleb Smirnoff         const char *dagid_str = "<elided>";
7733c602fabSXin LI 
7743c602fabSXin LI         ND_TCHECK2(*daoack, ND_RPL_DAOACK_MIN_LEN);
7753c602fabSXin LI         if (length < ND_RPL_DAOACK_MIN_LEN)
7763c602fabSXin LI         	goto tooshort;
7773c602fabSXin LI 
7783c602fabSXin LI         bp += ND_RPL_DAOACK_MIN_LEN;
7793c602fabSXin LI         length -= ND_RPL_DAOACK_MIN_LEN;
7803c602fabSXin LI         if(RPL_DAOACK_D(daoack->rpl_flags)) {
781*3340d773SGleb Smirnoff                 ND_TCHECK2(daoack->rpl_dagid, DAGID_LEN);
7823c602fabSXin LI                 if (length < DAGID_LEN)
7833c602fabSXin LI                 	goto tooshort;
784*3340d773SGleb Smirnoff                 dagid_str = ip6addr_string (ndo, daoack->rpl_dagid);
7853c602fabSXin LI                 bp += DAGID_LEN;
7863c602fabSXin LI                 length -= DAGID_LEN;
7873c602fabSXin LI         }
7883c602fabSXin LI 
7893c602fabSXin LI         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,status:%u]",
7903c602fabSXin LI                   dagid_str,
7913c602fabSXin LI                   daoack->rpl_daoseq,
7923c602fabSXin LI                   daoack->rpl_instanceid,
7933c602fabSXin LI                   daoack->rpl_status));
7943c602fabSXin LI 
7953c602fabSXin LI         /* no officially defined options for DAOACK, but print any we find */
7963c602fabSXin LI         if(ndo->ndo_vflag > 1) {
797*3340d773SGleb Smirnoff                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
7983c602fabSXin LI                 rpl_dio_printopt(ndo, opt, length);
7993c602fabSXin LI         }
8003c602fabSXin LI 	return;
8013c602fabSXin LI 
8023c602fabSXin LI trunc:
8033c602fabSXin LI 	ND_PRINT((ndo," [|dao-truncated]"));
8043c602fabSXin LI 	return;
8053c602fabSXin LI 
8063c602fabSXin LI tooshort:
8073c602fabSXin LI 	ND_PRINT((ndo," [|dao-length too short]"));
8083c602fabSXin LI 	return;
8093c602fabSXin LI }
81027df3f5dSRui Paulo 
81127df3f5dSRui Paulo static void
81227df3f5dSRui Paulo rpl_print(netdissect_options *ndo,
81327df3f5dSRui Paulo           const struct icmp6_hdr *hdr,
8143c602fabSXin LI           const u_char *bp, u_int length)
81527df3f5dSRui Paulo {
816cac3dcd5SXin LI         int secured = hdr->icmp6_code & 0x80;
817cac3dcd5SXin LI         int basecode= hdr->icmp6_code & 0x7f;
81827df3f5dSRui Paulo 
819cac3dcd5SXin LI         if(secured) {
8203c602fabSXin LI                 ND_PRINT((ndo, ", (SEC) [worktodo]"));
8213c602fabSXin LI                 /* XXX
8223c602fabSXin LI                  * the next header pointer needs to move forward to
8233c602fabSXin LI                  * skip the secure part.
8243c602fabSXin LI                  */
8253c602fabSXin LI                 return;
826cac3dcd5SXin LI         } else {
827cac3dcd5SXin LI                 ND_PRINT((ndo, ", (CLR)"));
828cac3dcd5SXin LI         }
829cac3dcd5SXin LI 
830cac3dcd5SXin LI         switch(basecode) {
8313c602fabSXin LI         case ND_RPL_DAG_IS:
832cac3dcd5SXin LI                 ND_PRINT((ndo, "DODAG Information Solicitation"));
83327df3f5dSRui Paulo                 if(ndo->ndo_vflag) {
83427df3f5dSRui Paulo                 }
83527df3f5dSRui Paulo                 break;
8363c602fabSXin LI         case ND_RPL_DAG_IO:
837cac3dcd5SXin LI                 ND_PRINT((ndo, "DODAG Information Object"));
83827df3f5dSRui Paulo                 if(ndo->ndo_vflag) {
8393c602fabSXin LI                         rpl_dio_print(ndo, bp, length);
84027df3f5dSRui Paulo                 }
84127df3f5dSRui Paulo                 break;
84227df3f5dSRui Paulo         case ND_RPL_DAO:
843cac3dcd5SXin LI                 ND_PRINT((ndo, "Destination Advertisement Object"));
844cac3dcd5SXin LI                 if(ndo->ndo_vflag) {
8453c602fabSXin LI                         rpl_dao_print(ndo, bp, length);
846cac3dcd5SXin LI                 }
847cac3dcd5SXin LI                 break;
848cac3dcd5SXin LI         case ND_RPL_DAO_ACK:
849cac3dcd5SXin LI                 ND_PRINT((ndo, "Destination Advertisement Object Ack"));
85027df3f5dSRui Paulo                 if(ndo->ndo_vflag) {
8513c602fabSXin LI                         rpl_daoack_print(ndo, bp, length);
85227df3f5dSRui Paulo                 }
85327df3f5dSRui Paulo                 break;
85427df3f5dSRui Paulo         default:
855cac3dcd5SXin LI                 ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
85627df3f5dSRui Paulo                 break;
85727df3f5dSRui Paulo         }
85827df3f5dSRui Paulo 	return;
8593c602fabSXin LI 
8603c602fabSXin LI #if 0
86127df3f5dSRui Paulo trunc:
86227df3f5dSRui Paulo 	ND_PRINT((ndo," [|truncated]"));
86327df3f5dSRui Paulo 	return;
8643c602fabSXin LI #endif
86527df3f5dSRui Paulo 
86627df3f5dSRui Paulo }
86727df3f5dSRui Paulo 
86827df3f5dSRui Paulo 
869b0453382SBill Fenner void
87027df3f5dSRui Paulo icmp6_print(netdissect_options *ndo,
87127df3f5dSRui Paulo             const u_char *bp, u_int length, const u_char *bp2, int fragmented)
872b0453382SBill Fenner {
873685295f4SBill Fenner 	const struct icmp6_hdr *dp;
874a90e161bSBill Fenner 	const struct ip6_hdr *ip;
875a90e161bSBill Fenner 	const struct ip6_hdr *oip;
876a90e161bSBill Fenner 	const struct udphdr *ouh;
877a90e161bSBill Fenner 	int dport;
878a90e161bSBill Fenner 	const u_char *ep;
8795b0fe478SBruce M Simpson 	u_int prot;
880b0453382SBill Fenner 
881*3340d773SGleb Smirnoff 	dp = (const struct icmp6_hdr *)bp;
882*3340d773SGleb Smirnoff 	ip = (const struct ip6_hdr *)bp2;
883*3340d773SGleb Smirnoff 	oip = (const struct ip6_hdr *)(dp + 1);
884685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
8853c602fabSXin LI 	ep = ndo->ndo_snapend;
886b0453382SBill Fenner 
8873c602fabSXin LI 	ND_TCHECK(dp->icmp6_cksum);
8885b0fe478SBruce M Simpson 
8893c602fabSXin LI 	if (ndo->ndo_vflag && !fragmented) {
8903c602fabSXin LI 		uint16_t sum, udp_sum;
8915b0fe478SBruce M Simpson 
8923c602fabSXin LI 		if (ND_TTEST2(bp[0], length)) {
893cac3dcd5SXin LI 			udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
894*3340d773SGleb Smirnoff 			sum = icmp6_cksum(ndo, ip, dp, length);
8955b0fe478SBruce M Simpson 			if (sum != 0)
8963c602fabSXin LI 				ND_PRINT((ndo,"[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
897cac3dcd5SXin LI                                                 udp_sum,
8983c602fabSXin LI                                                 in_cksum_shouldbe(udp_sum, sum)));
8995b0fe478SBruce M Simpson 			else
9003c602fabSXin LI 				ND_PRINT((ndo,"[icmp6 sum ok] "));
9015b0fe478SBruce M Simpson 		}
9025b0fe478SBruce M Simpson 	}
9035b0fe478SBruce M Simpson 
9043c602fabSXin LI         ND_PRINT((ndo,"ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)));
9051de50e9fSSam Leffler 
9061de50e9fSSam Leffler         /* display cosmetics: print the packet length for printer that use the vflag now */
9073c602fabSXin LI         if (ndo->ndo_vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT ||
90838034737SDimitry Andric                       dp->icmp6_type == ND_ROUTER_ADVERT ||
90938034737SDimitry Andric                       dp->icmp6_type == ND_NEIGHBOR_ADVERT ||
91038034737SDimitry Andric                       dp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
91138034737SDimitry Andric                       dp->icmp6_type == ND_REDIRECT ||
91238034737SDimitry Andric                       dp->icmp6_type == ICMP6_HADISCOV_REPLY ||
91338034737SDimitry Andric                       dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
9143c602fabSXin LI                 ND_PRINT((ndo,", length %u", length));
9151de50e9fSSam Leffler 
916b0453382SBill Fenner 	switch (dp->icmp6_type) {
917b0453382SBill Fenner 	case ICMP6_DST_UNREACH:
9183c602fabSXin LI 		ND_TCHECK(oip->ip6_dst);
9193c602fabSXin LI                 ND_PRINT((ndo,", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)));
920b0453382SBill Fenner 		switch (dp->icmp6_code) {
9211de50e9fSSam Leffler 
9221de50e9fSSam Leffler 		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
923b0453382SBill Fenner 		case ICMP6_DST_UNREACH_ADMIN:
9241de50e9fSSam Leffler 		case ICMP6_DST_UNREACH_ADDR:
9253c602fabSXin LI                         ND_PRINT((ndo," %s",ip6addr_string(ndo, &oip->ip6_dst)));
926b0453382SBill Fenner                         break;
927b0453382SBill Fenner 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
9283c602fabSXin LI 			ND_PRINT((ndo," %s, source address %s",
9293c602fabSXin LI 			       ip6addr_string(ndo, &oip->ip6_dst),
9303c602fabSXin LI                                   ip6addr_string(ndo, &oip->ip6_src)));
931b0453382SBill Fenner 			break;
932b0453382SBill Fenner 		case ICMP6_DST_UNREACH_NOPORT:
933*3340d773SGleb Smirnoff 			if ((ouh = get_upperlayer(ndo, (const u_char *)oip, &prot))
934685295f4SBill Fenner 			    == NULL)
935685295f4SBill Fenner 				goto trunc;
936685295f4SBill Fenner 
9375b0fe478SBruce M Simpson 			dport = EXTRACT_16BITS(&ouh->uh_dport);
938685295f4SBill Fenner 			switch (prot) {
939b0453382SBill Fenner 			case IPPROTO_TCP:
9403c602fabSXin LI 				ND_PRINT((ndo,", %s tcp port %s",
9413c602fabSXin LI 					ip6addr_string(ndo, &oip->ip6_dst),
942*3340d773SGleb Smirnoff                                           tcpport_string(ndo, dport)));
943b0453382SBill Fenner 				break;
944b0453382SBill Fenner 			case IPPROTO_UDP:
9453c602fabSXin LI 				ND_PRINT((ndo,", %s udp port %s",
9463c602fabSXin LI 					ip6addr_string(ndo, &oip->ip6_dst),
947*3340d773SGleb Smirnoff                                           udpport_string(ndo, dport)));
948b0453382SBill Fenner 				break;
949b0453382SBill Fenner 			default:
9503c602fabSXin LI 				ND_PRINT((ndo,", %s protocol %d port %d unreachable",
9513c602fabSXin LI 					ip6addr_string(ndo, &oip->ip6_dst),
9523c602fabSXin LI                                           oip->ip6_nxt, dport));
953b0453382SBill Fenner 				break;
954b0453382SBill Fenner 			}
955b0453382SBill Fenner 			break;
956b0453382SBill Fenner 		default:
9573c602fabSXin LI                   if (ndo->ndo_vflag <= 1) {
9583c602fabSXin LI                     print_unknown_data(ndo, bp,"\n\t",length);
9591de50e9fSSam Leffler                     return;
9601de50e9fSSam Leffler                   }
961b0453382SBill Fenner                     break;
962b0453382SBill Fenner 		}
963b0453382SBill Fenner 		break;
964b0453382SBill Fenner 	case ICMP6_PACKET_TOO_BIG:
9653c602fabSXin LI 		ND_TCHECK(dp->icmp6_mtu);
9663c602fabSXin LI 		ND_PRINT((ndo,", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)));
967b0453382SBill Fenner 		break;
968b0453382SBill Fenner 	case ICMP6_TIME_EXCEEDED:
9693c602fabSXin LI 		ND_TCHECK(oip->ip6_dst);
970b0453382SBill Fenner 		switch (dp->icmp6_code) {
971b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_TRANSIT:
9723c602fabSXin LI 			ND_PRINT((ndo," for %s",
9733c602fabSXin LI                                   ip6addr_string(ndo, &oip->ip6_dst)));
974b0453382SBill Fenner 			break;
975b0453382SBill Fenner 		case ICMP6_TIME_EXCEED_REASSEMBLY:
9763c602fabSXin LI 			ND_PRINT((ndo," (reassembly)"));
977b0453382SBill Fenner 			break;
978b0453382SBill Fenner 		default:
9793c602fabSXin LI                         ND_PRINT((ndo,", unknown code (%u)", dp->icmp6_code));
980b0453382SBill Fenner 			break;
981b0453382SBill Fenner 		}
982b0453382SBill Fenner 		break;
983b0453382SBill Fenner 	case ICMP6_PARAM_PROB:
9843c602fabSXin LI 		ND_TCHECK(oip->ip6_dst);
985b0453382SBill Fenner 		switch (dp->icmp6_code) {
986b0453382SBill Fenner 		case ICMP6_PARAMPROB_HEADER:
9873c602fabSXin LI                         ND_PRINT((ndo,", erroneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
988b0453382SBill Fenner                         break;
989b0453382SBill Fenner 		case ICMP6_PARAMPROB_NEXTHEADER:
9903c602fabSXin LI                         ND_PRINT((ndo,", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
991b0453382SBill Fenner                         break;
992b0453382SBill Fenner 		case ICMP6_PARAMPROB_OPTION:
9933c602fabSXin LI                         ND_PRINT((ndo,", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
994b0453382SBill Fenner                         break;
995b0453382SBill Fenner 		default:
9963c602fabSXin LI                         ND_PRINT((ndo,", code-#%d",
9973c602fabSXin LI                                   dp->icmp6_code));
998b0453382SBill Fenner                         break;
999b0453382SBill Fenner 		}
1000b0453382SBill Fenner 		break;
1001b0453382SBill Fenner 	case ICMP6_ECHO_REQUEST:
1002b0453382SBill Fenner 	case ICMP6_ECHO_REPLY:
10033c602fabSXin LI                 ND_TCHECK(dp->icmp6_seq);
10043c602fabSXin LI                 ND_PRINT((ndo,", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)));
1005b0453382SBill Fenner 		break;
1006b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_QUERY:
10071de50e9fSSam Leffler 		if (length == MLD_MINLEN) {
10083c602fabSXin LI 			mld6_print(ndo, (const u_char *)dp);
10091de50e9fSSam Leffler 		} else if (length >= MLDV2_MINLEN) {
10103c602fabSXin LI 			ND_PRINT((ndo," v2"));
10113c602fabSXin LI 			mldv2_query_print(ndo, (const u_char *)dp, length);
10121de50e9fSSam Leffler 		} else {
10133c602fabSXin LI                         ND_PRINT((ndo," unknown-version (len %u) ", length));
10141de50e9fSSam Leffler 		}
1015b0453382SBill Fenner 		break;
1016b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REPORT:
10173c602fabSXin LI 		mld6_print(ndo, (const u_char *)dp);
1018b0453382SBill Fenner 		break;
1019b0453382SBill Fenner 	case ICMP6_MEMBERSHIP_REDUCTION:
10203c602fabSXin LI 		mld6_print(ndo, (const u_char *)dp);
1021b0453382SBill Fenner 		break;
1022b0453382SBill Fenner 	case ND_ROUTER_SOLICIT:
1023b0453382SBill Fenner #define RTSOLLEN 8
10243c602fabSXin LI 		if (ndo->ndo_vflag) {
10253c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + RTSOLLEN,
10265b0fe478SBruce M Simpson 					length - RTSOLLEN);
1027b0453382SBill Fenner 		}
1028b0453382SBill Fenner 		break;
1029b0453382SBill Fenner 	case ND_ROUTER_ADVERT:
10301de50e9fSSam Leffler #define RTADVLEN 16
10313c602fabSXin LI 		if (ndo->ndo_vflag) {
1032*3340d773SGleb Smirnoff 			const struct nd_router_advert *p;
1033b0453382SBill Fenner 
1034*3340d773SGleb Smirnoff 			p = (const struct nd_router_advert *)dp;
10353c602fabSXin LI 			ND_TCHECK(p->nd_ra_retransmit);
10363c602fabSXin LI 			ND_PRINT((ndo,"\n\thop limit %u, Flags [%s]" \
10371de50e9fSSam Leffler                                   ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
10381de50e9fSSam Leffler                                   (u_int)p->nd_ra_curhoplimit,
10391de50e9fSSam Leffler                                   bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
10401de50e9fSSam Leffler                                   get_rtpref(p->nd_ra_flags_reserved),
10411de50e9fSSam Leffler                                   EXTRACT_16BITS(&p->nd_ra_router_lifetime),
10421de50e9fSSam Leffler                                   EXTRACT_32BITS(&p->nd_ra_reachable),
10433c602fabSXin LI                                   EXTRACT_32BITS(&p->nd_ra_retransmit)));
10441de50e9fSSam Leffler 
10453c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + RTADVLEN,
10465b0fe478SBruce M Simpson 					length - RTADVLEN);
1047b0453382SBill Fenner 		}
1048b0453382SBill Fenner 		break;
1049b0453382SBill Fenner 	case ND_NEIGHBOR_SOLICIT:
1050b0453382SBill Fenner 	    {
1051*3340d773SGleb Smirnoff 		const struct nd_neighbor_solicit *p;
1052*3340d773SGleb Smirnoff 		p = (const struct nd_neighbor_solicit *)dp;
10533c602fabSXin LI 		ND_TCHECK(p->nd_ns_target);
10543c602fabSXin LI 		ND_PRINT((ndo,", who has %s", ip6addr_string(ndo, &p->nd_ns_target)));
10553c602fabSXin LI 		if (ndo->ndo_vflag) {
1056b0453382SBill Fenner #define NDSOLLEN 24
10573c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + NDSOLLEN,
10585b0fe478SBruce M Simpson 					length - NDSOLLEN);
1059b0453382SBill Fenner 		}
1060b0453382SBill Fenner 	    }
1061b0453382SBill Fenner 		break;
1062b0453382SBill Fenner 	case ND_NEIGHBOR_ADVERT:
1063b0453382SBill Fenner 	    {
1064*3340d773SGleb Smirnoff 		const struct nd_neighbor_advert *p;
1065b0453382SBill Fenner 
1066*3340d773SGleb Smirnoff 		p = (const struct nd_neighbor_advert *)dp;
10673c602fabSXin LI 		ND_TCHECK(p->nd_na_target);
10683c602fabSXin LI 		ND_PRINT((ndo,", tgt is %s",
10693c602fabSXin LI                           ip6addr_string(ndo, &p->nd_na_target)));
10703c602fabSXin LI 		if (ndo->ndo_vflag) {
10713c602fabSXin LI                         ND_PRINT((ndo,", Flags [%s]",
10721de50e9fSSam Leffler                                   bittok2str(icmp6_nd_na_flag_values,
10731de50e9fSSam Leffler                                              "none",
10743c602fabSXin LI                                              EXTRACT_32BITS(&p->nd_na_flags_reserved))));
1075b0453382SBill Fenner #define NDADVLEN 24
10763c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + NDADVLEN,
10775b0fe478SBruce M Simpson 					length - NDADVLEN);
1078685295f4SBill Fenner #undef NDADVLEN
1079b0453382SBill Fenner 		}
1080b0453382SBill Fenner 	    }
1081b0453382SBill Fenner 		break;
1082b0453382SBill Fenner 	case ND_REDIRECT:
1083*3340d773SGleb Smirnoff #define RDR(i) ((const struct nd_redirect *)(i))
10843c602fabSXin LI                          ND_TCHECK(RDR(dp)->nd_rd_dst);
1085*3340d773SGleb Smirnoff                          ND_PRINT((ndo,", %s", ip6addr_string(ndo, &RDR(dp)->nd_rd_dst)));
10863c602fabSXin LI 		ND_TCHECK(RDR(dp)->nd_rd_target);
10873c602fabSXin LI 		ND_PRINT((ndo," to %s",
1088*3340d773SGleb Smirnoff                           ip6addr_string(ndo, &RDR(dp)->nd_rd_target)));
1089b0453382SBill Fenner #define REDIRECTLEN 40
10903c602fabSXin LI 		if (ndo->ndo_vflag) {
10913c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + REDIRECTLEN,
10925b0fe478SBruce M Simpson 					length - REDIRECTLEN);
1093b0453382SBill Fenner 		}
1094b0453382SBill Fenner 		break;
1095685295f4SBill Fenner #undef REDIRECTLEN
1096685295f4SBill Fenner #undef RDR
1097b0453382SBill Fenner 	case ICMP6_ROUTER_RENUMBERING:
10983c602fabSXin LI 		icmp6_rrenum_print(ndo, bp, ep);
1099b0453382SBill Fenner 		break;
1100685295f4SBill Fenner 	case ICMP6_NI_QUERY:
1101685295f4SBill Fenner 	case ICMP6_NI_REPLY:
11023c602fabSXin LI 		icmp6_nodeinfo_print(ndo, length, bp, ep);
11035b0fe478SBruce M Simpson 		break;
11041de50e9fSSam Leffler 	case IND_SOLICIT:
11051de50e9fSSam Leffler 	case IND_ADVERT:
11061de50e9fSSam Leffler 		break;
11071de50e9fSSam Leffler 	case ICMP6_V2_MEMBERSHIP_REPORT:
11083c602fabSXin LI 		mldv2_report_print(ndo, (const u_char *) dp, length);
11091de50e9fSSam Leffler 		break;
11101de50e9fSSam Leffler 	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
11115b0fe478SBruce M Simpson 	case ICMP6_HADISCOV_REQUEST:
11123c602fabSXin LI                 ND_TCHECK(dp->icmp6_data16[0]);
11133c602fabSXin LI                 ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
11145b0fe478SBruce M Simpson                 break;
11155b0fe478SBruce M Simpson 	case ICMP6_HADISCOV_REPLY:
11163c602fabSXin LI 		if (ndo->ndo_vflag) {
1117*3340d773SGleb Smirnoff 			const struct in6_addr *in6;
1118*3340d773SGleb Smirnoff 			const u_char *cp;
11195b0fe478SBruce M Simpson 
11203c602fabSXin LI 			ND_TCHECK(dp->icmp6_data16[0]);
11213c602fabSXin LI 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1122*3340d773SGleb Smirnoff 			cp = (const u_char *)dp + length;
1123*3340d773SGleb Smirnoff 			in6 = (const struct in6_addr *)(dp + 1);
1124*3340d773SGleb Smirnoff 			for (; (const u_char *)in6 < cp; in6++) {
11253c602fabSXin LI 				ND_TCHECK(*in6);
11263c602fabSXin LI 				ND_PRINT((ndo,", %s", ip6addr_string(ndo, in6)));
11275b0fe478SBruce M Simpson 			}
11285b0fe478SBruce M Simpson 		}
11295b0fe478SBruce M Simpson 		break;
11305b0fe478SBruce M Simpson 	case ICMP6_MOBILEPREFIX_ADVERT:
11313c602fabSXin LI 		if (ndo->ndo_vflag) {
11323c602fabSXin LI 			ND_TCHECK(dp->icmp6_data16[0]);
11333c602fabSXin LI 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
11345b0fe478SBruce M Simpson 			if (dp->icmp6_data16[1] & 0xc0)
11353c602fabSXin LI 				ND_PRINT((ndo," "));
11365b0fe478SBruce M Simpson 			if (dp->icmp6_data16[1] & 0x80)
11373c602fabSXin LI 				ND_PRINT((ndo,"M"));
11385b0fe478SBruce M Simpson 			if (dp->icmp6_data16[1] & 0x40)
11393c602fabSXin LI 				ND_PRINT((ndo,"O"));
11405b0fe478SBruce M Simpson #define MPADVLEN 8
11413c602fabSXin LI 			icmp6_opt_print(ndo, (const u_char *)dp + MPADVLEN,
11425b0fe478SBruce M Simpson 					length - MPADVLEN);
11435b0fe478SBruce M Simpson 		}
1144b0453382SBill Fenner 		break;
114527df3f5dSRui Paulo         case ND_RPL_MESSAGE:
11463c602fabSXin LI                 /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */
11473c602fabSXin LI                 rpl_print(ndo, dp, &dp->icmp6_data8[0], length-sizeof(struct icmp6_hdr)+4);
114827df3f5dSRui Paulo                 break;
1149b0453382SBill Fenner 	default:
11503c602fabSXin LI                 ND_PRINT((ndo,", length %u", length));
11513c602fabSXin LI                 if (ndo->ndo_vflag <= 1)
11523c602fabSXin LI                         print_unknown_data(ndo, bp,"\n\t", length);
11531de50e9fSSam Leffler                 return;
1154b0453382SBill Fenner         }
11553c602fabSXin LI         if (!ndo->ndo_vflag)
11563c602fabSXin LI                 ND_PRINT((ndo,", length %u", length));
1157b0453382SBill Fenner 	return;
1158b0453382SBill Fenner trunc:
11593c602fabSXin LI 	ND_PRINT((ndo, "[|icmp6]"));
1160b0453382SBill Fenner }
1161b0453382SBill Fenner 
11623c602fabSXin LI static const struct udphdr *
11633c602fabSXin LI get_upperlayer(netdissect_options *ndo, const u_char *bp, u_int *prot)
1164685295f4SBill Fenner {
1165a90e161bSBill Fenner 	const u_char *ep;
1166*3340d773SGleb Smirnoff 	const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
11673c602fabSXin LI 	const struct udphdr *uh;
11683c602fabSXin LI 	const struct ip6_hbh *hbh;
11693c602fabSXin LI 	const struct ip6_frag *fragh;
11703c602fabSXin LI 	const struct ah *ah;
11715b0fe478SBruce M Simpson 	u_int nh;
11725b0fe478SBruce M Simpson 	int hlen;
1173685295f4SBill Fenner 
1174685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
11753c602fabSXin LI 	ep = ndo->ndo_snapend;
1176685295f4SBill Fenner 
11773c602fabSXin LI 	if (!ND_TTEST(ip6->ip6_nxt))
1178685295f4SBill Fenner 		return NULL;
1179685295f4SBill Fenner 
1180685295f4SBill Fenner 	nh = ip6->ip6_nxt;
1181685295f4SBill Fenner 	hlen = sizeof(struct ip6_hdr);
1182685295f4SBill Fenner 
1183f4d0c64aSSam Leffler 	while (bp < ep) {
1184685295f4SBill Fenner 		bp += hlen;
1185685295f4SBill Fenner 
1186685295f4SBill Fenner 		switch(nh) {
1187685295f4SBill Fenner 		case IPPROTO_UDP:
1188685295f4SBill Fenner 		case IPPROTO_TCP:
1189*3340d773SGleb Smirnoff 			uh = (const struct udphdr *)bp;
11903c602fabSXin LI 			if (ND_TTEST(uh->uh_dport)) {
1191685295f4SBill Fenner 				*prot = nh;
1192685295f4SBill Fenner 				return(uh);
1193685295f4SBill Fenner 			}
1194685295f4SBill Fenner 			else
1195685295f4SBill Fenner 				return(NULL);
1196685295f4SBill Fenner 			/* NOTREACHED */
1197685295f4SBill Fenner 
1198685295f4SBill Fenner 		case IPPROTO_HOPOPTS:
1199685295f4SBill Fenner 		case IPPROTO_DSTOPTS:
1200685295f4SBill Fenner 		case IPPROTO_ROUTING:
1201*3340d773SGleb Smirnoff 			hbh = (const struct ip6_hbh *)bp;
12023c602fabSXin LI 			if (!ND_TTEST(hbh->ip6h_len))
1203685295f4SBill Fenner 				return(NULL);
1204685295f4SBill Fenner 			nh = hbh->ip6h_nxt;
1205685295f4SBill Fenner 			hlen = (hbh->ip6h_len + 1) << 3;
1206685295f4SBill Fenner 			break;
1207685295f4SBill Fenner 
1208685295f4SBill Fenner 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
1209*3340d773SGleb Smirnoff 			fragh = (const struct ip6_frag *)bp;
12103c602fabSXin LI 			if (!ND_TTEST(fragh->ip6f_offlg))
1211685295f4SBill Fenner 				return(NULL);
1212685295f4SBill Fenner 			/* fragments with non-zero offset are meaningless */
12135b0fe478SBruce M Simpson 			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
1214685295f4SBill Fenner 				return(NULL);
1215685295f4SBill Fenner 			nh = fragh->ip6f_nxt;
1216685295f4SBill Fenner 			hlen = sizeof(struct ip6_frag);
1217685295f4SBill Fenner 			break;
1218685295f4SBill Fenner 
1219685295f4SBill Fenner 		case IPPROTO_AH:
1220*3340d773SGleb Smirnoff 			ah = (const struct ah *)bp;
12213c602fabSXin LI 			if (!ND_TTEST(ah->ah_len))
1222685295f4SBill Fenner 				return(NULL);
1223685295f4SBill Fenner 			nh = ah->ah_nxt;
1224685295f4SBill Fenner 			hlen = (ah->ah_len + 2) << 2;
1225685295f4SBill Fenner 			break;
1226685295f4SBill Fenner 
1227685295f4SBill Fenner 		default:	/* unknown or undecodable header */
1228685295f4SBill Fenner 			*prot = nh; /* meaningless, but set here anyway */
1229685295f4SBill Fenner 			return(NULL);
1230685295f4SBill Fenner 		}
1231685295f4SBill Fenner 	}
1232685295f4SBill Fenner 
1233685295f4SBill Fenner 	return(NULL);		/* should be notreached, though */
1234685295f4SBill Fenner }
1235685295f4SBill Fenner 
12365b0fe478SBruce M Simpson static void
12373c602fabSXin LI icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
1238b0453382SBill Fenner {
1239a90e161bSBill Fenner 	const struct nd_opt_hdr *op;
1240a90e161bSBill Fenner 	const struct nd_opt_prefix_info *opp;
1241a90e161bSBill Fenner 	const struct nd_opt_mtu *opm;
124227df3f5dSRui Paulo 	const struct nd_opt_rdnss *oprd;
1243d03c0883SXin LI 	const struct nd_opt_dnssl *opds;
1244a90e161bSBill Fenner 	const struct nd_opt_advinterval *opa;
12455b0fe478SBruce M Simpson 	const struct nd_opt_homeagent_info *oph;
1246a90e161bSBill Fenner 	const struct nd_opt_route_info *opri;
1247d03c0883SXin LI 	const u_char *cp, *ep, *domp;
1248*3340d773SGleb Smirnoff 	struct in6_addr in6;
1249*3340d773SGleb Smirnoff 	const struct in6_addr *in6p;
1250a90e161bSBill Fenner 	size_t l;
125127df3f5dSRui Paulo 	u_int i;
1252b0453382SBill Fenner 
1253*3340d773SGleb Smirnoff #define ECHECK(var) if ((const u_char *)&(var) > ep - sizeof(var)) return
1254b0453382SBill Fenner 
1255a90e161bSBill Fenner 	cp = bp;
1256685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
12573c602fabSXin LI 	ep = ndo->ndo_snapend;
1258b0453382SBill Fenner 
1259a90e161bSBill Fenner 	while (cp < ep) {
1260*3340d773SGleb Smirnoff 		op = (const struct nd_opt_hdr *)cp;
1261a90e161bSBill Fenner 
1262b0453382SBill Fenner 		ECHECK(op->nd_opt_len);
1263b0453382SBill Fenner 		if (resid <= 0)
1264b0453382SBill Fenner 			return;
1265a90e161bSBill Fenner 		if (op->nd_opt_len == 0)
1266a90e161bSBill Fenner 			goto trunc;
1267a90e161bSBill Fenner 		if (cp + (op->nd_opt_len << 3) > ep)
1268a90e161bSBill Fenner 			goto trunc;
1269a90e161bSBill Fenner 
12703c602fabSXin LI                 ND_PRINT((ndo,"\n\t  %s option (%u), length %u (%u): ",
12711de50e9fSSam Leffler                           tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
12721de50e9fSSam Leffler                           op->nd_opt_type,
12731de50e9fSSam Leffler                           op->nd_opt_len << 3,
12743c602fabSXin LI                           op->nd_opt_len));
12751de50e9fSSam Leffler 
1276b0453382SBill Fenner 		switch (op->nd_opt_type) {
1277b0453382SBill Fenner 		case ND_OPT_SOURCE_LINKADDR:
1278a90e161bSBill Fenner 			l = (op->nd_opt_len << 3) - 2;
12793c602fabSXin LI 			print_lladdr(ndo, cp + 2, l);
1280b0453382SBill Fenner 			break;
1281b0453382SBill Fenner 		case ND_OPT_TARGET_LINKADDR:
1282a90e161bSBill Fenner 			l = (op->nd_opt_len << 3) - 2;
12833c602fabSXin LI 			print_lladdr(ndo, cp + 2, l);
1284b0453382SBill Fenner 			break;
1285b0453382SBill Fenner 		case ND_OPT_PREFIX_INFORMATION:
1286*3340d773SGleb Smirnoff 			opp = (const struct nd_opt_prefix_info *)op;
12873c602fabSXin LI 			ND_TCHECK(opp->nd_opt_pi_prefix);
12883c602fabSXin LI                         ND_PRINT((ndo,"%s/%u%s, Flags [%s], valid time %s",
12893c602fabSXin LI                                   ip6addr_string(ndo, &opp->nd_opt_pi_prefix),
12901de50e9fSSam Leffler                                   opp->nd_opt_pi_prefix_len,
12911de50e9fSSam Leffler                                   (op->nd_opt_len != 4) ? "badlen" : "",
12921de50e9fSSam Leffler                                   bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
12933c602fabSXin LI                                   get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))));
12943c602fabSXin LI                         ND_PRINT((ndo,", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))));
1295b0453382SBill Fenner 			break;
1296b0453382SBill Fenner 		case ND_OPT_REDIRECTED_HEADER:
12973c602fabSXin LI                         print_unknown_data(ndo, bp,"\n\t    ",op->nd_opt_len<<3);
1298b0453382SBill Fenner 			/* xxx */
1299b0453382SBill Fenner 			break;
1300b0453382SBill Fenner 		case ND_OPT_MTU:
1301*3340d773SGleb Smirnoff 			opm = (const struct nd_opt_mtu *)op;
13023c602fabSXin LI 			ND_TCHECK(opm->nd_opt_mtu_mtu);
13033c602fabSXin LI 			ND_PRINT((ndo," %u%s",
13041de50e9fSSam Leffler                                EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
13053c602fabSXin LI                                   (op->nd_opt_len != 1) ? "bad option length" : "" ));
1306b0453382SBill Fenner                         break;
130727df3f5dSRui Paulo 		case ND_OPT_RDNSS:
1308*3340d773SGleb Smirnoff 			oprd = (const struct nd_opt_rdnss *)op;
130927df3f5dSRui Paulo 			l = (op->nd_opt_len - 1) / 2;
13103c602fabSXin LI 			ND_PRINT((ndo," lifetime %us,",
13113c602fabSXin LI                                   EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)));
131227df3f5dSRui Paulo 			for (i = 0; i < l; i++) {
13133c602fabSXin LI 				ND_TCHECK(oprd->nd_opt_rdnss_addr[i]);
13143c602fabSXin LI 				ND_PRINT((ndo," addr: %s",
13153c602fabSXin LI                                           ip6addr_string(ndo, &oprd->nd_opt_rdnss_addr[i])));
131627df3f5dSRui Paulo 			}
131727df3f5dSRui Paulo 			break;
1318d03c0883SXin LI 		case ND_OPT_DNSSL:
1319*3340d773SGleb Smirnoff 			opds = (const struct nd_opt_dnssl *)op;
13203c602fabSXin LI 			ND_PRINT((ndo," lifetime %us, domain(s):",
13213c602fabSXin LI                                   EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime)));
1322d03c0883SXin LI 			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
1323d03c0883SXin LI 			while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0')
1324d03c0883SXin LI 			{
13253c602fabSXin LI 				ND_PRINT((ndo, " "));
13263c602fabSXin LI 				if ((domp = ns_nprint (ndo, domp, bp)) == NULL)
1327d03c0883SXin LI 					goto trunc;
1328d03c0883SXin LI 			}
1329d03c0883SXin LI 			break;
1330a90e161bSBill Fenner 		case ND_OPT_ADVINTERVAL:
1331*3340d773SGleb Smirnoff 			opa = (const struct nd_opt_advinterval *)op;
13323c602fabSXin LI 			ND_TCHECK(opa->nd_opt_adv_interval);
13333c602fabSXin LI 			ND_PRINT((ndo," %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval)));
1334a90e161bSBill Fenner 			break;
13355b0fe478SBruce M Simpson                 case ND_OPT_HOMEAGENT_INFO:
1336*3340d773SGleb Smirnoff 			oph = (const struct nd_opt_homeagent_info *)op;
13373c602fabSXin LI 			ND_TCHECK(oph->nd_opt_hai_lifetime);
13383c602fabSXin LI 			ND_PRINT((ndo," preference %u, lifetime %u",
13391de50e9fSSam Leffler                                   EXTRACT_16BITS(&oph->nd_opt_hai_preference),
13403c602fabSXin LI                                   EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)));
13415b0fe478SBruce M Simpson 			break;
1342a90e161bSBill Fenner 		case ND_OPT_ROUTE_INFO:
1343*3340d773SGleb Smirnoff 			opri = (const struct nd_opt_route_info *)op;
13443c602fabSXin LI 			ND_TCHECK(opri->nd_opt_rti_lifetime);
1345a90e161bSBill Fenner 			memset(&in6, 0, sizeof(in6));
1346*3340d773SGleb Smirnoff 			in6p = (const struct in6_addr *)(opri + 1);
1347a90e161bSBill Fenner 			switch (op->nd_opt_len) {
1348a90e161bSBill Fenner 			case 1:
1349a90e161bSBill Fenner 				break;
1350a90e161bSBill Fenner 			case 2:
13513c602fabSXin LI 				ND_TCHECK2(*in6p, 8);
1352a90e161bSBill Fenner 				memcpy(&in6, opri + 1, 8);
1353a90e161bSBill Fenner 				break;
1354a90e161bSBill Fenner 			case 3:
13553c602fabSXin LI 				ND_TCHECK(*in6p);
1356a90e161bSBill Fenner 				memcpy(&in6, opri + 1, sizeof(in6));
1357685295f4SBill Fenner 				break;
1358b0453382SBill Fenner 			default:
1359a90e161bSBill Fenner 				goto trunc;
1360a90e161bSBill Fenner 			}
13613c602fabSXin LI 			ND_PRINT((ndo," %s/%u", ip6addr_string(ndo, &in6),
13623c602fabSXin LI                                   opri->nd_opt_rti_prefixlen));
13633c602fabSXin LI 			ND_PRINT((ndo,", pref=%s", get_rtpref(opri->nd_opt_rti_flags)));
13643c602fabSXin LI 			ND_PRINT((ndo,", lifetime=%s",
13653c602fabSXin LI                                   get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))));
1366a90e161bSBill Fenner 			break;
1367a90e161bSBill Fenner 		default:
13683c602fabSXin LI                         if (ndo->ndo_vflag <= 1) {
13693c602fabSXin LI                                 print_unknown_data(ndo,cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
13701de50e9fSSam Leffler                             return;
13711de50e9fSSam Leffler                         }
1372b0453382SBill Fenner                         break;
1373b0453382SBill Fenner 		}
13741de50e9fSSam Leffler                 /* do we want to see an additional hexdump ? */
13753c602fabSXin LI                 if (ndo->ndo_vflag> 1)
13763c602fabSXin LI                         print_unknown_data(ndo, cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
1377a90e161bSBill Fenner 
1378a90e161bSBill Fenner 		cp += op->nd_opt_len << 3;
1379a90e161bSBill Fenner 		resid -= op->nd_opt_len << 3;
1380a90e161bSBill Fenner 	}
1381b0453382SBill Fenner 	return;
1382a90e161bSBill Fenner 
1383b0453382SBill Fenner  trunc:
13843c602fabSXin LI 	ND_PRINT((ndo, "[ndp opt]"));
1385b0453382SBill Fenner 	return;
1386b0453382SBill Fenner #undef ECHECK
1387b0453382SBill Fenner }
1388b0453382SBill Fenner 
13895b0fe478SBruce M Simpson static void
13903c602fabSXin LI mld6_print(netdissect_options *ndo, const u_char *bp)
1391b0453382SBill Fenner {
1392*3340d773SGleb Smirnoff 	const struct mld6_hdr *mp = (const struct mld6_hdr *)bp;
1393a90e161bSBill Fenner 	const u_char *ep;
1394b0453382SBill Fenner 
1395685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
13963c602fabSXin LI 	ep = ndo->ndo_snapend;
1397b0453382SBill Fenner 
1398*3340d773SGleb Smirnoff 	if ((const u_char *)mp + sizeof(*mp) > ep)
1399b0453382SBill Fenner 		return;
1400b0453382SBill Fenner 
14013c602fabSXin LI 	ND_PRINT((ndo,"max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)));
14023c602fabSXin LI 	ND_PRINT((ndo,"addr: %s", ip6addr_string(ndo, &mp->mld6_addr)));
1403685295f4SBill Fenner }
1404685295f4SBill Fenner 
1405685295f4SBill Fenner static void
14063c602fabSXin LI mldv2_report_print(netdissect_options *ndo, const u_char *bp, u_int len)
14071de50e9fSSam Leffler {
1408*3340d773SGleb Smirnoff     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
14091de50e9fSSam Leffler     u_int group, nsrcs, ngroups;
14101de50e9fSSam Leffler     u_int i, j;
14111de50e9fSSam Leffler 
14121de50e9fSSam Leffler     /* Minimum len is 8 */
14131de50e9fSSam Leffler     if (len < 8) {
14143c602fabSXin LI             ND_PRINT((ndo," [invalid len %d]", len));
14151de50e9fSSam Leffler             return;
14161de50e9fSSam Leffler     }
14171de50e9fSSam Leffler 
14183c602fabSXin LI     ND_TCHECK(icp->icmp6_data16[1]);
141927df3f5dSRui Paulo     ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
14203c602fabSXin LI     ND_PRINT((ndo,", %d group record(s)", ngroups));
14213c602fabSXin LI     if (ndo->ndo_vflag > 0) {
14221de50e9fSSam Leffler 	/* Print the group records */
14231de50e9fSSam Leffler 	group = 8;
14241de50e9fSSam Leffler         for (i = 0; i < ngroups; i++) {
14251de50e9fSSam Leffler 	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
14261de50e9fSSam Leffler 	    if (len < group + 20) {
14273c602fabSXin LI                     ND_PRINT((ndo," [invalid number of groups]"));
14281de50e9fSSam Leffler                     return;
14291de50e9fSSam Leffler 	    }
14303c602fabSXin LI             ND_TCHECK2(bp[group + 4], sizeof(struct in6_addr));
14313c602fabSXin LI             ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[group + 4])));
14323c602fabSXin LI 	    ND_PRINT((ndo," %s", tok2str(mldv2report2str, " [v2-report-#%d]",
14333c602fabSXin LI                                          bp[group])));
14341de50e9fSSam Leffler             nsrcs = (bp[group + 2] << 8) + bp[group + 3];
14351de50e9fSSam Leffler 	    /* Check the number of sources and print them */
14362ebc47dbSSam Leffler 	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
14373c602fabSXin LI                     ND_PRINT((ndo," [invalid number of sources %d]", nsrcs));
14381de50e9fSSam Leffler                     return;
14391de50e9fSSam Leffler 	    }
14403c602fabSXin LI             if (ndo->ndo_vflag == 1)
14413c602fabSXin LI                     ND_PRINT((ndo,", %d source(s)", nsrcs));
14421de50e9fSSam Leffler             else {
14431de50e9fSSam Leffler 		/* Print the sources */
14443c602fabSXin LI                     ND_PRINT((ndo," {"));
14451de50e9fSSam Leffler                 for (j = 0; j < nsrcs; j++) {
14463c602fabSXin LI                     ND_TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
14472ebc47dbSSam Leffler                             sizeof(struct in6_addr));
14483c602fabSXin LI 		    ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[group + 20 + j * sizeof(struct in6_addr)])));
14491de50e9fSSam Leffler 		}
14503c602fabSXin LI                 ND_PRINT((ndo," }"));
14511de50e9fSSam Leffler             }
14521de50e9fSSam Leffler 	    /* Next group record */
14532ebc47dbSSam Leffler             group += 20 + nsrcs * sizeof(struct in6_addr);
14543c602fabSXin LI 	    ND_PRINT((ndo,"]"));
14551de50e9fSSam Leffler         }
14561de50e9fSSam Leffler     }
14571de50e9fSSam Leffler     return;
14581de50e9fSSam Leffler trunc:
14593c602fabSXin LI     ND_PRINT((ndo,"[|icmp6]"));
14601de50e9fSSam Leffler     return;
14611de50e9fSSam Leffler }
14621de50e9fSSam Leffler 
14631de50e9fSSam Leffler static void
14643c602fabSXin LI mldv2_query_print(netdissect_options *ndo, const u_char *bp, u_int len)
14651de50e9fSSam Leffler {
1466*3340d773SGleb Smirnoff     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
14671de50e9fSSam Leffler     u_int mrc;
14681de50e9fSSam Leffler     int mrt, qqi;
14691de50e9fSSam Leffler     u_int nsrcs;
14701de50e9fSSam Leffler     register u_int i;
14711de50e9fSSam Leffler 
14721de50e9fSSam Leffler     /* Minimum len is 28 */
14731de50e9fSSam Leffler     if (len < 28) {
14743c602fabSXin LI             ND_PRINT((ndo," [invalid len %d]", len));
14751de50e9fSSam Leffler 	return;
14761de50e9fSSam Leffler     }
14773c602fabSXin LI     ND_TCHECK(icp->icmp6_data16[0]);
147827df3f5dSRui Paulo     mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
14791de50e9fSSam Leffler     if (mrc < 32768) {
14801de50e9fSSam Leffler 	mrt = mrc;
14811de50e9fSSam Leffler     } else {
14821de50e9fSSam Leffler         mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
14831de50e9fSSam Leffler     }
14843c602fabSXin LI     if (ndo->ndo_vflag) {
14853c602fabSXin LI             ND_PRINT((ndo," [max resp delay=%d]", mrt));
14861de50e9fSSam Leffler     }
14873c602fabSXin LI     ND_TCHECK2(bp[8], sizeof(struct in6_addr));
14883c602fabSXin LI     ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[8])));
14891de50e9fSSam Leffler 
14903c602fabSXin LI     if (ndo->ndo_vflag) {
14913c602fabSXin LI         ND_TCHECK(bp[25]);
14921de50e9fSSam Leffler 	if (bp[24] & 0x08) {
14933c602fabSXin LI 		ND_PRINT((ndo," sflag"));
14941de50e9fSSam Leffler 	}
14951de50e9fSSam Leffler 	if (bp[24] & 0x07) {
14963c602fabSXin LI 		ND_PRINT((ndo," robustness=%d", bp[24] & 0x07));
14971de50e9fSSam Leffler 	}
14981de50e9fSSam Leffler 	if (bp[25] < 128) {
14991de50e9fSSam Leffler 		qqi = bp[25];
15001de50e9fSSam Leffler 	} else {
15011de50e9fSSam Leffler 		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
15021de50e9fSSam Leffler 	}
15033c602fabSXin LI 	ND_PRINT((ndo," qqi=%d", qqi));
15041de50e9fSSam Leffler     }
15051de50e9fSSam Leffler 
15063c602fabSXin LI     ND_TCHECK2(bp[26], 2);
150727df3f5dSRui Paulo     nsrcs = EXTRACT_16BITS(&bp[26]);
15081de50e9fSSam Leffler     if (nsrcs > 0) {
15092ebc47dbSSam Leffler 	if (len < 28 + nsrcs * sizeof(struct in6_addr))
15103c602fabSXin LI 	    ND_PRINT((ndo," [invalid number of sources]"));
15113c602fabSXin LI 	else if (ndo->ndo_vflag > 1) {
15123c602fabSXin LI 	    ND_PRINT((ndo," {"));
15131de50e9fSSam Leffler 	    for (i = 0; i < nsrcs; i++) {
15143c602fabSXin LI 		ND_TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
15152ebc47dbSSam Leffler                         sizeof(struct in6_addr));
15163c602fabSXin LI 		ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[28 + i * sizeof(struct in6_addr)])));
15171de50e9fSSam Leffler 	    }
15183c602fabSXin LI 	    ND_PRINT((ndo," }"));
15191de50e9fSSam Leffler 	} else
15203c602fabSXin LI                 ND_PRINT((ndo,", %d source(s)", nsrcs));
15211de50e9fSSam Leffler     }
15223c602fabSXin LI     ND_PRINT((ndo,"]"));
15231de50e9fSSam Leffler     return;
15241de50e9fSSam Leffler trunc:
15253c602fabSXin LI     ND_PRINT((ndo,"[|icmp6]"));
15261de50e9fSSam Leffler     return;
15271de50e9fSSam Leffler }
15281de50e9fSSam Leffler 
152927df3f5dSRui Paulo static void
15303c602fabSXin LI dnsname_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
1531685295f4SBill Fenner {
1532685295f4SBill Fenner 	int i;
1533685295f4SBill Fenner 
1534685295f4SBill Fenner 	/* DNS name decoding - no decompression */
15353c602fabSXin LI 	ND_PRINT((ndo,", \""));
1536685295f4SBill Fenner 	while (cp < ep) {
1537685295f4SBill Fenner 		i = *cp++;
1538685295f4SBill Fenner 		if (i) {
1539685295f4SBill Fenner 			if (i > ep - cp) {
15403c602fabSXin LI 				ND_PRINT((ndo,"???"));
1541685295f4SBill Fenner 				break;
1542685295f4SBill Fenner 			}
1543685295f4SBill Fenner 			while (i-- && cp < ep) {
15443c602fabSXin LI 				safeputchar(ndo, *cp);
1545685295f4SBill Fenner 				cp++;
1546685295f4SBill Fenner 			}
1547685295f4SBill Fenner 			if (cp + 1 < ep && *cp)
15483c602fabSXin LI 				ND_PRINT((ndo,"."));
1549685295f4SBill Fenner 		} else {
1550685295f4SBill Fenner 			if (cp == ep) {
1551685295f4SBill Fenner 				/* FQDN */
15523c602fabSXin LI 				ND_PRINT((ndo,"."));
1553685295f4SBill Fenner 			} else if (cp + 1 == ep && *cp == '\0') {
1554685295f4SBill Fenner 				/* truncated */
1555685295f4SBill Fenner 			} else {
1556685295f4SBill Fenner 				/* invalid */
15573c602fabSXin LI 				ND_PRINT((ndo,"???"));
1558685295f4SBill Fenner 			}
1559685295f4SBill Fenner 			break;
1560685295f4SBill Fenner 		}
1561685295f4SBill Fenner 	}
15623c602fabSXin LI 	ND_PRINT((ndo,"\""));
1563685295f4SBill Fenner }
1564685295f4SBill Fenner 
15655b0fe478SBruce M Simpson static void
15663c602fabSXin LI icmp6_nodeinfo_print(netdissect_options *ndo, u_int icmp6len, const u_char *bp, const u_char *ep)
1567685295f4SBill Fenner {
15683c602fabSXin LI 	const struct icmp6_nodeinfo *ni6;
15693c602fabSXin LI 	const struct icmp6_hdr *dp;
1570685295f4SBill Fenner 	const u_char *cp;
15715b0fe478SBruce M Simpson 	size_t siz, i;
1572685295f4SBill Fenner 	int needcomma;
1573685295f4SBill Fenner 
15745b0fe478SBruce M Simpson 	if (ep < bp)
15755b0fe478SBruce M Simpson 		return;
1576*3340d773SGleb Smirnoff 	dp = (const struct icmp6_hdr *)bp;
1577*3340d773SGleb Smirnoff 	ni6 = (const struct icmp6_nodeinfo *)bp;
1578685295f4SBill Fenner 	siz = ep - bp;
1579685295f4SBill Fenner 
1580685295f4SBill Fenner 	switch (ni6->ni_type) {
1581685295f4SBill Fenner 	case ICMP6_NI_QUERY:
1582685295f4SBill Fenner 		if (siz == sizeof(*dp) + 4) {
1583685295f4SBill Fenner 			/* KAME who-are-you */
15843c602fabSXin LI 			ND_PRINT((ndo," who-are-you request"));
1585685295f4SBill Fenner 			break;
1586685295f4SBill Fenner 		}
15873c602fabSXin LI 		ND_PRINT((ndo," node information query"));
1588685295f4SBill Fenner 
15893c602fabSXin LI 		ND_TCHECK2(*dp, sizeof(*ni6));
1590*3340d773SGleb Smirnoff 		ni6 = (const struct icmp6_nodeinfo *)dp;
15913c602fabSXin LI 		ND_PRINT((ndo," ("));	/*)*/
15925b0fe478SBruce M Simpson 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1593685295f4SBill Fenner 		case NI_QTYPE_NOOP:
15943c602fabSXin LI 			ND_PRINT((ndo,"noop"));
1595685295f4SBill Fenner 			break;
1596685295f4SBill Fenner 		case NI_QTYPE_SUPTYPES:
15973c602fabSXin LI 			ND_PRINT((ndo,"supported qtypes"));
15985b0fe478SBruce M Simpson 			i = EXTRACT_16BITS(&ni6->ni_flags);
1599685295f4SBill Fenner 			if (i)
16003c602fabSXin LI 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1601685295f4SBill Fenner 			break;
1602685295f4SBill Fenner 		case NI_QTYPE_FQDN:
16033c602fabSXin LI 			ND_PRINT((ndo,"DNS name"));
1604685295f4SBill Fenner 			break;
1605685295f4SBill Fenner 		case NI_QTYPE_NODEADDR:
16063c602fabSXin LI 			ND_PRINT((ndo,"node addresses"));
1607685295f4SBill Fenner 			i = ni6->ni_flags;
1608685295f4SBill Fenner 			if (!i)
1609685295f4SBill Fenner 				break;
1610685295f4SBill Fenner 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
16113c602fabSXin LI 			ND_PRINT((ndo," [%s%s%s%s%s%s]",
1612685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1613685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1614685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1615685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1616685295f4SBill Fenner 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
16173c602fabSXin LI 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""));
1618685295f4SBill Fenner 			break;
1619685295f4SBill Fenner 		default:
16203c602fabSXin LI 			ND_PRINT((ndo,"unknown"));
1621685295f4SBill Fenner 			break;
1622685295f4SBill Fenner 		}
1623685295f4SBill Fenner 
1624685295f4SBill Fenner 		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
1625685295f4SBill Fenner 		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
1626685295f4SBill Fenner 			if (siz != sizeof(*ni6))
16273c602fabSXin LI 				if (ndo->ndo_vflag)
16283c602fabSXin LI 					ND_PRINT((ndo,", invalid len"));
1629685295f4SBill Fenner 			/*(*/
16303c602fabSXin LI 			ND_PRINT((ndo,")"));
1631685295f4SBill Fenner 			break;
1632685295f4SBill Fenner 		}
1633685295f4SBill Fenner 
1634685295f4SBill Fenner 
1635685295f4SBill Fenner 		/* XXX backward compat, icmp-name-lookup-03 */
1636685295f4SBill Fenner 		if (siz == sizeof(*ni6)) {
16373c602fabSXin LI 			ND_PRINT((ndo,", 03 draft"));
1638685295f4SBill Fenner 			/*(*/
16393c602fabSXin LI 			ND_PRINT((ndo,")"));
1640685295f4SBill Fenner 			break;
1641685295f4SBill Fenner 		}
1642685295f4SBill Fenner 
1643685295f4SBill Fenner 		switch (ni6->ni_code) {
1644685295f4SBill Fenner 		case ICMP6_NI_SUBJ_IPV6:
16453c602fabSXin LI 			if (!ND_TTEST2(*dp,
1646685295f4SBill Fenner 			    sizeof(*ni6) + sizeof(struct in6_addr)))
1647685295f4SBill Fenner 				break;
1648685295f4SBill Fenner 			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
16493c602fabSXin LI 				if (ndo->ndo_vflag)
16503c602fabSXin LI 					ND_PRINT((ndo,", invalid subject len"));
1651685295f4SBill Fenner 				break;
1652685295f4SBill Fenner 			}
16533c602fabSXin LI 			ND_PRINT((ndo,", subject=%s",
1654*3340d773SGleb Smirnoff                                   ip6addr_string(ndo, ni6 + 1)));
1655685295f4SBill Fenner 			break;
1656685295f4SBill Fenner 		case ICMP6_NI_SUBJ_FQDN:
16573c602fabSXin LI 			ND_PRINT((ndo,", subject=DNS name"));
1658685295f4SBill Fenner 			cp = (const u_char *)(ni6 + 1);
1659685295f4SBill Fenner 			if (cp[0] == ep - cp - 1) {
1660685295f4SBill Fenner 				/* icmp-name-lookup-03, pascal string */
16613c602fabSXin LI 				if (ndo->ndo_vflag)
16623c602fabSXin LI 					ND_PRINT((ndo,", 03 draft"));
1663685295f4SBill Fenner 				cp++;
16643c602fabSXin LI 				ND_PRINT((ndo,", \""));
1665685295f4SBill Fenner 				while (cp < ep) {
16663c602fabSXin LI 					safeputchar(ndo, *cp);
1667685295f4SBill Fenner 					cp++;
1668685295f4SBill Fenner 				}
16693c602fabSXin LI 				ND_PRINT((ndo,"\""));
1670685295f4SBill Fenner 			} else
16713c602fabSXin LI 				dnsname_print(ndo, cp, ep);
1672685295f4SBill Fenner 			break;
1673685295f4SBill Fenner 		case ICMP6_NI_SUBJ_IPV4:
16743c602fabSXin LI 			if (!ND_TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1675685295f4SBill Fenner 				break;
1676685295f4SBill Fenner 			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
16773c602fabSXin LI 				if (ndo->ndo_vflag)
16783c602fabSXin LI 					ND_PRINT((ndo,", invalid subject len"));
1679685295f4SBill Fenner 				break;
1680685295f4SBill Fenner 			}
16813c602fabSXin LI 			ND_PRINT((ndo,", subject=%s",
1682*3340d773SGleb Smirnoff                                   ipaddr_string(ndo, ni6 + 1)));
1683685295f4SBill Fenner 			break;
1684685295f4SBill Fenner 		default:
16853c602fabSXin LI 			ND_PRINT((ndo,", unknown subject"));
1686685295f4SBill Fenner 			break;
1687685295f4SBill Fenner 		}
1688685295f4SBill Fenner 
1689685295f4SBill Fenner 		/*(*/
16903c602fabSXin LI 		ND_PRINT((ndo,")"));
1691685295f4SBill Fenner 		break;
1692685295f4SBill Fenner 
1693685295f4SBill Fenner 	case ICMP6_NI_REPLY:
1694685295f4SBill Fenner 		if (icmp6len > siz) {
16953c602fabSXin LI 			ND_PRINT((ndo,"[|icmp6: node information reply]"));
1696685295f4SBill Fenner 			break;
1697685295f4SBill Fenner 		}
1698685295f4SBill Fenner 
1699685295f4SBill Fenner 		needcomma = 0;
1700685295f4SBill Fenner 
1701*3340d773SGleb Smirnoff 		ni6 = (const struct icmp6_nodeinfo *)dp;
17023c602fabSXin LI 		ND_PRINT((ndo," node information reply"));
17033c602fabSXin LI 		ND_PRINT((ndo," ("));	/*)*/
1704685295f4SBill Fenner 		switch (ni6->ni_code) {
1705685295f4SBill Fenner 		case ICMP6_NI_SUCCESS:
17063c602fabSXin LI 			if (ndo->ndo_vflag) {
17073c602fabSXin LI 				ND_PRINT((ndo,"success"));
1708685295f4SBill Fenner 				needcomma++;
1709685295f4SBill Fenner 			}
1710685295f4SBill Fenner 			break;
1711685295f4SBill Fenner 		case ICMP6_NI_REFUSED:
17123c602fabSXin LI 			ND_PRINT((ndo,"refused"));
1713685295f4SBill Fenner 			needcomma++;
1714685295f4SBill Fenner 			if (siz != sizeof(*ni6))
17153c602fabSXin LI 				if (ndo->ndo_vflag)
17163c602fabSXin LI 					ND_PRINT((ndo,", invalid length"));
1717685295f4SBill Fenner 			break;
1718685295f4SBill Fenner 		case ICMP6_NI_UNKNOWN:
17193c602fabSXin LI 			ND_PRINT((ndo,"unknown"));
1720685295f4SBill Fenner 			needcomma++;
1721685295f4SBill Fenner 			if (siz != sizeof(*ni6))
17223c602fabSXin LI 				if (ndo->ndo_vflag)
17233c602fabSXin LI 					ND_PRINT((ndo,", invalid length"));
1724685295f4SBill Fenner 			break;
1725685295f4SBill Fenner 		}
1726685295f4SBill Fenner 
1727685295f4SBill Fenner 		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1728685295f4SBill Fenner 			/*(*/
17293c602fabSXin LI 			ND_PRINT((ndo,")"));
1730685295f4SBill Fenner 			break;
1731685295f4SBill Fenner 		}
1732685295f4SBill Fenner 
17335b0fe478SBruce M Simpson 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1734685295f4SBill Fenner 		case NI_QTYPE_NOOP:
1735685295f4SBill Fenner 			if (needcomma)
17363c602fabSXin LI 				ND_PRINT((ndo,", "));
17373c602fabSXin LI 			ND_PRINT((ndo,"noop"));
1738685295f4SBill Fenner 			if (siz != sizeof(*ni6))
17393c602fabSXin LI 				if (ndo->ndo_vflag)
17403c602fabSXin LI 					ND_PRINT((ndo,", invalid length"));
1741685295f4SBill Fenner 			break;
1742685295f4SBill Fenner 		case NI_QTYPE_SUPTYPES:
1743685295f4SBill Fenner 			if (needcomma)
17443c602fabSXin LI 				ND_PRINT((ndo,", "));
17453c602fabSXin LI 			ND_PRINT((ndo,"supported qtypes"));
17465b0fe478SBruce M Simpson 			i = EXTRACT_16BITS(&ni6->ni_flags);
1747685295f4SBill Fenner 			if (i)
17483c602fabSXin LI 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1749685295f4SBill Fenner 			break;
1750685295f4SBill Fenner 		case NI_QTYPE_FQDN:
1751685295f4SBill Fenner 			if (needcomma)
17523c602fabSXin LI 				ND_PRINT((ndo,", "));
17533c602fabSXin LI 			ND_PRINT((ndo,"DNS name"));
1754685295f4SBill Fenner 			cp = (const u_char *)(ni6 + 1) + 4;
1755685295f4SBill Fenner 			if (cp[0] == ep - cp - 1) {
1756685295f4SBill Fenner 				/* icmp-name-lookup-03, pascal string */
17573c602fabSXin LI 				if (ndo->ndo_vflag)
17583c602fabSXin LI 					ND_PRINT((ndo,", 03 draft"));
1759685295f4SBill Fenner 				cp++;
17603c602fabSXin LI 				ND_PRINT((ndo,", \""));
1761685295f4SBill Fenner 				while (cp < ep) {
17623c602fabSXin LI 					safeputchar(ndo, *cp);
1763685295f4SBill Fenner 					cp++;
1764685295f4SBill Fenner 				}
17653c602fabSXin LI 				ND_PRINT((ndo,"\""));
1766685295f4SBill Fenner 			} else
17673c602fabSXin LI 				dnsname_print(ndo, cp, ep);
17685b0fe478SBruce M Simpson 			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1769*3340d773SGleb Smirnoff 				ND_PRINT((ndo," [TTL=%u]", EXTRACT_32BITS(ni6 + 1)));
1770685295f4SBill Fenner 			break;
1771685295f4SBill Fenner 		case NI_QTYPE_NODEADDR:
1772685295f4SBill Fenner 			if (needcomma)
17733c602fabSXin LI 				ND_PRINT((ndo,", "));
17743c602fabSXin LI 			ND_PRINT((ndo,"node addresses"));
1775685295f4SBill Fenner 			i = sizeof(*ni6);
1776685295f4SBill Fenner 			while (i < siz) {
1777685295f4SBill Fenner 				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1778685295f4SBill Fenner 					break;
1779*3340d773SGleb Smirnoff 				ND_PRINT((ndo," %s", ip6addr_string(ndo, bp + i)));
1780685295f4SBill Fenner 				i += sizeof(struct in6_addr);
17813c602fabSXin LI 				ND_PRINT((ndo,"(%d)", (int32_t)EXTRACT_32BITS(bp + i)));
1782685295f4SBill Fenner 				i += sizeof(int32_t);
1783685295f4SBill Fenner 			}
1784685295f4SBill Fenner 			i = ni6->ni_flags;
1785685295f4SBill Fenner 			if (!i)
1786685295f4SBill Fenner 				break;
17873c602fabSXin LI 			ND_PRINT((ndo," [%s%s%s%s%s%s%s]",
1788685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1789685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1790685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1791685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1792685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1793685295f4SBill Fenner                                   (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
17943c602fabSXin LI                                   (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""));
1795685295f4SBill Fenner 			break;
1796685295f4SBill Fenner 		default:
1797685295f4SBill Fenner 			if (needcomma)
17983c602fabSXin LI 				ND_PRINT((ndo,", "));
17993c602fabSXin LI 			ND_PRINT((ndo,"unknown"));
1800685295f4SBill Fenner 			break;
1801685295f4SBill Fenner 		}
1802685295f4SBill Fenner 
1803685295f4SBill Fenner 		/*(*/
18043c602fabSXin LI 		ND_PRINT((ndo,")"));
1805685295f4SBill Fenner 		break;
1806685295f4SBill Fenner 	}
1807685295f4SBill Fenner 	return;
1808685295f4SBill Fenner 
1809685295f4SBill Fenner trunc:
18103c602fabSXin LI 	ND_PRINT((ndo, "[|icmp6]"));
1811685295f4SBill Fenner }
1812685295f4SBill Fenner 
18135b0fe478SBruce M Simpson static void
18143c602fabSXin LI icmp6_rrenum_print(netdissect_options *ndo, const u_char *bp, const u_char *ep)
1815685295f4SBill Fenner {
18163c602fabSXin LI 	const struct icmp6_router_renum *rr6;
1817685295f4SBill Fenner 	const char *cp;
1818*3340d773SGleb Smirnoff 	const struct rr_pco_match *match;
1819*3340d773SGleb Smirnoff 	const struct rr_pco_use *use;
1820685295f4SBill Fenner 	char hbuf[NI_MAXHOST];
1821685295f4SBill Fenner 	int n;
1822685295f4SBill Fenner 
18235b0fe478SBruce M Simpson 	if (ep < bp)
18245b0fe478SBruce M Simpson 		return;
1825*3340d773SGleb Smirnoff 	rr6 = (const struct icmp6_router_renum *)bp;
1826685295f4SBill Fenner 	cp = (const char *)(rr6 + 1);
1827685295f4SBill Fenner 
18283c602fabSXin LI 	ND_TCHECK(rr6->rr_reserved);
1829685295f4SBill Fenner 	switch (rr6->rr_code) {
1830685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
18313c602fabSXin LI 		ND_PRINT((ndo,"router renum: command"));
1832685295f4SBill Fenner 		break;
1833685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_RESULT:
18343c602fabSXin LI 		ND_PRINT((ndo,"router renum: result"));
1835685295f4SBill Fenner 		break;
1836685295f4SBill Fenner 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
18373c602fabSXin LI 		ND_PRINT((ndo,"router renum: sequence number reset"));
1838685295f4SBill Fenner 		break;
1839685295f4SBill Fenner 	default:
18403c602fabSXin LI 		ND_PRINT((ndo,"router renum: code-#%d", rr6->rr_code));
1841685295f4SBill Fenner 		break;
1842685295f4SBill Fenner 	}
1843685295f4SBill Fenner 
18443c602fabSXin LI         ND_PRINT((ndo,", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)));
1845685295f4SBill Fenner 
18463c602fabSXin LI 	if (ndo->ndo_vflag) {
1847685295f4SBill Fenner #define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
18483c602fabSXin LI 		ND_PRINT((ndo,"["));	/*]*/
1849685295f4SBill Fenner 		if (rr6->rr_flags) {
18503c602fabSXin LI 			ND_PRINT((ndo,"%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1851685295f4SBill Fenner                                   F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1852a90e161bSBill Fenner                                   F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1853685295f4SBill Fenner                                   F(ICMP6_RR_FLAGS_SPECSITE, "S"),
18543c602fabSXin LI                                   F(ICMP6_RR_FLAGS_PREVDONE, "P")));
1855685295f4SBill Fenner 		}
18563c602fabSXin LI                 ND_PRINT((ndo,"seg=%u,", rr6->rr_segnum));
18573c602fabSXin LI                 ND_PRINT((ndo,"maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)));
1858685295f4SBill Fenner 		if (rr6->rr_reserved)
18593c602fabSXin LI 			ND_PRINT((ndo,"rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)));
1860685295f4SBill Fenner 		/*[*/
18613c602fabSXin LI 		ND_PRINT((ndo,"]"));
1862685295f4SBill Fenner #undef F
1863685295f4SBill Fenner 	}
1864685295f4SBill Fenner 
1865685295f4SBill Fenner 	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1866*3340d773SGleb Smirnoff 		match = (const struct rr_pco_match *)cp;
1867685295f4SBill Fenner 		cp = (const char *)(match + 1);
1868685295f4SBill Fenner 
18693c602fabSXin LI 		ND_TCHECK(match->rpm_prefix);
1870685295f4SBill Fenner 
18713c602fabSXin LI 		if (ndo->ndo_vflag > 1)
18723c602fabSXin LI 			ND_PRINT((ndo,"\n\t"));
1873685295f4SBill Fenner 		else
18743c602fabSXin LI 			ND_PRINT((ndo," "));
18753c602fabSXin LI 		ND_PRINT((ndo,"match("));	/*)*/
1876685295f4SBill Fenner 		switch (match->rpm_code) {
18773c602fabSXin LI 		case RPM_PCO_ADD:	ND_PRINT((ndo,"add")); break;
18783c602fabSXin LI 		case RPM_PCO_CHANGE:	ND_PRINT((ndo,"change")); break;
18793c602fabSXin LI 		case RPM_PCO_SETGLOBAL:	ND_PRINT((ndo,"setglobal")); break;
18803c602fabSXin LI 		default:		ND_PRINT((ndo,"#%u", match->rpm_code)); break;
1881685295f4SBill Fenner 		}
1882685295f4SBill Fenner 
18833c602fabSXin LI 		if (ndo->ndo_vflag) {
18843c602fabSXin LI 			ND_PRINT((ndo,",ord=%u", match->rpm_ordinal));
18853c602fabSXin LI 			ND_PRINT((ndo,",min=%u", match->rpm_minlen));
18863c602fabSXin LI 			ND_PRINT((ndo,",max=%u", match->rpm_maxlen));
1887685295f4SBill Fenner 		}
1888*3340d773SGleb Smirnoff 		if (addrtostr6(&match->rpm_prefix, hbuf, sizeof(hbuf)))
18893c602fabSXin LI 			ND_PRINT((ndo,",%s/%u", hbuf, match->rpm_matchlen));
1890685295f4SBill Fenner 		else
18913c602fabSXin LI 			ND_PRINT((ndo,",?/%u", match->rpm_matchlen));
1892685295f4SBill Fenner 		/*(*/
18933c602fabSXin LI 		ND_PRINT((ndo,")"));
1894685295f4SBill Fenner 
1895685295f4SBill Fenner 		n = match->rpm_len - 3;
1896685295f4SBill Fenner 		if (n % 4)
1897685295f4SBill Fenner 			goto trunc;
1898685295f4SBill Fenner 		n /= 4;
1899685295f4SBill Fenner 		while (n-- > 0) {
1900*3340d773SGleb Smirnoff 			use = (const struct rr_pco_use *)cp;
1901685295f4SBill Fenner 			cp = (const char *)(use + 1);
1902685295f4SBill Fenner 
19033c602fabSXin LI 			ND_TCHECK(use->rpu_prefix);
1904685295f4SBill Fenner 
19053c602fabSXin LI 			if (ndo->ndo_vflag > 1)
19063c602fabSXin LI 				ND_PRINT((ndo,"\n\t"));
1907685295f4SBill Fenner 			else
19083c602fabSXin LI 				ND_PRINT((ndo," "));
19093c602fabSXin LI 			ND_PRINT((ndo,"use("));	/*)*/
1910685295f4SBill Fenner 			if (use->rpu_flags) {
1911685295f4SBill Fenner #define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
19123c602fabSXin LI 				ND_PRINT((ndo,"%s%s,",
1913685295f4SBill Fenner                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
19143c602fabSXin LI                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")));
1915685295f4SBill Fenner #undef F
1916685295f4SBill Fenner 			}
19173c602fabSXin LI 			if (ndo->ndo_vflag) {
19183c602fabSXin LI 				ND_PRINT((ndo,"mask=0x%x,", use->rpu_ramask));
19193c602fabSXin LI 				ND_PRINT((ndo,"raflags=0x%x,", use->rpu_raflags));
1920685295f4SBill Fenner 				if (~use->rpu_vltime == 0)
19213c602fabSXin LI 					ND_PRINT((ndo,"vltime=infty,"));
1922685295f4SBill Fenner 				else
19233c602fabSXin LI 					ND_PRINT((ndo,"vltime=%u,",
19243c602fabSXin LI                                                   EXTRACT_32BITS(&use->rpu_vltime)));
1925685295f4SBill Fenner 				if (~use->rpu_pltime == 0)
19263c602fabSXin LI 					ND_PRINT((ndo,"pltime=infty,"));
1927685295f4SBill Fenner 				else
19283c602fabSXin LI 					ND_PRINT((ndo,"pltime=%u,",
19293c602fabSXin LI                                                   EXTRACT_32BITS(&use->rpu_pltime)));
1930685295f4SBill Fenner 			}
1931*3340d773SGleb Smirnoff 			if (addrtostr6(&use->rpu_prefix, hbuf, sizeof(hbuf)))
19323c602fabSXin LI 				ND_PRINT((ndo,"%s/%u/%u", hbuf, use->rpu_uselen,
19333c602fabSXin LI                                           use->rpu_keeplen));
1934685295f4SBill Fenner 			else
19353c602fabSXin LI 				ND_PRINT((ndo,"?/%u/%u", use->rpu_uselen,
19363c602fabSXin LI                                           use->rpu_keeplen));
1937685295f4SBill Fenner 			/*(*/
19383c602fabSXin LI                         ND_PRINT((ndo,")"));
1939685295f4SBill Fenner 		}
1940685295f4SBill Fenner 	}
1941b0453382SBill Fenner 
1942b0453382SBill Fenner 	return;
1943685295f4SBill Fenner 
1944685295f4SBill Fenner trunc:
19453c602fabSXin LI 	ND_PRINT((ndo,"[|icmp6]"));
1946b0453382SBill Fenner }
1947685295f4SBill Fenner 
19483c602fabSXin LI /*
19493c602fabSXin LI  * Local Variables:
19503c602fabSXin LI  * c-style: whitesmith
19513c602fabSXin LI  * c-basic-offset: 8
19523c602fabSXin LI  * End:
19533c602fabSXin LI  */
1954