xref: /netbsd/external/bsd/tcpdump/dist/print-icmp6.c (revision c8ac67c2)
1546f56c3Schristos /*
2546f56c3Schristos  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
3546f56c3Schristos  *	The Regents of the University of California.  All rights reserved.
4546f56c3Schristos  *
5546f56c3Schristos  * Redistribution and use in source and binary forms, with or without
6546f56c3Schristos  * modification, are permitted provided that: (1) source code distributions
7546f56c3Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
8546f56c3Schristos  * distributions including binary code include the above copyright notice and
9546f56c3Schristos  * this paragraph in its entirety in the documentation or other materials
10546f56c3Schristos  * provided with the distribution, and (3) all advertising materials mentioning
11546f56c3Schristos  * features or use of this software display the following acknowledgement:
12546f56c3Schristos  * ``This product includes software developed by the University of California,
13546f56c3Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14546f56c3Schristos  * the University nor the names of its contributors may be used to endorse
15546f56c3Schristos  * or promote products derived from this software without specific prior
16546f56c3Schristos  * written permission.
17546f56c3Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18546f56c3Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19546f56c3Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20546f56c3Schristos  */
21546f56c3Schristos 
22c8632dc8Schristos #include <sys/cdefs.h>
23546f56c3Schristos #ifndef lint
24*c8ac67c2Sthorpej __RCSID("$NetBSD: print-icmp6.c,v 1.14 2021/05/30 21:48:42 thorpej Exp $");
25546f56c3Schristos #endif
26546f56c3Schristos 
27c767dfb8Sspz /* \summary: IPv6 Internet Control Message Protocol (ICMPv6) printer */
28c767dfb8Sspz 
29546f56c3Schristos #ifdef HAVE_CONFIG_H
30546f56c3Schristos #include "config.h"
31546f56c3Schristos #endif
32546f56c3Schristos 
33c746cb4fSchristos #include <netdissect-stdinc.h>
34546f56c3Schristos 
35546f56c3Schristos #include <stdio.h>
36546f56c3Schristos #include <string.h>
37546f56c3Schristos 
38c746cb4fSchristos #include "netdissect.h"
39546f56c3Schristos #include "addrtoname.h"
40c746cb4fSchristos #include "addrtostr.h"
41546f56c3Schristos #include "extract.h"
42546f56c3Schristos 
43546f56c3Schristos #include "ip6.h"
44546f56c3Schristos #include "ipproto.h"
45546f56c3Schristos 
46546f56c3Schristos #include "udp.h"
47546f56c3Schristos #include "ah.h"
48546f56c3Schristos 
49193b2145Schristos static const char icmp6_tstr[] = " [|icmp6]";
50193b2145Schristos static const char rpl_tstr[] = " [|rpl]";
51193b2145Schristos static const char mldv2_tstr[] = " [|mldv2]";
52193b2145Schristos 
537e4823a9Schristos /*	NetBSD: icmp6.h,v 1.13 2000/08/03 16:30:37 itojun Exp 	*/
547e4823a9Schristos /*	$KAME: icmp6.h,v 1.22 2000/08/03 15:25:16 jinmei Exp $	*/
557e4823a9Schristos 
567e4823a9Schristos /*
577e4823a9Schristos  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
587e4823a9Schristos  * All rights reserved.
597e4823a9Schristos  *
607e4823a9Schristos  * Redistribution and use in source and binary forms, with or without
617e4823a9Schristos  * modification, are permitted provided that the following conditions
627e4823a9Schristos  * are met:
637e4823a9Schristos  * 1. Redistributions of source code must retain the above copyright
647e4823a9Schristos  *    notice, this list of conditions and the following disclaimer.
657e4823a9Schristos  * 2. Redistributions in binary form must reproduce the above copyright
667e4823a9Schristos  *    notice, this list of conditions and the following disclaimer in the
677e4823a9Schristos  *    documentation and/or other materials provided with the distribution.
687e4823a9Schristos  * 3. Neither the name of the project nor the names of its contributors
697e4823a9Schristos  *    may be used to endorse or promote products derived from this software
707e4823a9Schristos  *    without specific prior written permission.
717e4823a9Schristos  *
727e4823a9Schristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
737e4823a9Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
747e4823a9Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
757e4823a9Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
767e4823a9Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
777e4823a9Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
787e4823a9Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
797e4823a9Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
807e4823a9Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
817e4823a9Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
827e4823a9Schristos  * SUCH DAMAGE.
837e4823a9Schristos  */
847e4823a9Schristos 
857e4823a9Schristos struct icmp6_hdr {
867e4823a9Schristos 	uint8_t		icmp6_type;	/* type field */
877e4823a9Schristos 	uint8_t		icmp6_code;	/* code field */
887e4823a9Schristos 	uint16_t	icmp6_cksum;	/* checksum field */
897e4823a9Schristos 	union {
907e4823a9Schristos 		uint32_t	icmp6_un_data32[1]; /* type-specific field */
917e4823a9Schristos 		uint16_t	icmp6_un_data16[2]; /* type-specific field */
927e4823a9Schristos 		uint8_t		icmp6_un_data8[4];  /* type-specific field */
937e4823a9Schristos 	} icmp6_dataun;
94*c8ac67c2Sthorpej } UNALIGNED;
957e4823a9Schristos 
967e4823a9Schristos #define icmp6_data32	icmp6_dataun.icmp6_un_data32
977e4823a9Schristos #define icmp6_data16	icmp6_dataun.icmp6_un_data16
987e4823a9Schristos #define icmp6_data8	icmp6_dataun.icmp6_un_data8
997e4823a9Schristos #define icmp6_pptr	icmp6_data32[0]		/* parameter prob */
1007e4823a9Schristos #define icmp6_mtu	icmp6_data32[0]		/* packet too big */
1017e4823a9Schristos #define icmp6_id	icmp6_data16[0]		/* echo request/reply */
1027e4823a9Schristos #define icmp6_seq	icmp6_data16[1]		/* echo request/reply */
1037e4823a9Schristos #define icmp6_maxdelay	icmp6_data16[0]		/* mcast group membership */
1047e4823a9Schristos 
1057e4823a9Schristos #define ICMP6_DST_UNREACH		1	/* dest unreachable, codes: */
1067e4823a9Schristos #define ICMP6_PACKET_TOO_BIG		2	/* packet too big */
1077e4823a9Schristos #define ICMP6_TIME_EXCEEDED		3	/* time exceeded, code: */
1087e4823a9Schristos #define ICMP6_PARAM_PROB		4	/* ip6 header bad */
1097e4823a9Schristos 
1107e4823a9Schristos #define ICMP6_ECHO_REQUEST		128	/* echo service */
1117e4823a9Schristos #define ICMP6_ECHO_REPLY		129	/* echo reply */
1127e4823a9Schristos #define ICMP6_MEMBERSHIP_QUERY		130	/* group membership query */
1137e4823a9Schristos #define MLD6_LISTENER_QUERY		130 	/* multicast listener query */
1147e4823a9Schristos #define ICMP6_MEMBERSHIP_REPORT		131	/* group membership report */
1157e4823a9Schristos #define MLD6_LISTENER_REPORT		131	/* multicast listener report */
1167e4823a9Schristos #define ICMP6_MEMBERSHIP_REDUCTION	132	/* group membership termination */
1177e4823a9Schristos #define MLD6_LISTENER_DONE		132	/* multicast listener done */
1187e4823a9Schristos 
1197e4823a9Schristos #define ND_ROUTER_SOLICIT		133	/* router solicitation */
1207e4823a9Schristos #define ND_ROUTER_ADVERT		134	/* router advertisement */
1217e4823a9Schristos #define ND_NEIGHBOR_SOLICIT		135	/* neighbor solicitation */
1227e4823a9Schristos #define ND_NEIGHBOR_ADVERT		136	/* neighbor advertisement */
1237e4823a9Schristos #define ND_REDIRECT			137	/* redirect */
1247e4823a9Schristos 
1257e4823a9Schristos #define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */
1267e4823a9Schristos 
1277e4823a9Schristos #define ICMP6_WRUREQUEST		139	/* who are you request */
1287e4823a9Schristos #define ICMP6_WRUREPLY			140	/* who are you reply */
1297e4823a9Schristos #define ICMP6_FQDN_QUERY		139	/* FQDN query */
1307e4823a9Schristos #define ICMP6_FQDN_REPLY		140	/* FQDN reply */
1317e4823a9Schristos #define ICMP6_NI_QUERY			139	/* node information request */
1327e4823a9Schristos #define ICMP6_NI_REPLY			140	/* node information reply */
1337e4823a9Schristos #define IND_SOLICIT			141	/* inverse neighbor solicitation */
1347e4823a9Schristos #define IND_ADVERT			142	/* inverse neighbor advertisement */
1357e4823a9Schristos 
1367e4823a9Schristos #define ICMP6_V2_MEMBERSHIP_REPORT	143	/* v2 membership report */
1377e4823a9Schristos #define MLDV2_LISTENER_REPORT		143	/* v2 multicast listener report */
1387e4823a9Schristos #define ICMP6_HADISCOV_REQUEST		144
1397e4823a9Schristos #define ICMP6_HADISCOV_REPLY		145
1407e4823a9Schristos #define ICMP6_MOBILEPREFIX_SOLICIT	146
1417e4823a9Schristos #define ICMP6_MOBILEPREFIX_ADVERT	147
1427e4823a9Schristos 
1437e4823a9Schristos #define MLD6_MTRACE_RESP		200	/* mtrace response(to sender) */
1447e4823a9Schristos #define MLD6_MTRACE			201	/* mtrace messages */
1457e4823a9Schristos 
1467e4823a9Schristos #define ICMP6_MAXTYPE			201
1477e4823a9Schristos 
1487e4823a9Schristos #define ICMP6_DST_UNREACH_NOROUTE	0	/* no route to destination */
1497e4823a9Schristos #define ICMP6_DST_UNREACH_ADMIN	 	1	/* administratively prohibited */
1507e4823a9Schristos #define ICMP6_DST_UNREACH_NOTNEIGHBOR	2	/* not a neighbor(obsolete) */
1517e4823a9Schristos #define ICMP6_DST_UNREACH_BEYONDSCOPE	2	/* beyond scope of source address */
1527e4823a9Schristos #define ICMP6_DST_UNREACH_ADDR		3	/* address unreachable */
1537e4823a9Schristos #define ICMP6_DST_UNREACH_NOPORT	4	/* port unreachable */
1547e4823a9Schristos 
1557e4823a9Schristos #define ICMP6_TIME_EXCEED_TRANSIT 	0	/* ttl==0 in transit */
1567e4823a9Schristos #define ICMP6_TIME_EXCEED_REASSEMBLY	1	/* ttl==0 in reass */
1577e4823a9Schristos 
1587e4823a9Schristos #define ICMP6_PARAMPROB_HEADER 	 	0	/* erroneous header field */
1597e4823a9Schristos #define ICMP6_PARAMPROB_NEXTHEADER	1	/* unrecognized next header */
1607e4823a9Schristos #define ICMP6_PARAMPROB_OPTION		2	/* unrecognized option */
1617e4823a9Schristos 
1627e4823a9Schristos #define ICMP6_INFOMSG_MASK		0x80	/* all informational messages */
1637e4823a9Schristos 
1647e4823a9Schristos #define ICMP6_NI_SUBJ_IPV6	0	/* Query Subject is an IPv6 address */
1657e4823a9Schristos #define ICMP6_NI_SUBJ_FQDN	1	/* Query Subject is a Domain name */
1667e4823a9Schristos #define ICMP6_NI_SUBJ_IPV4	2	/* Query Subject is an IPv4 address */
1677e4823a9Schristos 
1687e4823a9Schristos #define ICMP6_NI_SUCCESS	0	/* node information successful reply */
1697e4823a9Schristos #define ICMP6_NI_REFUSED	1	/* node information request is refused */
1707e4823a9Schristos #define ICMP6_NI_UNKNOWN	2	/* unknown Qtype */
1717e4823a9Schristos 
1727e4823a9Schristos #define ICMP6_ROUTER_RENUMBERING_COMMAND  0	/* rr command */
1737e4823a9Schristos #define ICMP6_ROUTER_RENUMBERING_RESULT   1	/* rr result */
1747e4823a9Schristos #define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET   255	/* rr seq num reset */
1757e4823a9Schristos 
1767e4823a9Schristos /* Used in kernel only */
1777e4823a9Schristos #define ND_REDIRECT_ONLINK	0	/* redirect to an on-link node */
1787e4823a9Schristos #define ND_REDIRECT_ROUTER	1	/* redirect to a better router */
1797e4823a9Schristos 
1807e4823a9Schristos /*
1817e4823a9Schristos  * Multicast Listener Discovery
1827e4823a9Schristos  */
1837e4823a9Schristos struct mld6_hdr {
1847e4823a9Schristos 	struct icmp6_hdr	mld6_hdr;
1857e4823a9Schristos 	struct in6_addr		mld6_addr; /* multicast address */
186*c8ac67c2Sthorpej } UNALIGNED;
1877e4823a9Schristos 
1887e4823a9Schristos #define mld6_type	mld6_hdr.icmp6_type
1897e4823a9Schristos #define mld6_code	mld6_hdr.icmp6_code
1907e4823a9Schristos #define mld6_cksum	mld6_hdr.icmp6_cksum
1917e4823a9Schristos #define mld6_maxdelay	mld6_hdr.icmp6_data16[0]
1927e4823a9Schristos #define mld6_reserved	mld6_hdr.icmp6_data16[1]
1937e4823a9Schristos 
1947e4823a9Schristos #define MLD_MINLEN	24
1957e4823a9Schristos #define MLDV2_MINLEN	28
1967e4823a9Schristos 
1977e4823a9Schristos /*
1987e4823a9Schristos  * Neighbor Discovery
1997e4823a9Schristos  */
2007e4823a9Schristos 
2017e4823a9Schristos struct nd_router_solicit {	/* router solicitation */
2027e4823a9Schristos 	struct icmp6_hdr 	nd_rs_hdr;
2037e4823a9Schristos 	/* could be followed by options */
204*c8ac67c2Sthorpej } UNALIGNED;
2057e4823a9Schristos 
2067e4823a9Schristos #define nd_rs_type	nd_rs_hdr.icmp6_type
2077e4823a9Schristos #define nd_rs_code	nd_rs_hdr.icmp6_code
2087e4823a9Schristos #define nd_rs_cksum	nd_rs_hdr.icmp6_cksum
2097e4823a9Schristos #define nd_rs_reserved	nd_rs_hdr.icmp6_data32[0]
2107e4823a9Schristos 
2117e4823a9Schristos struct nd_router_advert {	/* router advertisement */
2127e4823a9Schristos 	struct icmp6_hdr	nd_ra_hdr;
2137e4823a9Schristos 	uint32_t		nd_ra_reachable;	/* reachable time */
2147e4823a9Schristos 	uint32_t		nd_ra_retransmit;	/* retransmit timer */
2157e4823a9Schristos 	/* could be followed by options */
216*c8ac67c2Sthorpej } UNALIGNED;
2177e4823a9Schristos 
2187e4823a9Schristos #define nd_ra_type		nd_ra_hdr.icmp6_type
2197e4823a9Schristos #define nd_ra_code		nd_ra_hdr.icmp6_code
2207e4823a9Schristos #define nd_ra_cksum		nd_ra_hdr.icmp6_cksum
2217e4823a9Schristos #define nd_ra_curhoplimit	nd_ra_hdr.icmp6_data8[0]
2227e4823a9Schristos #define nd_ra_flags_reserved	nd_ra_hdr.icmp6_data8[1]
2237e4823a9Schristos #define ND_RA_FLAG_MANAGED	0x80
2247e4823a9Schristos #define ND_RA_FLAG_OTHER	0x40
2257e4823a9Schristos #define ND_RA_FLAG_HOME_AGENT	0x20
2267e4823a9Schristos 
2277e4823a9Schristos /*
2287e4823a9Schristos  * Router preference values based on draft-draves-ipngwg-router-selection-01.
2297e4823a9Schristos  * These are non-standard definitions.
2307e4823a9Schristos  */
2317e4823a9Schristos #define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
2327e4823a9Schristos 
2337e4823a9Schristos #define ND_RA_FLAG_RTPREF_HIGH	0x08 /* 00001000 */
2347e4823a9Schristos #define ND_RA_FLAG_RTPREF_MEDIUM	0x00 /* 00000000 */
2357e4823a9Schristos #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
2367e4823a9Schristos #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
2377e4823a9Schristos 
2387e4823a9Schristos #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
2397e4823a9Schristos 
2407e4823a9Schristos struct nd_neighbor_solicit {	/* neighbor solicitation */
2417e4823a9Schristos 	struct icmp6_hdr	nd_ns_hdr;
2427e4823a9Schristos 	struct in6_addr		nd_ns_target;	/*target address */
2437e4823a9Schristos 	/* could be followed by options */
244*c8ac67c2Sthorpej } UNALIGNED;
2457e4823a9Schristos 
2467e4823a9Schristos #define nd_ns_type		nd_ns_hdr.icmp6_type
2477e4823a9Schristos #define nd_ns_code		nd_ns_hdr.icmp6_code
2487e4823a9Schristos #define nd_ns_cksum		nd_ns_hdr.icmp6_cksum
2497e4823a9Schristos #define nd_ns_reserved		nd_ns_hdr.icmp6_data32[0]
2507e4823a9Schristos 
2517e4823a9Schristos struct nd_neighbor_advert {	/* neighbor advertisement */
2527e4823a9Schristos 	struct icmp6_hdr	nd_na_hdr;
2537e4823a9Schristos 	struct in6_addr		nd_na_target;	/* target address */
2547e4823a9Schristos 	/* could be followed by options */
255*c8ac67c2Sthorpej } UNALIGNED;
2567e4823a9Schristos 
2577e4823a9Schristos #define nd_na_type		nd_na_hdr.icmp6_type
2587e4823a9Schristos #define nd_na_code		nd_na_hdr.icmp6_code
2597e4823a9Schristos #define nd_na_cksum		nd_na_hdr.icmp6_cksum
2607e4823a9Schristos #define nd_na_flags_reserved	nd_na_hdr.icmp6_data32[0]
2617e4823a9Schristos 
2627e4823a9Schristos #define ND_NA_FLAG_ROUTER		0x80000000
2637e4823a9Schristos #define ND_NA_FLAG_SOLICITED		0x40000000
2647e4823a9Schristos #define ND_NA_FLAG_OVERRIDE		0x20000000
2657e4823a9Schristos 
2667e4823a9Schristos struct nd_redirect {		/* redirect */
2677e4823a9Schristos 	struct icmp6_hdr	nd_rd_hdr;
2687e4823a9Schristos 	struct in6_addr		nd_rd_target;	/* target address */
2697e4823a9Schristos 	struct in6_addr		nd_rd_dst;	/* destination address */
2707e4823a9Schristos 	/* could be followed by options */
271*c8ac67c2Sthorpej } UNALIGNED;
2727e4823a9Schristos 
2737e4823a9Schristos #define nd_rd_type		nd_rd_hdr.icmp6_type
2747e4823a9Schristos #define nd_rd_code		nd_rd_hdr.icmp6_code
2757e4823a9Schristos #define nd_rd_cksum		nd_rd_hdr.icmp6_cksum
2767e4823a9Schristos #define nd_rd_reserved		nd_rd_hdr.icmp6_data32[0]
2777e4823a9Schristos 
2787e4823a9Schristos struct nd_opt_hdr {		/* Neighbor discovery option header */
2797e4823a9Schristos 	uint8_t		nd_opt_type;
2807e4823a9Schristos 	uint8_t		nd_opt_len;
2817e4823a9Schristos 	/* followed by option specific data*/
2827e4823a9Schristos };
2837e4823a9Schristos 
2847e4823a9Schristos #define ND_OPT_SOURCE_LINKADDR		1
2857e4823a9Schristos #define ND_OPT_TARGET_LINKADDR		2
2867e4823a9Schristos #define ND_OPT_PREFIX_INFORMATION	3
2877e4823a9Schristos #define ND_OPT_REDIRECTED_HEADER	4
2887e4823a9Schristos #define ND_OPT_MTU			5
2897e4823a9Schristos #define ND_OPT_ADVINTERVAL		7
2907e4823a9Schristos #define ND_OPT_HOMEAGENT_INFO		8
2917e4823a9Schristos #define ND_OPT_ROUTE_INFO		24	/* RFC4191 */
2927e4823a9Schristos #define ND_OPT_RDNSS			25
2937e4823a9Schristos #define ND_OPT_DNSSL			31
2947e4823a9Schristos 
2957e4823a9Schristos struct nd_opt_prefix_info {	/* prefix information */
296c767dfb8Sspz 	nd_uint8_t		nd_opt_pi_type;
297c767dfb8Sspz 	nd_uint8_t		nd_opt_pi_len;
298c767dfb8Sspz 	nd_uint8_t		nd_opt_pi_prefix_len;
299c767dfb8Sspz 	nd_uint8_t		nd_opt_pi_flags_reserved;
300c767dfb8Sspz 	nd_uint32_t		nd_opt_pi_valid_time;
301c767dfb8Sspz 	nd_uint32_t		nd_opt_pi_preferred_time;
302c767dfb8Sspz 	nd_uint32_t		nd_opt_pi_reserved2;
3037e4823a9Schristos 	struct in6_addr	nd_opt_pi_prefix;
304*c8ac67c2Sthorpej } UNALIGNED;
3057e4823a9Schristos 
3067e4823a9Schristos #define ND_OPT_PI_FLAG_ONLINK		0x80
3077e4823a9Schristos #define ND_OPT_PI_FLAG_AUTO		0x40
3087e4823a9Schristos #define ND_OPT_PI_FLAG_ROUTER		0x20	/*2292bis*/
3097e4823a9Schristos 
3107e4823a9Schristos struct nd_opt_rd_hdr {         /* redirected header */
3117e4823a9Schristos 	uint8_t		nd_opt_rh_type;
3127e4823a9Schristos 	uint8_t		nd_opt_rh_len;
3137e4823a9Schristos 	uint16_t	nd_opt_rh_reserved1;
3147e4823a9Schristos 	uint32_t	nd_opt_rh_reserved2;
3157e4823a9Schristos 	/* followed by IP header and data */
316*c8ac67c2Sthorpej } UNALIGNED;
3177e4823a9Schristos 
3187e4823a9Schristos struct nd_opt_mtu {		/* MTU option */
3197e4823a9Schristos 	uint8_t		nd_opt_mtu_type;
3207e4823a9Schristos 	uint8_t		nd_opt_mtu_len;
3217e4823a9Schristos 	uint16_t	nd_opt_mtu_reserved;
3227e4823a9Schristos 	uint32_t	nd_opt_mtu_mtu;
323*c8ac67c2Sthorpej } UNALIGNED;
3247e4823a9Schristos 
3257e4823a9Schristos struct nd_opt_rdnss {		/* RDNSS RFC 6106 5.1 */
3267e4823a9Schristos 	uint8_t		nd_opt_rdnss_type;
3277e4823a9Schristos 	uint8_t		nd_opt_rdnss_len;
3287e4823a9Schristos 	uint16_t	nd_opt_rdnss_reserved;
3297e4823a9Schristos 	uint32_t	nd_opt_rdnss_lifetime;
3307e4823a9Schristos 	struct in6_addr nd_opt_rdnss_addr[1];	/* variable-length */
331*c8ac67c2Sthorpej } UNALIGNED;
3327e4823a9Schristos 
3337e4823a9Schristos struct nd_opt_dnssl {		/* DNSSL RFC 6106 5.2 */
3347e4823a9Schristos 	uint8_t  nd_opt_dnssl_type;
3357e4823a9Schristos 	uint8_t  nd_opt_dnssl_len;
3367e4823a9Schristos 	uint16_t nd_opt_dnssl_reserved;
3377e4823a9Schristos 	uint32_t nd_opt_dnssl_lifetime;
3387e4823a9Schristos 	/* followed by list of DNS search domains, variable-length */
339*c8ac67c2Sthorpej } UNALIGNED;
3407e4823a9Schristos 
3417e4823a9Schristos struct nd_opt_advinterval {	/* Advertisement interval option */
3427e4823a9Schristos 	uint8_t		nd_opt_adv_type;
3437e4823a9Schristos 	uint8_t		nd_opt_adv_len;
3447e4823a9Schristos 	uint16_t	nd_opt_adv_reserved;
3457e4823a9Schristos 	uint32_t	nd_opt_adv_interval;
346*c8ac67c2Sthorpej } UNALIGNED;
3477e4823a9Schristos 
3487e4823a9Schristos struct nd_opt_homeagent_info {	/* Home Agent info */
3497e4823a9Schristos 	uint8_t		nd_opt_hai_type;
3507e4823a9Schristos 	uint8_t		nd_opt_hai_len;
3517e4823a9Schristos 	uint16_t	nd_opt_hai_reserved;
3527e4823a9Schristos 	int16_t		nd_opt_hai_preference;
3537e4823a9Schristos 	uint16_t	nd_opt_hai_lifetime;
354*c8ac67c2Sthorpej } UNALIGNED;
3557e4823a9Schristos 
3567e4823a9Schristos struct nd_opt_route_info {	/* route info */
3577e4823a9Schristos 	uint8_t		nd_opt_rti_type;
3587e4823a9Schristos 	uint8_t		nd_opt_rti_len;
3597e4823a9Schristos 	uint8_t		nd_opt_rti_prefixlen;
3607e4823a9Schristos 	uint8_t		nd_opt_rti_flags;
3617e4823a9Schristos 	uint32_t	nd_opt_rti_lifetime;
3627e4823a9Schristos 	/* prefix follows */
363*c8ac67c2Sthorpej } UNALIGNED;
3647e4823a9Schristos 
3657e4823a9Schristos /*
3667e4823a9Schristos  * icmp6 namelookup
3677e4823a9Schristos  */
3687e4823a9Schristos 
3697e4823a9Schristos struct icmp6_namelookup {
3707e4823a9Schristos 	struct icmp6_hdr 	icmp6_nl_hdr;
3717e4823a9Schristos 	uint8_t		icmp6_nl_nonce[8];
3727e4823a9Schristos 	int32_t		icmp6_nl_ttl;
3737e4823a9Schristos #if 0
3747e4823a9Schristos 	uint8_t		icmp6_nl_len;
3757e4823a9Schristos 	uint8_t		icmp6_nl_name[3];
3767e4823a9Schristos #endif
3777e4823a9Schristos 	/* could be followed by options */
378*c8ac67c2Sthorpej } UNALIGNED;
3797e4823a9Schristos 
3807e4823a9Schristos /*
3817e4823a9Schristos  * icmp6 node information
3827e4823a9Schristos  */
3837e4823a9Schristos struct icmp6_nodeinfo {
3847e4823a9Schristos 	struct icmp6_hdr icmp6_ni_hdr;
3857e4823a9Schristos 	uint8_t icmp6_ni_nonce[8];
3867e4823a9Schristos 	/* could be followed by reply data */
387*c8ac67c2Sthorpej } UNALIGNED;
3887e4823a9Schristos 
3897e4823a9Schristos #define ni_type		icmp6_ni_hdr.icmp6_type
3907e4823a9Schristos #define ni_code		icmp6_ni_hdr.icmp6_code
3917e4823a9Schristos #define ni_cksum	icmp6_ni_hdr.icmp6_cksum
3927e4823a9Schristos #define ni_qtype	icmp6_ni_hdr.icmp6_data16[0]
3937e4823a9Schristos #define ni_flags	icmp6_ni_hdr.icmp6_data16[1]
3947e4823a9Schristos 
3957e4823a9Schristos #define NI_QTYPE_NOOP		0 /* NOOP  */
3967e4823a9Schristos #define NI_QTYPE_SUPTYPES	1 /* Supported Qtypes */
3977e4823a9Schristos #define NI_QTYPE_FQDN		2 /* FQDN (draft 04) */
3987e4823a9Schristos #define NI_QTYPE_DNSNAME	2 /* DNS Name */
3997e4823a9Schristos #define NI_QTYPE_NODEADDR	3 /* Node Addresses */
4007e4823a9Schristos #define NI_QTYPE_IPV4ADDR	4 /* IPv4 Addresses */
4017e4823a9Schristos 
4027e4823a9Schristos /* network endian */
4037e4823a9Schristos #define NI_SUPTYPE_FLAG_COMPRESS	((uint16_t)htons(0x1))
4047e4823a9Schristos #define NI_FQDN_FLAG_VALIDTTL		((uint16_t)htons(0x1))
4057e4823a9Schristos 
4067e4823a9Schristos /* network endian */
4077e4823a9Schristos #define NI_NODEADDR_FLAG_TRUNCATE	((uint16_t)htons(0x1))
4087e4823a9Schristos #define NI_NODEADDR_FLAG_ALL		((uint16_t)htons(0x2))
4097e4823a9Schristos #define NI_NODEADDR_FLAG_COMPAT		((uint16_t)htons(0x4))
4107e4823a9Schristos #define NI_NODEADDR_FLAG_LINKLOCAL	((uint16_t)htons(0x8))
4117e4823a9Schristos #define NI_NODEADDR_FLAG_SITELOCAL	((uint16_t)htons(0x10))
4127e4823a9Schristos #define NI_NODEADDR_FLAG_GLOBAL		((uint16_t)htons(0x20))
4137e4823a9Schristos #define NI_NODEADDR_FLAG_ANYCAST	((uint16_t)htons(0x40)) /* just experimental. not in spec */
4147e4823a9Schristos 
4157e4823a9Schristos struct ni_reply_fqdn {
4167e4823a9Schristos 	uint32_t ni_fqdn_ttl;	/* TTL */
4177e4823a9Schristos 	uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */
4187e4823a9Schristos 	uint8_t ni_fqdn_name[3]; /* XXX: alignment */
419*c8ac67c2Sthorpej } UNALIGNED;
4207e4823a9Schristos 
4217e4823a9Schristos /*
4227e4823a9Schristos  * Router Renumbering. as router-renum-08.txt
4237e4823a9Schristos  */
4247e4823a9Schristos struct icmp6_router_renum {	/* router renumbering header */
4257e4823a9Schristos 	struct icmp6_hdr	rr_hdr;
4267e4823a9Schristos 	uint8_t		rr_segnum;
4277e4823a9Schristos 	uint8_t		rr_flags;
4287e4823a9Schristos 	uint16_t	rr_maxdelay;
4297e4823a9Schristos 	uint32_t	rr_reserved;
430*c8ac67c2Sthorpej } UNALIGNED;
4317e4823a9Schristos #define ICMP6_RR_FLAGS_TEST		0x80
4327e4823a9Schristos #define ICMP6_RR_FLAGS_REQRESULT	0x40
4337e4823a9Schristos #define ICMP6_RR_FLAGS_FORCEAPPLY	0x20
4347e4823a9Schristos #define ICMP6_RR_FLAGS_SPECSITE		0x10
4357e4823a9Schristos #define ICMP6_RR_FLAGS_PREVDONE		0x08
4367e4823a9Schristos 
4377e4823a9Schristos #define rr_type		rr_hdr.icmp6_type
4387e4823a9Schristos #define rr_code		rr_hdr.icmp6_code
4397e4823a9Schristos #define rr_cksum	rr_hdr.icmp6_cksum
4407e4823a9Schristos #define rr_seqnum 	rr_hdr.icmp6_data32[0]
4417e4823a9Schristos 
4427e4823a9Schristos struct rr_pco_match {		/* match prefix part */
4437e4823a9Schristos 	uint8_t		rpm_code;
4447e4823a9Schristos 	uint8_t		rpm_len;
4457e4823a9Schristos 	uint8_t		rpm_ordinal;
4467e4823a9Schristos 	uint8_t		rpm_matchlen;
4477e4823a9Schristos 	uint8_t		rpm_minlen;
4487e4823a9Schristos 	uint8_t		rpm_maxlen;
4497e4823a9Schristos 	uint16_t	rpm_reserved;
4507e4823a9Schristos 	struct	in6_addr	rpm_prefix;
451*c8ac67c2Sthorpej } UNALIGNED;
4527e4823a9Schristos 
4537e4823a9Schristos #define RPM_PCO_ADD		1
4547e4823a9Schristos #define RPM_PCO_CHANGE		2
4557e4823a9Schristos #define RPM_PCO_SETGLOBAL	3
4567e4823a9Schristos #define RPM_PCO_MAX		4
4577e4823a9Schristos 
4587e4823a9Schristos struct rr_pco_use {		/* use prefix part */
4597e4823a9Schristos 	uint8_t		rpu_uselen;
4607e4823a9Schristos 	uint8_t		rpu_keeplen;
4617e4823a9Schristos 	uint8_t		rpu_ramask;
4627e4823a9Schristos 	uint8_t		rpu_raflags;
4637e4823a9Schristos 	uint32_t	rpu_vltime;
4647e4823a9Schristos 	uint32_t	rpu_pltime;
4657e4823a9Schristos 	uint32_t	rpu_flags;
4667e4823a9Schristos 	struct	in6_addr rpu_prefix;
467*c8ac67c2Sthorpej } UNALIGNED;
4687e4823a9Schristos #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK	0x80
4697e4823a9Schristos #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO	0x40
4707e4823a9Schristos 
4717e4823a9Schristos /* network endian */
4727e4823a9Schristos #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME     ((uint32_t)htonl(0x80000000))
4737e4823a9Schristos #define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME     ((uint32_t)htonl(0x40000000))
4747e4823a9Schristos 
4757e4823a9Schristos struct rr_result {		/* router renumbering result message */
4767e4823a9Schristos 	uint16_t	rrr_flags;
4777e4823a9Schristos 	uint8_t		rrr_ordinal;
4787e4823a9Schristos 	uint8_t		rrr_matchedlen;
4797e4823a9Schristos 	uint32_t	rrr_ifid;
4807e4823a9Schristos 	struct	in6_addr rrr_prefix;
481*c8ac67c2Sthorpej } UNALIGNED;
4827e4823a9Schristos /* network endian */
4837e4823a9Schristos #define ICMP6_RR_RESULT_FLAGS_OOB		((uint16_t)htons(0x0002))
4847e4823a9Schristos #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN		((uint16_t)htons(0x0001))
4857e4823a9Schristos 
486546f56c3Schristos static const char *get_rtpref(u_int);
4877e4823a9Schristos static const char *get_lifetime(uint32_t);
4887e4823a9Schristos static void print_lladdr(netdissect_options *ndo, const u_char *, size_t);
4897e4823a9Schristos static void icmp6_opt_print(netdissect_options *ndo, const u_char *, int);
4907e4823a9Schristos static void mld6_print(netdissect_options *ndo, const u_char *);
4917e4823a9Schristos static void mldv2_report_print(netdissect_options *ndo, const u_char *, u_int);
4927e4823a9Schristos static void mldv2_query_print(netdissect_options *ndo, const u_char *, u_int);
4937e4823a9Schristos static const struct udphdr *get_upperlayer(netdissect_options *ndo, const u_char *, u_int *);
4947e4823a9Schristos static void dnsname_print(netdissect_options *ndo, const u_char *, const u_char *);
4957e4823a9Schristos static void icmp6_nodeinfo_print(netdissect_options *ndo, u_int, const u_char *, const u_char *);
4967e4823a9Schristos static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_char *);
497546f56c3Schristos 
498546f56c3Schristos #ifndef abs
499546f56c3Schristos #define abs(a)	((0 < (a)) ? (a) : -(a))
500546f56c3Schristos #endif
501546f56c3Schristos 
5027e4823a9Schristos #include "rpl.h"
503546f56c3Schristos 
504aecd9f07Schristos static const struct tok icmp6_type_values[] = {
505546f56c3Schristos     { ICMP6_DST_UNREACH, "destination unreachable"},
506546f56c3Schristos     { ICMP6_PACKET_TOO_BIG, "packet too big"},
507546f56c3Schristos     { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
508546f56c3Schristos     { ICMP6_PARAM_PROB, "parameter problem"},
509546f56c3Schristos     { ICMP6_ECHO_REQUEST, "echo request"},
510546f56c3Schristos     { ICMP6_ECHO_REPLY, "echo reply"},
511546f56c3Schristos     { MLD6_LISTENER_QUERY, "multicast listener query"},
512546f56c3Schristos     { MLD6_LISTENER_REPORT, "multicast listener report"},
513546f56c3Schristos     { MLD6_LISTENER_DONE, "multicast listener done"},
514546f56c3Schristos     { ND_ROUTER_SOLICIT, "router solicitation"},
515546f56c3Schristos     { ND_ROUTER_ADVERT, "router advertisement"},
516546f56c3Schristos     { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
517546f56c3Schristos     { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
518546f56c3Schristos     { ND_REDIRECT, "redirect"},
519546f56c3Schristos     { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
520546f56c3Schristos     { IND_SOLICIT, "inverse neighbor solicitation"},
521546f56c3Schristos     { IND_ADVERT, "inverse neighbor advertisement"},
522546f56c3Schristos     { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
523546f56c3Schristos     { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
524546f56c3Schristos     { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
525546f56c3Schristos     { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
526546f56c3Schristos     { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
527546f56c3Schristos     { ICMP6_WRUREQUEST, "who-are-you request"},
528546f56c3Schristos     { ICMP6_WRUREPLY, "who-are-you reply"},
529546f56c3Schristos     { ICMP6_NI_QUERY, "node information query"},
530546f56c3Schristos     { ICMP6_NI_REPLY, "node information reply"},
531546f56c3Schristos     { MLD6_MTRACE, "mtrace message"},
532546f56c3Schristos     { MLD6_MTRACE_RESP, "mtrace response"},
533546f56c3Schristos     { ND_RPL_MESSAGE,   "RPL"},
534546f56c3Schristos     { 0,	NULL }
535546f56c3Schristos };
536546f56c3Schristos 
537aecd9f07Schristos static const struct tok icmp6_dst_unreach_code_values[] = {
538546f56c3Schristos     { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
539546f56c3Schristos     { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
540546f56c3Schristos     { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
541546f56c3Schristos     { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
542546f56c3Schristos     { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
543546f56c3Schristos     { 0,	NULL }
544546f56c3Schristos };
545546f56c3Schristos 
546aecd9f07Schristos static const struct tok icmp6_opt_pi_flag_values[] = {
547546f56c3Schristos     { ND_OPT_PI_FLAG_ONLINK, "onlink" },
548546f56c3Schristos     { ND_OPT_PI_FLAG_AUTO, "auto" },
549546f56c3Schristos     { ND_OPT_PI_FLAG_ROUTER, "router" },
550546f56c3Schristos     { 0,	NULL }
551546f56c3Schristos };
552546f56c3Schristos 
553aecd9f07Schristos static const struct tok icmp6_opt_ra_flag_values[] = {
554546f56c3Schristos     { ND_RA_FLAG_MANAGED, "managed" },
555546f56c3Schristos     { ND_RA_FLAG_OTHER, "other stateful"},
556546f56c3Schristos     { ND_RA_FLAG_HOME_AGENT, "home agent"},
557546f56c3Schristos     { 0,	NULL }
558546f56c3Schristos };
559546f56c3Schristos 
560aecd9f07Schristos static const struct tok icmp6_nd_na_flag_values[] = {
561546f56c3Schristos     { ND_NA_FLAG_ROUTER, "router" },
562546f56c3Schristos     { ND_NA_FLAG_SOLICITED, "solicited" },
563546f56c3Schristos     { ND_NA_FLAG_OVERRIDE, "override" },
564546f56c3Schristos     { 0,	NULL }
565546f56c3Schristos };
566546f56c3Schristos 
567546f56c3Schristos 
568aecd9f07Schristos static const struct tok icmp6_opt_values[] = {
569546f56c3Schristos    { ND_OPT_SOURCE_LINKADDR, "source link-address"},
570546f56c3Schristos    { ND_OPT_TARGET_LINKADDR, "destination link-address"},
571546f56c3Schristos    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
572546f56c3Schristos    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
573546f56c3Schristos    { ND_OPT_MTU, "mtu"},
574546f56c3Schristos    { ND_OPT_RDNSS, "rdnss"},
575aecd9f07Schristos    { ND_OPT_DNSSL, "dnssl"},
576546f56c3Schristos    { ND_OPT_ADVINTERVAL, "advertisement interval"},
577546f56c3Schristos    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
578546f56c3Schristos    { ND_OPT_ROUTE_INFO, "route info"},
579546f56c3Schristos    { 0,	NULL }
580546f56c3Schristos };
581546f56c3Schristos 
582546f56c3Schristos /* mldv2 report types */
583aecd9f07Schristos static const struct tok mldv2report2str[] = {
584546f56c3Schristos 	{ 1,	"is_in" },
585546f56c3Schristos 	{ 2,	"is_ex" },
586546f56c3Schristos 	{ 3,	"to_in" },
587546f56c3Schristos 	{ 4,	"to_ex" },
588546f56c3Schristos 	{ 5,	"allow" },
589546f56c3Schristos 	{ 6,	"block" },
590546f56c3Schristos 	{ 0,	NULL }
591546f56c3Schristos };
592546f56c3Schristos 
593546f56c3Schristos static const char *
get_rtpref(u_int v)594546f56c3Schristos get_rtpref(u_int v)
595546f56c3Schristos {
596546f56c3Schristos 	static const char *rtpref_str[] = {
597546f56c3Schristos 		"medium",		/* 00 */
598546f56c3Schristos 		"high",			/* 01 */
599546f56c3Schristos 		"rsv",			/* 10 */
600546f56c3Schristos 		"low"			/* 11 */
601546f56c3Schristos 	};
602546f56c3Schristos 
603546f56c3Schristos 	return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
604546f56c3Schristos }
605546f56c3Schristos 
606546f56c3Schristos static const char *
get_lifetime(uint32_t v)6077e4823a9Schristos get_lifetime(uint32_t v)
608546f56c3Schristos {
609546f56c3Schristos 	static char buf[20];
610546f56c3Schristos 
6117e4823a9Schristos 	if (v == (uint32_t)~0UL)
612546f56c3Schristos 		return "infinity";
613546f56c3Schristos 	else {
614aecd9f07Schristos 		snprintf(buf, sizeof(buf), "%us", v);
615546f56c3Schristos 		return buf;
616546f56c3Schristos 	}
617546f56c3Schristos }
618546f56c3Schristos 
619546f56c3Schristos static void
print_lladdr(netdissect_options * ndo,const uint8_t * p,size_t l)6207e4823a9Schristos print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l)
621546f56c3Schristos {
6227e4823a9Schristos 	const uint8_t *ep, *q;
623546f56c3Schristos 
624546f56c3Schristos 	q = p;
625546f56c3Schristos 	ep = p + l;
626546f56c3Schristos 	while (l > 0 && q < ep) {
627546f56c3Schristos 		if (q > p)
6287e4823a9Schristos                         ND_PRINT((ndo,":"));
6297e4823a9Schristos 		ND_PRINT((ndo,"%02x", *q++));
630546f56c3Schristos 		l--;
631546f56c3Schristos 	}
632546f56c3Schristos }
633546f56c3Schristos 
icmp6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const struct icmp6_hdr * icp,u_int len)634c746cb4fSchristos static int icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
635c746cb4fSchristos 	const struct icmp6_hdr *icp, u_int len)
636546f56c3Schristos {
637c746cb4fSchristos 	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len,
6387e4823a9Schristos 				IPPROTO_ICMPV6);
639546f56c3Schristos }
640546f56c3Schristos 
641c767dfb8Sspz static const struct tok rpl_mop_values[] = {
6427e4823a9Schristos         { RPL_DIO_NONSTORING,         "nonstoring"},
6437e4823a9Schristos         { RPL_DIO_STORING,            "storing"},
6447e4823a9Schristos         { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"},
6457e4823a9Schristos         { RPL_DIO_STORING_MULTICAST,  "storing-multicast"},
6467e4823a9Schristos         { 0, NULL},
647546f56c3Schristos };
648546f56c3Schristos 
649c767dfb8Sspz static const struct tok rpl_subopt_values[] = {
6507e4823a9Schristos         { RPL_OPT_PAD0, "pad0"},
6517e4823a9Schristos         { RPL_OPT_PADN, "padN"},
6527e4823a9Schristos         { RPL_DIO_METRICS, "metrics"},
6537e4823a9Schristos         { RPL_DIO_ROUTINGINFO, "routinginfo"},
6547e4823a9Schristos         { RPL_DIO_CONFIG,    "config"},
6557e4823a9Schristos         { RPL_DAO_RPLTARGET, "rpltarget"},
6567e4823a9Schristos         { RPL_DAO_TRANSITINFO, "transitinfo"},
6577e4823a9Schristos         { RPL_DIO_DESTPREFIX, "destprefix"},
6587e4823a9Schristos         { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"},
6597e4823a9Schristos         { 0, NULL},
660546f56c3Schristos };
661546f56c3Schristos 
6627e4823a9Schristos static void
rpl_dio_printopt(netdissect_options * ndo,const struct rpl_dio_genoption * opt,u_int length)6637e4823a9Schristos rpl_dio_printopt(netdissect_options *ndo,
6647e4823a9Schristos                  const struct rpl_dio_genoption *opt,
6657e4823a9Schristos                  u_int length)
6667e4823a9Schristos {
6677e4823a9Schristos         if(length < RPL_DIO_GENOPTION_LEN) return;
6687e4823a9Schristos         length -= RPL_DIO_GENOPTION_LEN;
6697e4823a9Schristos 
6707e4823a9Schristos         ND_TCHECK(opt->rpl_dio_len);
6717e4823a9Schristos 
6727e4823a9Schristos         while((opt->rpl_dio_type == RPL_OPT_PAD0 &&
673c746cb4fSchristos                (const u_char *)opt < ndo->ndo_snapend) ||
6747e4823a9Schristos               ND_TTEST2(*opt,(opt->rpl_dio_len+2))) {
6757e4823a9Schristos 
6767e4823a9Schristos                 unsigned int optlen = opt->rpl_dio_len+2;
6777e4823a9Schristos                 if(opt->rpl_dio_type == RPL_OPT_PAD0) {
6787e4823a9Schristos                         optlen = 1;
6797e4823a9Schristos                         ND_PRINT((ndo, " opt:pad0"));
6807e4823a9Schristos                 } else {
6817e4823a9Schristos                         ND_PRINT((ndo, " opt:%s len:%u ",
682c746cb4fSchristos                                   tok2str(rpl_subopt_values, "subopt:%u", opt->rpl_dio_type),
6837e4823a9Schristos                                   optlen));
6847e4823a9Schristos                         if(ndo->ndo_vflag > 2) {
6857e4823a9Schristos                                 unsigned int paylen = opt->rpl_dio_len;
6867e4823a9Schristos                                 if(paylen > length) paylen = length;
6877e4823a9Schristos                                 hex_print(ndo,
6887e4823a9Schristos                                           " ",
689c746cb4fSchristos                                           ((const uint8_t *)opt) + RPL_DIO_GENOPTION_LEN,  /* content of DIO option */
6907e4823a9Schristos                                           paylen);
6917e4823a9Schristos                         }
6927e4823a9Schristos                 }
693c746cb4fSchristos                 opt = (const struct rpl_dio_genoption *)(((const char *)opt) + optlen);
6947e4823a9Schristos                 length -= optlen;
695193b2145Schristos                 ND_TCHECK(opt->rpl_dio_len);
6967e4823a9Schristos         }
6977e4823a9Schristos         return;
6987e4823a9Schristos trunc:
699193b2145Schristos 	ND_PRINT((ndo, "%s", rpl_tstr));
7007e4823a9Schristos 	return;
7017e4823a9Schristos }
7027e4823a9Schristos 
7037e4823a9Schristos static void
rpl_dio_print(netdissect_options * ndo,const u_char * bp,u_int length)7047e4823a9Schristos rpl_dio_print(netdissect_options *ndo,
7057e4823a9Schristos               const u_char *bp, u_int length)
7067e4823a9Schristos {
707c746cb4fSchristos         const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp;
708c746cb4fSchristos         const char *dagid_str;
7097e4823a9Schristos 
7107e4823a9Schristos         ND_TCHECK(*dio);
711c746cb4fSchristos         dagid_str = ip6addr_string (ndo, dio->rpl_dagid);
7127e4823a9Schristos 
7137e4823a9Schristos         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]",
7147e4823a9Schristos                   dagid_str,
7157e4823a9Schristos                   dio->rpl_dtsn,
7167e4823a9Schristos                   dio->rpl_instanceid,
7177e4823a9Schristos                   EXTRACT_16BITS(&dio->rpl_dagrank),
7187e4823a9Schristos                   RPL_DIO_GROUNDED(dio->rpl_mopprf) ? "grounded,":"",
7197e4823a9Schristos                   tok2str(rpl_mop_values, "mop%u", RPL_DIO_MOP(dio->rpl_mopprf)),
7207e4823a9Schristos                   RPL_DIO_PRF(dio->rpl_mopprf)));
7217e4823a9Schristos 
7227e4823a9Schristos         if(ndo->ndo_vflag > 1) {
723c746cb4fSchristos                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)&dio[1];
7247e4823a9Schristos                 rpl_dio_printopt(ndo, opt, length);
7257e4823a9Schristos         }
7267e4823a9Schristos 	return;
7277e4823a9Schristos trunc:
728193b2145Schristos 	ND_PRINT((ndo, "%s", rpl_tstr));
7297e4823a9Schristos 	return;
7307e4823a9Schristos }
7317e4823a9Schristos 
7327e4823a9Schristos static void
rpl_dao_print(netdissect_options * ndo,const u_char * bp,u_int length)7337e4823a9Schristos rpl_dao_print(netdissect_options *ndo,
7347e4823a9Schristos               const u_char *bp, u_int length)
7357e4823a9Schristos {
736c746cb4fSchristos         const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp;
737c746cb4fSchristos         const char *dagid_str = "<elided>";
7387e4823a9Schristos 
7397e4823a9Schristos         ND_TCHECK(*dao);
7407e4823a9Schristos         if (length < ND_RPL_DAO_MIN_LEN)
7417e4823a9Schristos         	goto tooshort;
7427e4823a9Schristos 
7437e4823a9Schristos         bp += ND_RPL_DAO_MIN_LEN;
7447e4823a9Schristos         length -= ND_RPL_DAO_MIN_LEN;
7457e4823a9Schristos         if(RPL_DAO_D(dao->rpl_flags)) {
7467e4823a9Schristos                 ND_TCHECK2(dao->rpl_dagid, DAGID_LEN);
7477e4823a9Schristos                 if (length < DAGID_LEN)
7487e4823a9Schristos                 	goto tooshort;
749c746cb4fSchristos                 dagid_str = ip6addr_string (ndo, dao->rpl_dagid);
7507e4823a9Schristos                 bp += DAGID_LEN;
7517e4823a9Schristos                 length -= DAGID_LEN;
7527e4823a9Schristos         }
7537e4823a9Schristos 
7547e4823a9Schristos         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u%s%s,%02x]",
7557e4823a9Schristos                   dagid_str,
7567e4823a9Schristos                   dao->rpl_daoseq,
7577e4823a9Schristos                   dao->rpl_instanceid,
7587e4823a9Schristos                   RPL_DAO_K(dao->rpl_flags) ? ",acK":"",
7597e4823a9Schristos                   RPL_DAO_D(dao->rpl_flags) ? ",Dagid":"",
7607e4823a9Schristos                   dao->rpl_flags));
7617e4823a9Schristos 
7627e4823a9Schristos         if(ndo->ndo_vflag > 1) {
763c746cb4fSchristos                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
7647e4823a9Schristos                 rpl_dio_printopt(ndo, opt, length);
7657e4823a9Schristos         }
7667e4823a9Schristos 	return;
7677e4823a9Schristos 
7687e4823a9Schristos trunc:
769193b2145Schristos 	ND_PRINT((ndo, "%s", rpl_tstr));
7707e4823a9Schristos 	return;
7717e4823a9Schristos 
7727e4823a9Schristos tooshort:
7737e4823a9Schristos 	ND_PRINT((ndo," [|length too short]"));
7747e4823a9Schristos 	return;
7757e4823a9Schristos }
7767e4823a9Schristos 
7777e4823a9Schristos static void
rpl_daoack_print(netdissect_options * ndo,const u_char * bp,u_int length)7787e4823a9Schristos rpl_daoack_print(netdissect_options *ndo,
7797e4823a9Schristos                  const u_char *bp, u_int length)
7807e4823a9Schristos {
781c746cb4fSchristos         const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp;
782c746cb4fSchristos         const char *dagid_str = "<elided>";
7837e4823a9Schristos 
7847e4823a9Schristos         ND_TCHECK2(*daoack, ND_RPL_DAOACK_MIN_LEN);
7857e4823a9Schristos         if (length < ND_RPL_DAOACK_MIN_LEN)
7867e4823a9Schristos         	goto tooshort;
7877e4823a9Schristos 
7887e4823a9Schristos         bp += ND_RPL_DAOACK_MIN_LEN;
7897e4823a9Schristos         length -= ND_RPL_DAOACK_MIN_LEN;
7907e4823a9Schristos         if(RPL_DAOACK_D(daoack->rpl_flags)) {
791c746cb4fSchristos                 ND_TCHECK2(daoack->rpl_dagid, DAGID_LEN);
7927e4823a9Schristos                 if (length < DAGID_LEN)
7937e4823a9Schristos                 	goto tooshort;
794c746cb4fSchristos                 dagid_str = ip6addr_string (ndo, daoack->rpl_dagid);
7957e4823a9Schristos                 bp += DAGID_LEN;
7967e4823a9Schristos                 length -= DAGID_LEN;
7977e4823a9Schristos         }
7987e4823a9Schristos 
7997e4823a9Schristos         ND_PRINT((ndo, " [dagid:%s,seq:%u,instance:%u,status:%u]",
8007e4823a9Schristos                   dagid_str,
8017e4823a9Schristos                   daoack->rpl_daoseq,
8027e4823a9Schristos                   daoack->rpl_instanceid,
8037e4823a9Schristos                   daoack->rpl_status));
8047e4823a9Schristos 
8057e4823a9Schristos         /* no officially defined options for DAOACK, but print any we find */
8067e4823a9Schristos         if(ndo->ndo_vflag > 1) {
807c746cb4fSchristos                 const struct rpl_dio_genoption *opt = (const struct rpl_dio_genoption *)bp;
8087e4823a9Schristos                 rpl_dio_printopt(ndo, opt, length);
8097e4823a9Schristos         }
8107e4823a9Schristos 	return;
8117e4823a9Schristos 
8127e4823a9Schristos trunc:
813193b2145Schristos 	ND_PRINT((ndo, "%s", rpl_tstr));
8147e4823a9Schristos 	return;
8157e4823a9Schristos 
8167e4823a9Schristos tooshort:
8177e4823a9Schristos 	ND_PRINT((ndo," [|dao-length too short]"));
8187e4823a9Schristos 	return;
8197e4823a9Schristos }
820546f56c3Schristos 
821141b0ad2Skamil UNALIGNED_OK
822546f56c3Schristos static void
rpl_print(netdissect_options * ndo,const struct icmp6_hdr * hdr,const u_char * bp,u_int length)823546f56c3Schristos rpl_print(netdissect_options *ndo,
824546f56c3Schristos           const struct icmp6_hdr *hdr,
8257e4823a9Schristos           const u_char *bp, u_int length)
826546f56c3Schristos {
8277becbaa8Schristos         int secured = hdr->icmp6_code & 0x80;
8287becbaa8Schristos         int basecode= hdr->icmp6_code & 0x7f;
829546f56c3Schristos 
8307becbaa8Schristos         if(secured) {
8317e4823a9Schristos                 ND_PRINT((ndo, ", (SEC) [worktodo]"));
8327e4823a9Schristos                 /* XXX
8337e4823a9Schristos                  * the next header pointer needs to move forward to
8347e4823a9Schristos                  * skip the secure part.
8357e4823a9Schristos                  */
8367e4823a9Schristos                 return;
8377becbaa8Schristos         } else {
8387becbaa8Schristos                 ND_PRINT((ndo, ", (CLR)"));
8397becbaa8Schristos         }
8407becbaa8Schristos 
8417becbaa8Schristos         switch(basecode) {
8427e4823a9Schristos         case ND_RPL_DAG_IS:
8437becbaa8Schristos                 ND_PRINT((ndo, "DODAG Information Solicitation"));
844546f56c3Schristos                 if(ndo->ndo_vflag) {
845546f56c3Schristos                 }
846546f56c3Schristos                 break;
8477e4823a9Schristos         case ND_RPL_DAG_IO:
8487becbaa8Schristos                 ND_PRINT((ndo, "DODAG Information Object"));
849546f56c3Schristos                 if(ndo->ndo_vflag) {
8507e4823a9Schristos                         rpl_dio_print(ndo, bp, length);
851546f56c3Schristos                 }
852546f56c3Schristos                 break;
853546f56c3Schristos         case ND_RPL_DAO:
8547becbaa8Schristos                 ND_PRINT((ndo, "Destination Advertisement Object"));
8557becbaa8Schristos                 if(ndo->ndo_vflag) {
8567e4823a9Schristos                         rpl_dao_print(ndo, bp, length);
8577becbaa8Schristos                 }
8587becbaa8Schristos                 break;
8597becbaa8Schristos         case ND_RPL_DAO_ACK:
8607becbaa8Schristos                 ND_PRINT((ndo, "Destination Advertisement Object Ack"));
861546f56c3Schristos                 if(ndo->ndo_vflag) {
8627e4823a9Schristos                         rpl_daoack_print(ndo, bp, length);
863546f56c3Schristos                 }
864546f56c3Schristos                 break;
865546f56c3Schristos         default:
8667becbaa8Schristos                 ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code));
867546f56c3Schristos                 break;
868546f56c3Schristos         }
869546f56c3Schristos 	return;
8707e4823a9Schristos 
8717e4823a9Schristos #if 0
872546f56c3Schristos trunc:
873193b2145Schristos 	ND_PRINT((ndo, "%s", rpl_tstr));
874546f56c3Schristos 	return;
8757e4823a9Schristos #endif
876546f56c3Schristos 
877546f56c3Schristos }
878546f56c3Schristos 
879546f56c3Schristos 
880141b0ad2Skamil UNALIGNED_OK
881546f56c3Schristos void
icmp6_print(netdissect_options * ndo,const u_char * bp,u_int length,const u_char * bp2,int fragmented)882546f56c3Schristos icmp6_print(netdissect_options *ndo,
883546f56c3Schristos             const u_char *bp, u_int length, const u_char *bp2, int fragmented)
884546f56c3Schristos {
885546f56c3Schristos 	const struct icmp6_hdr *dp;
886546f56c3Schristos 	const struct ip6_hdr *ip;
887546f56c3Schristos 	const struct ip6_hdr *oip;
888546f56c3Schristos 	const struct udphdr *ouh;
889546f56c3Schristos 	int dport;
890546f56c3Schristos 	const u_char *ep;
891546f56c3Schristos 	u_int prot;
892546f56c3Schristos 
893c746cb4fSchristos 	dp = (const struct icmp6_hdr *)bp;
894c746cb4fSchristos 	ip = (const struct ip6_hdr *)bp2;
895c746cb4fSchristos 	oip = (const struct ip6_hdr *)(dp + 1);
896546f56c3Schristos 	/* 'ep' points to the end of available data. */
8977e4823a9Schristos 	ep = ndo->ndo_snapend;
898546f56c3Schristos 
8997e4823a9Schristos 	ND_TCHECK(dp->icmp6_cksum);
900546f56c3Schristos 
9017e4823a9Schristos 	if (ndo->ndo_vflag && !fragmented) {
9027e4823a9Schristos 		uint16_t sum, udp_sum;
903546f56c3Schristos 
9047e4823a9Schristos 		if (ND_TTEST2(bp[0], length)) {
9057becbaa8Schristos 			udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
906c746cb4fSchristos 			sum = icmp6_cksum(ndo, ip, dp, length);
907546f56c3Schristos 			if (sum != 0)
9087e4823a9Schristos 				ND_PRINT((ndo,"[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
9097becbaa8Schristos                                                 udp_sum,
9107e4823a9Schristos                                                 in_cksum_shouldbe(udp_sum, sum)));
911546f56c3Schristos 			else
9127e4823a9Schristos 				ND_PRINT((ndo,"[icmp6 sum ok] "));
913546f56c3Schristos 		}
914546f56c3Schristos 	}
915546f56c3Schristos 
9167e4823a9Schristos         ND_PRINT((ndo,"ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)));
917546f56c3Schristos 
918546f56c3Schristos         /* display cosmetics: print the packet length for printer that use the vflag now */
9197e4823a9Schristos         if (ndo->ndo_vflag)
920341013d2Schristos 		switch (dp->icmp6_type)  {
921341013d2Schristos 		case ND_ROUTER_SOLICIT:
922341013d2Schristos                 case ND_ROUTER_ADVERT:
923341013d2Schristos                 case ND_NEIGHBOR_ADVERT:
924341013d2Schristos                 case ND_NEIGHBOR_SOLICIT:
925341013d2Schristos                 case ND_REDIRECT:
926341013d2Schristos                 case ICMP6_HADISCOV_REPLY:
927341013d2Schristos                 case ICMP6_MOBILEPREFIX_ADVERT:
9287e4823a9Schristos 			ND_PRINT((ndo, ", length %u", length));
929341013d2Schristos 			break;
930341013d2Schristos 		default:
931341013d2Schristos 			break;
932341013d2Schristos 		}
933546f56c3Schristos 
934546f56c3Schristos 	switch (dp->icmp6_type) {
935546f56c3Schristos 	case ICMP6_DST_UNREACH:
9367e4823a9Schristos 		ND_TCHECK(oip->ip6_dst);
9377e4823a9Schristos                 ND_PRINT((ndo,", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)));
938546f56c3Schristos 		switch (dp->icmp6_code) {
939546f56c3Schristos 
940546f56c3Schristos 		case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
941546f56c3Schristos 		case ICMP6_DST_UNREACH_ADMIN:
942546f56c3Schristos 		case ICMP6_DST_UNREACH_ADDR:
9437e4823a9Schristos                         ND_PRINT((ndo," %s",ip6addr_string(ndo, &oip->ip6_dst)));
944546f56c3Schristos                         break;
945546f56c3Schristos 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
9467e4823a9Schristos 			ND_PRINT((ndo," %s, source address %s",
9477e4823a9Schristos 			       ip6addr_string(ndo, &oip->ip6_dst),
9487e4823a9Schristos                                   ip6addr_string(ndo, &oip->ip6_src)));
949546f56c3Schristos 			break;
950546f56c3Schristos 		case ICMP6_DST_UNREACH_NOPORT:
951c746cb4fSchristos 			if ((ouh = get_upperlayer(ndo, (const u_char *)oip, &prot))
952546f56c3Schristos 			    == NULL)
953546f56c3Schristos 				goto trunc;
954546f56c3Schristos 
955546f56c3Schristos 			dport = EXTRACT_16BITS(&ouh->uh_dport);
956546f56c3Schristos 			switch (prot) {
957546f56c3Schristos 			case IPPROTO_TCP:
9587e4823a9Schristos 				ND_PRINT((ndo,", %s tcp port %s",
9597e4823a9Schristos 					ip6addr_string(ndo, &oip->ip6_dst),
960c746cb4fSchristos                                           tcpport_string(ndo, dport)));
961546f56c3Schristos 				break;
962546f56c3Schristos 			case IPPROTO_UDP:
9637e4823a9Schristos 				ND_PRINT((ndo,", %s udp port %s",
9647e4823a9Schristos 					ip6addr_string(ndo, &oip->ip6_dst),
965c746cb4fSchristos                                           udpport_string(ndo, dport)));
966546f56c3Schristos 				break;
967546f56c3Schristos 			default:
9687e4823a9Schristos 				ND_PRINT((ndo,", %s protocol %d port %d unreachable",
9697e4823a9Schristos 					ip6addr_string(ndo, &oip->ip6_dst),
9707e4823a9Schristos                                           oip->ip6_nxt, dport));
971546f56c3Schristos 				break;
972546f56c3Schristos 			}
973546f56c3Schristos 			break;
974546f56c3Schristos 		default:
9757e4823a9Schristos                   if (ndo->ndo_vflag <= 1) {
9767e4823a9Schristos                     print_unknown_data(ndo, bp,"\n\t",length);
977546f56c3Schristos                     return;
978546f56c3Schristos                   }
979546f56c3Schristos                     break;
980546f56c3Schristos 		}
981546f56c3Schristos 		break;
982546f56c3Schristos 	case ICMP6_PACKET_TOO_BIG:
9837e4823a9Schristos 		ND_TCHECK(dp->icmp6_mtu);
9847e4823a9Schristos 		ND_PRINT((ndo,", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)));
985546f56c3Schristos 		break;
986546f56c3Schristos 	case ICMP6_TIME_EXCEEDED:
9877e4823a9Schristos 		ND_TCHECK(oip->ip6_dst);
988546f56c3Schristos 		switch (dp->icmp6_code) {
989546f56c3Schristos 		case ICMP6_TIME_EXCEED_TRANSIT:
9907e4823a9Schristos 			ND_PRINT((ndo," for %s",
9917e4823a9Schristos                                   ip6addr_string(ndo, &oip->ip6_dst)));
992546f56c3Schristos 			break;
993546f56c3Schristos 		case ICMP6_TIME_EXCEED_REASSEMBLY:
9947e4823a9Schristos 			ND_PRINT((ndo," (reassembly)"));
995546f56c3Schristos 			break;
996546f56c3Schristos 		default:
9977e4823a9Schristos                         ND_PRINT((ndo,", unknown code (%u)", dp->icmp6_code));
998546f56c3Schristos 			break;
999546f56c3Schristos 		}
1000546f56c3Schristos 		break;
1001546f56c3Schristos 	case ICMP6_PARAM_PROB:
10027e4823a9Schristos 		ND_TCHECK(oip->ip6_dst);
1003546f56c3Schristos 		switch (dp->icmp6_code) {
1004546f56c3Schristos 		case ICMP6_PARAMPROB_HEADER:
10057e4823a9Schristos                         ND_PRINT((ndo,", erroneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1006546f56c3Schristos                         break;
1007546f56c3Schristos 		case ICMP6_PARAMPROB_NEXTHEADER:
10087e4823a9Schristos                         ND_PRINT((ndo,", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1009546f56c3Schristos                         break;
1010546f56c3Schristos 		case ICMP6_PARAMPROB_OPTION:
10117e4823a9Schristos                         ND_PRINT((ndo,", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)));
1012546f56c3Schristos                         break;
1013546f56c3Schristos 		default:
10147e4823a9Schristos                         ND_PRINT((ndo,", code-#%d",
10157e4823a9Schristos                                   dp->icmp6_code));
1016546f56c3Schristos                         break;
1017546f56c3Schristos 		}
1018546f56c3Schristos 		break;
1019546f56c3Schristos 	case ICMP6_ECHO_REQUEST:
1020546f56c3Schristos 	case ICMP6_ECHO_REPLY:
10217e4823a9Schristos                 ND_TCHECK(dp->icmp6_seq);
10227e4823a9Schristos                 ND_PRINT((ndo,", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)));
1023546f56c3Schristos 		break;
1024546f56c3Schristos 	case ICMP6_MEMBERSHIP_QUERY:
1025546f56c3Schristos 		if (length == MLD_MINLEN) {
10267e4823a9Schristos 			mld6_print(ndo, (const u_char *)dp);
1027546f56c3Schristos 		} else if (length >= MLDV2_MINLEN) {
10287e4823a9Schristos 			ND_PRINT((ndo," v2"));
10297e4823a9Schristos 			mldv2_query_print(ndo, (const u_char *)dp, length);
1030546f56c3Schristos 		} else {
10317e4823a9Schristos                         ND_PRINT((ndo," unknown-version (len %u) ", length));
1032546f56c3Schristos 		}
1033546f56c3Schristos 		break;
1034546f56c3Schristos 	case ICMP6_MEMBERSHIP_REPORT:
10357e4823a9Schristos 		mld6_print(ndo, (const u_char *)dp);
1036546f56c3Schristos 		break;
1037546f56c3Schristos 	case ICMP6_MEMBERSHIP_REDUCTION:
10387e4823a9Schristos 		mld6_print(ndo, (const u_char *)dp);
1039546f56c3Schristos 		break;
1040546f56c3Schristos 	case ND_ROUTER_SOLICIT:
1041546f56c3Schristos #define RTSOLLEN 8
10427e4823a9Schristos 		if (ndo->ndo_vflag) {
10437e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + RTSOLLEN,
1044546f56c3Schristos 					length - RTSOLLEN);
1045546f56c3Schristos 		}
1046546f56c3Schristos 		break;
1047546f56c3Schristos 	case ND_ROUTER_ADVERT:
1048546f56c3Schristos #define RTADVLEN 16
10497e4823a9Schristos 		if (ndo->ndo_vflag) {
1050c746cb4fSchristos 			const struct nd_router_advert *p;
1051546f56c3Schristos 
1052c746cb4fSchristos 			p = (const struct nd_router_advert *)dp;
10537e4823a9Schristos 			ND_TCHECK(p->nd_ra_retransmit);
10547e4823a9Schristos 			ND_PRINT((ndo,"\n\thop limit %u, Flags [%s]" \
1055193b2145Schristos                                   ", pref %s, router lifetime %us, reachable time %ums, retrans timer %ums",
1056546f56c3Schristos                                   (u_int)p->nd_ra_curhoplimit,
1057546f56c3Schristos                                   bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
1058546f56c3Schristos                                   get_rtpref(p->nd_ra_flags_reserved),
1059546f56c3Schristos                                   EXTRACT_16BITS(&p->nd_ra_router_lifetime),
1060546f56c3Schristos                                   EXTRACT_32BITS(&p->nd_ra_reachable),
10617e4823a9Schristos                                   EXTRACT_32BITS(&p->nd_ra_retransmit)));
1062546f56c3Schristos 
10637e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + RTADVLEN,
1064546f56c3Schristos 					length - RTADVLEN);
1065546f56c3Schristos 		}
1066546f56c3Schristos 		break;
1067546f56c3Schristos 	case ND_NEIGHBOR_SOLICIT:
1068546f56c3Schristos 	    {
1069c746cb4fSchristos 		const struct nd_neighbor_solicit *p;
1070c746cb4fSchristos 		p = (const struct nd_neighbor_solicit *)dp;
10717e4823a9Schristos 		ND_TCHECK(p->nd_ns_target);
10727e4823a9Schristos 		ND_PRINT((ndo,", who has %s", ip6addr_string(ndo, &p->nd_ns_target)));
10737e4823a9Schristos 		if (ndo->ndo_vflag) {
1074546f56c3Schristos #define NDSOLLEN 24
10757e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + NDSOLLEN,
1076546f56c3Schristos 					length - NDSOLLEN);
1077546f56c3Schristos 		}
1078546f56c3Schristos 	    }
1079546f56c3Schristos 		break;
1080546f56c3Schristos 	case ND_NEIGHBOR_ADVERT:
1081546f56c3Schristos 	    {
1082c746cb4fSchristos 		const struct nd_neighbor_advert *p;
1083546f56c3Schristos 
1084c746cb4fSchristos 		p = (const struct nd_neighbor_advert *)dp;
10857e4823a9Schristos 		ND_TCHECK(p->nd_na_target);
10867e4823a9Schristos 		ND_PRINT((ndo,", tgt is %s",
10877e4823a9Schristos                           ip6addr_string(ndo, &p->nd_na_target)));
10887e4823a9Schristos 		if (ndo->ndo_vflag) {
10897e4823a9Schristos                         ND_PRINT((ndo,", Flags [%s]",
1090546f56c3Schristos                                   bittok2str(icmp6_nd_na_flag_values,
1091546f56c3Schristos                                              "none",
10927e4823a9Schristos                                              EXTRACT_32BITS(&p->nd_na_flags_reserved))));
1093546f56c3Schristos #define NDADVLEN 24
10947e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + NDADVLEN,
1095546f56c3Schristos 					length - NDADVLEN);
1096546f56c3Schristos #undef NDADVLEN
1097546f56c3Schristos 		}
1098546f56c3Schristos 	    }
1099546f56c3Schristos 		break;
1100546f56c3Schristos 	case ND_REDIRECT:
1101c746cb4fSchristos #define RDR(i) ((const struct nd_redirect *)(i))
11027e4823a9Schristos                          ND_TCHECK(RDR(dp)->nd_rd_dst);
1103c746cb4fSchristos                          ND_PRINT((ndo,", %s", ip6addr_string(ndo, &RDR(dp)->nd_rd_dst)));
11047e4823a9Schristos 		ND_TCHECK(RDR(dp)->nd_rd_target);
11057e4823a9Schristos 		ND_PRINT((ndo," to %s",
1106c746cb4fSchristos                           ip6addr_string(ndo, &RDR(dp)->nd_rd_target)));
1107546f56c3Schristos #define REDIRECTLEN 40
11087e4823a9Schristos 		if (ndo->ndo_vflag) {
11097e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + REDIRECTLEN,
1110546f56c3Schristos 					length - REDIRECTLEN);
1111546f56c3Schristos 		}
1112546f56c3Schristos 		break;
1113546f56c3Schristos #undef REDIRECTLEN
1114546f56c3Schristos #undef RDR
1115546f56c3Schristos 	case ICMP6_ROUTER_RENUMBERING:
11167e4823a9Schristos 		icmp6_rrenum_print(ndo, bp, ep);
1117546f56c3Schristos 		break;
1118546f56c3Schristos 	case ICMP6_NI_QUERY:
1119546f56c3Schristos 	case ICMP6_NI_REPLY:
11207e4823a9Schristos 		icmp6_nodeinfo_print(ndo, length, bp, ep);
1121546f56c3Schristos 		break;
1122546f56c3Schristos 	case IND_SOLICIT:
1123546f56c3Schristos 	case IND_ADVERT:
1124546f56c3Schristos 		break;
1125546f56c3Schristos 	case ICMP6_V2_MEMBERSHIP_REPORT:
11267e4823a9Schristos 		mldv2_report_print(ndo, (const u_char *) dp, length);
1127546f56c3Schristos 		break;
1128546f56c3Schristos 	case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
1129546f56c3Schristos 	case ICMP6_HADISCOV_REQUEST:
11307e4823a9Schristos                 ND_TCHECK(dp->icmp6_data16[0]);
11317e4823a9Schristos                 ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1132546f56c3Schristos                 break;
1133546f56c3Schristos 	case ICMP6_HADISCOV_REPLY:
11347e4823a9Schristos 		if (ndo->ndo_vflag) {
1135c746cb4fSchristos 			const struct in6_addr *in6;
1136c746cb4fSchristos 			const u_char *cp;
1137546f56c3Schristos 
11387e4823a9Schristos 			ND_TCHECK(dp->icmp6_data16[0]);
11397e4823a9Schristos 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
1140c746cb4fSchristos 			cp = (const u_char *)dp + length;
1141c746cb4fSchristos 			in6 = (const struct in6_addr *)(dp + 1);
1142c746cb4fSchristos 			for (; (const u_char *)in6 < cp; in6++) {
11437e4823a9Schristos 				ND_TCHECK(*in6);
11447e4823a9Schristos 				ND_PRINT((ndo,", %s", ip6addr_string(ndo, in6)));
1145546f56c3Schristos 			}
1146546f56c3Schristos 		}
1147546f56c3Schristos 		break;
1148546f56c3Schristos 	case ICMP6_MOBILEPREFIX_ADVERT:
11497e4823a9Schristos 		if (ndo->ndo_vflag) {
11507e4823a9Schristos 			ND_TCHECK(dp->icmp6_data16[0]);
11517e4823a9Schristos 			ND_PRINT((ndo,", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])));
11521c9cc6b1Schristos 			ND_TCHECK(dp->icmp6_data16[1]);
1153546f56c3Schristos 			if (dp->icmp6_data16[1] & 0xc0)
11547e4823a9Schristos 				ND_PRINT((ndo," "));
1155546f56c3Schristos 			if (dp->icmp6_data16[1] & 0x80)
11567e4823a9Schristos 				ND_PRINT((ndo,"M"));
1157546f56c3Schristos 			if (dp->icmp6_data16[1] & 0x40)
11587e4823a9Schristos 				ND_PRINT((ndo,"O"));
1159546f56c3Schristos #define MPADVLEN 8
11607e4823a9Schristos 			icmp6_opt_print(ndo, (const u_char *)dp + MPADVLEN,
1161546f56c3Schristos 					length - MPADVLEN);
1162546f56c3Schristos 		}
1163546f56c3Schristos 		break;
1164546f56c3Schristos         case ND_RPL_MESSAGE:
11657e4823a9Schristos                 /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */
11667e4823a9Schristos                 rpl_print(ndo, dp, &dp->icmp6_data8[0], length-sizeof(struct icmp6_hdr)+4);
1167546f56c3Schristos                 break;
1168546f56c3Schristos 	default:
11697e4823a9Schristos                 ND_PRINT((ndo,", length %u", length));
11707e4823a9Schristos                 if (ndo->ndo_vflag <= 1)
11717e4823a9Schristos                         print_unknown_data(ndo, bp,"\n\t", length);
1172546f56c3Schristos                 return;
1173546f56c3Schristos         }
11747e4823a9Schristos         if (!ndo->ndo_vflag)
11757e4823a9Schristos                 ND_PRINT((ndo,", length %u", length));
1176546f56c3Schristos 	return;
1177546f56c3Schristos trunc:
1178193b2145Schristos 	ND_PRINT((ndo, "%s", icmp6_tstr));
1179546f56c3Schristos }
1180546f56c3Schristos 
11817e4823a9Schristos static const struct udphdr *
get_upperlayer(netdissect_options * ndo,const u_char * bp,u_int * prot)11827e4823a9Schristos get_upperlayer(netdissect_options *ndo, const u_char *bp, u_int *prot)
1183546f56c3Schristos {
1184546f56c3Schristos 	const u_char *ep;
1185c746cb4fSchristos 	const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp;
11867e4823a9Schristos 	const struct udphdr *uh;
11877e4823a9Schristos 	const struct ip6_hbh *hbh;
11887e4823a9Schristos 	const struct ip6_frag *fragh;
11897e4823a9Schristos 	const struct ah *ah;
1190546f56c3Schristos 	u_int nh;
1191546f56c3Schristos 	int hlen;
1192546f56c3Schristos 
1193546f56c3Schristos 	/* 'ep' points to the end of available data. */
11947e4823a9Schristos 	ep = ndo->ndo_snapend;
1195546f56c3Schristos 
11967e4823a9Schristos 	if (!ND_TTEST(ip6->ip6_nxt))
1197546f56c3Schristos 		return NULL;
1198546f56c3Schristos 
1199546f56c3Schristos 	nh = ip6->ip6_nxt;
1200546f56c3Schristos 	hlen = sizeof(struct ip6_hdr);
1201546f56c3Schristos 
1202546f56c3Schristos 	while (bp < ep) {
1203546f56c3Schristos 		bp += hlen;
1204546f56c3Schristos 
1205546f56c3Schristos 		switch(nh) {
1206546f56c3Schristos 		case IPPROTO_UDP:
1207546f56c3Schristos 		case IPPROTO_TCP:
1208c746cb4fSchristos 			uh = (const struct udphdr *)bp;
12097e4823a9Schristos 			if (ND_TTEST(uh->uh_dport)) {
1210546f56c3Schristos 				*prot = nh;
1211546f56c3Schristos 				return(uh);
1212546f56c3Schristos 			}
1213546f56c3Schristos 			else
1214546f56c3Schristos 				return(NULL);
1215546f56c3Schristos 			/* NOTREACHED */
1216546f56c3Schristos 
1217546f56c3Schristos 		case IPPROTO_HOPOPTS:
1218546f56c3Schristos 		case IPPROTO_DSTOPTS:
1219546f56c3Schristos 		case IPPROTO_ROUTING:
1220c746cb4fSchristos 			hbh = (const struct ip6_hbh *)bp;
12217e4823a9Schristos 			if (!ND_TTEST(hbh->ip6h_len))
1222546f56c3Schristos 				return(NULL);
1223546f56c3Schristos 			nh = hbh->ip6h_nxt;
1224546f56c3Schristos 			hlen = (hbh->ip6h_len + 1) << 3;
1225546f56c3Schristos 			break;
1226546f56c3Schristos 
1227546f56c3Schristos 		case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
1228c746cb4fSchristos 			fragh = (const struct ip6_frag *)bp;
12297e4823a9Schristos 			if (!ND_TTEST(fragh->ip6f_offlg))
1230546f56c3Schristos 				return(NULL);
1231546f56c3Schristos 			/* fragments with non-zero offset are meaningless */
1232546f56c3Schristos 			if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
1233546f56c3Schristos 				return(NULL);
1234546f56c3Schristos 			nh = fragh->ip6f_nxt;
1235546f56c3Schristos 			hlen = sizeof(struct ip6_frag);
1236546f56c3Schristos 			break;
1237546f56c3Schristos 
1238546f56c3Schristos 		case IPPROTO_AH:
1239c746cb4fSchristos 			ah = (const struct ah *)bp;
12407e4823a9Schristos 			if (!ND_TTEST(ah->ah_len))
1241546f56c3Schristos 				return(NULL);
1242546f56c3Schristos 			nh = ah->ah_nxt;
1243546f56c3Schristos 			hlen = (ah->ah_len + 2) << 2;
1244546f56c3Schristos 			break;
1245546f56c3Schristos 
1246546f56c3Schristos 		default:	/* unknown or undecodable header */
1247546f56c3Schristos 			*prot = nh; /* meaningless, but set here anyway */
1248546f56c3Schristos 			return(NULL);
1249546f56c3Schristos 		}
1250546f56c3Schristos 	}
1251546f56c3Schristos 
1252546f56c3Schristos 	return(NULL);		/* should be notreached, though */
1253546f56c3Schristos }
1254546f56c3Schristos 
1255546f56c3Schristos static void
icmp6_opt_print(netdissect_options * ndo,const u_char * bp,int resid)12567e4823a9Schristos icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid)
1257546f56c3Schristos {
1258546f56c3Schristos 	const struct nd_opt_hdr *op;
1259546f56c3Schristos 	const struct nd_opt_prefix_info *opp;
1260546f56c3Schristos 	const struct nd_opt_mtu *opm;
1261546f56c3Schristos 	const struct nd_opt_rdnss *oprd;
1262aecd9f07Schristos 	const struct nd_opt_dnssl *opds;
1263546f56c3Schristos 	const struct nd_opt_advinterval *opa;
1264546f56c3Schristos 	const struct nd_opt_homeagent_info *oph;
1265546f56c3Schristos 	const struct nd_opt_route_info *opri;
1266aecd9f07Schristos 	const u_char *cp, *ep, *domp;
1267c746cb4fSchristos 	struct in6_addr in6;
1268c746cb4fSchristos 	const struct in6_addr *in6p;
1269546f56c3Schristos 	size_t l;
1270546f56c3Schristos 	u_int i;
1271546f56c3Schristos 
1272c746cb4fSchristos #define ECHECK(var) if ((const u_char *)&(var) > ep - sizeof(var)) return
1273546f56c3Schristos 
1274546f56c3Schristos 	cp = bp;
1275546f56c3Schristos 	/* 'ep' points to the end of available data. */
12767e4823a9Schristos 	ep = ndo->ndo_snapend;
1277546f56c3Schristos 
1278546f56c3Schristos 	while (cp < ep) {
1279c746cb4fSchristos 		op = (const struct nd_opt_hdr *)cp;
1280546f56c3Schristos 
1281546f56c3Schristos 		ECHECK(op->nd_opt_len);
1282546f56c3Schristos 		if (resid <= 0)
1283546f56c3Schristos 			return;
1284546f56c3Schristos 		if (op->nd_opt_len == 0)
1285546f56c3Schristos 			goto trunc;
1286546f56c3Schristos 		if (cp + (op->nd_opt_len << 3) > ep)
1287546f56c3Schristos 			goto trunc;
1288546f56c3Schristos 
12897e4823a9Schristos                 ND_PRINT((ndo,"\n\t  %s option (%u), length %u (%u): ",
1290546f56c3Schristos                           tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
1291546f56c3Schristos                           op->nd_opt_type,
1292546f56c3Schristos                           op->nd_opt_len << 3,
12937e4823a9Schristos                           op->nd_opt_len));
1294546f56c3Schristos 
1295546f56c3Schristos 		switch (op->nd_opt_type) {
1296546f56c3Schristos 		case ND_OPT_SOURCE_LINKADDR:
1297546f56c3Schristos 			l = (op->nd_opt_len << 3) - 2;
12987e4823a9Schristos 			print_lladdr(ndo, cp + 2, l);
1299546f56c3Schristos 			break;
1300546f56c3Schristos 		case ND_OPT_TARGET_LINKADDR:
1301546f56c3Schristos 			l = (op->nd_opt_len << 3) - 2;
13027e4823a9Schristos 			print_lladdr(ndo, cp + 2, l);
1303546f56c3Schristos 			break;
1304546f56c3Schristos 		case ND_OPT_PREFIX_INFORMATION:
1305c746cb4fSchristos 			opp = (const struct nd_opt_prefix_info *)op;
13067e4823a9Schristos 			ND_TCHECK(opp->nd_opt_pi_prefix);
13077e4823a9Schristos                         ND_PRINT((ndo,"%s/%u%s, Flags [%s], valid time %s",
13087e4823a9Schristos                                   ip6addr_string(ndo, &opp->nd_opt_pi_prefix),
1309546f56c3Schristos                                   opp->nd_opt_pi_prefix_len,
1310546f56c3Schristos                                   (op->nd_opt_len != 4) ? "badlen" : "",
1311546f56c3Schristos                                   bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
13127e4823a9Schristos                                   get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))));
13137e4823a9Schristos                         ND_PRINT((ndo,", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))));
1314546f56c3Schristos 			break;
1315546f56c3Schristos 		case ND_OPT_REDIRECTED_HEADER:
13167e4823a9Schristos                         print_unknown_data(ndo, bp,"\n\t    ",op->nd_opt_len<<3);
1317546f56c3Schristos 			/* xxx */
1318546f56c3Schristos 			break;
1319546f56c3Schristos 		case ND_OPT_MTU:
1320c746cb4fSchristos 			opm = (const struct nd_opt_mtu *)op;
13217e4823a9Schristos 			ND_TCHECK(opm->nd_opt_mtu_mtu);
13227e4823a9Schristos 			ND_PRINT((ndo," %u%s",
1323546f56c3Schristos                                EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
13247e4823a9Schristos                                   (op->nd_opt_len != 1) ? "bad option length" : "" ));
1325546f56c3Schristos                         break;
1326546f56c3Schristos 		case ND_OPT_RDNSS:
1327c746cb4fSchristos 			oprd = (const struct nd_opt_rdnss *)op;
1328546f56c3Schristos 			l = (op->nd_opt_len - 1) / 2;
13297e4823a9Schristos 			ND_PRINT((ndo," lifetime %us,",
13307e4823a9Schristos                                   EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)));
1331546f56c3Schristos 			for (i = 0; i < l; i++) {
13327e4823a9Schristos 				ND_TCHECK(oprd->nd_opt_rdnss_addr[i]);
13337e4823a9Schristos 				ND_PRINT((ndo," addr: %s",
13347e4823a9Schristos                                           ip6addr_string(ndo, &oprd->nd_opt_rdnss_addr[i])));
1335546f56c3Schristos 			}
1336546f56c3Schristos 			break;
1337aecd9f07Schristos 		case ND_OPT_DNSSL:
1338c746cb4fSchristos 			opds = (const struct nd_opt_dnssl *)op;
13397e4823a9Schristos 			ND_PRINT((ndo," lifetime %us, domain(s):",
13407e4823a9Schristos                                   EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime)));
1341aecd9f07Schristos 			domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */
1342aecd9f07Schristos 			while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0')
1343aecd9f07Schristos 			{
13447e4823a9Schristos 				ND_PRINT((ndo, " "));
13457e4823a9Schristos 				if ((domp = ns_nprint (ndo, domp, bp)) == NULL)
1346aecd9f07Schristos 					goto trunc;
1347aecd9f07Schristos 			}
1348aecd9f07Schristos 			break;
1349546f56c3Schristos 		case ND_OPT_ADVINTERVAL:
1350c746cb4fSchristos 			opa = (const struct nd_opt_advinterval *)op;
13517e4823a9Schristos 			ND_TCHECK(opa->nd_opt_adv_interval);
13527e4823a9Schristos 			ND_PRINT((ndo," %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval)));
1353546f56c3Schristos 			break;
1354546f56c3Schristos                 case ND_OPT_HOMEAGENT_INFO:
1355c746cb4fSchristos 			oph = (const struct nd_opt_homeagent_info *)op;
13567e4823a9Schristos 			ND_TCHECK(oph->nd_opt_hai_lifetime);
13577e4823a9Schristos 			ND_PRINT((ndo," preference %u, lifetime %u",
1358546f56c3Schristos                                   EXTRACT_16BITS(&oph->nd_opt_hai_preference),
13597e4823a9Schristos                                   EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)));
1360546f56c3Schristos 			break;
1361546f56c3Schristos 		case ND_OPT_ROUTE_INFO:
1362c746cb4fSchristos 			opri = (const struct nd_opt_route_info *)op;
13637e4823a9Schristos 			ND_TCHECK(opri->nd_opt_rti_lifetime);
1364546f56c3Schristos 			memset(&in6, 0, sizeof(in6));
1365c746cb4fSchristos 			in6p = (const struct in6_addr *)(opri + 1);
1366546f56c3Schristos 			switch (op->nd_opt_len) {
1367546f56c3Schristos 			case 1:
1368546f56c3Schristos 				break;
1369546f56c3Schristos 			case 2:
13707e4823a9Schristos 				ND_TCHECK2(*in6p, 8);
1371546f56c3Schristos 				memcpy(&in6, opri + 1, 8);
1372546f56c3Schristos 				break;
1373546f56c3Schristos 			case 3:
13747e4823a9Schristos 				ND_TCHECK(*in6p);
1375546f56c3Schristos 				memcpy(&in6, opri + 1, sizeof(in6));
1376546f56c3Schristos 				break;
1377546f56c3Schristos 			default:
1378546f56c3Schristos 				goto trunc;
1379546f56c3Schristos 			}
13807e4823a9Schristos 			ND_PRINT((ndo," %s/%u", ip6addr_string(ndo, &in6),
13817e4823a9Schristos                                   opri->nd_opt_rti_prefixlen));
13827e4823a9Schristos 			ND_PRINT((ndo,", pref=%s", get_rtpref(opri->nd_opt_rti_flags)));
13837e4823a9Schristos 			ND_PRINT((ndo,", lifetime=%s",
13847e4823a9Schristos                                   get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))));
1385546f56c3Schristos 			break;
1386546f56c3Schristos 		default:
13877e4823a9Schristos                         if (ndo->ndo_vflag <= 1) {
13887e4823a9Schristos                                 print_unknown_data(ndo,cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
1389546f56c3Schristos                             return;
1390546f56c3Schristos                         }
1391546f56c3Schristos                         break;
1392546f56c3Schristos 		}
1393546f56c3Schristos                 /* do we want to see an additional hexdump ? */
13947e4823a9Schristos                 if (ndo->ndo_vflag> 1)
13957e4823a9Schristos                         print_unknown_data(ndo, cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
1396546f56c3Schristos 
1397546f56c3Schristos 		cp += op->nd_opt_len << 3;
1398546f56c3Schristos 		resid -= op->nd_opt_len << 3;
1399546f56c3Schristos 	}
1400546f56c3Schristos 	return;
1401546f56c3Schristos 
1402546f56c3Schristos trunc:
1403193b2145Schristos 	ND_PRINT((ndo, "%s", icmp6_tstr));
1404546f56c3Schristos 	return;
1405546f56c3Schristos #undef ECHECK
1406546f56c3Schristos }
1407546f56c3Schristos 
1408141b0ad2Skamil UNALIGNED_OK
1409546f56c3Schristos static void
mld6_print(netdissect_options * ndo,const u_char * bp)14107e4823a9Schristos mld6_print(netdissect_options *ndo, const u_char *bp)
1411546f56c3Schristos {
1412c746cb4fSchristos 	const struct mld6_hdr *mp = (const struct mld6_hdr *)bp;
1413546f56c3Schristos 	const u_char *ep;
1414546f56c3Schristos 
1415546f56c3Schristos 	/* 'ep' points to the end of available data. */
14167e4823a9Schristos 	ep = ndo->ndo_snapend;
1417546f56c3Schristos 
1418c746cb4fSchristos 	if ((const u_char *)mp + sizeof(*mp) > ep)
1419546f56c3Schristos 		return;
1420546f56c3Schristos 
14217e4823a9Schristos 	ND_PRINT((ndo,"max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)));
14227e4823a9Schristos 	ND_PRINT((ndo,"addr: %s", ip6addr_string(ndo, &mp->mld6_addr)));
1423546f56c3Schristos }
1424546f56c3Schristos 
1425141b0ad2Skamil UNALIGNED_OK
1426546f56c3Schristos static void
mldv2_report_print(netdissect_options * ndo,const u_char * bp,u_int len)14277e4823a9Schristos mldv2_report_print(netdissect_options *ndo, const u_char *bp, u_int len)
1428546f56c3Schristos {
1429c746cb4fSchristos     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1430546f56c3Schristos     u_int group, nsrcs, ngroups;
1431546f56c3Schristos     u_int i, j;
1432546f56c3Schristos 
1433546f56c3Schristos     /* Minimum len is 8 */
1434546f56c3Schristos     if (len < 8) {
14357e4823a9Schristos             ND_PRINT((ndo," [invalid len %d]", len));
1436546f56c3Schristos             return;
1437546f56c3Schristos     }
1438546f56c3Schristos 
14397e4823a9Schristos     ND_TCHECK(icp->icmp6_data16[1]);
1440546f56c3Schristos     ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
14417e4823a9Schristos     ND_PRINT((ndo,", %d group record(s)", ngroups));
14427e4823a9Schristos     if (ndo->ndo_vflag > 0) {
1443546f56c3Schristos 	/* Print the group records */
1444546f56c3Schristos 	group = 8;
1445546f56c3Schristos         for (i = 0; i < ngroups; i++) {
1446546f56c3Schristos 	    /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
1447546f56c3Schristos 	    if (len < group + 20) {
14487e4823a9Schristos                     ND_PRINT((ndo," [invalid number of groups]"));
1449546f56c3Schristos                     return;
1450546f56c3Schristos 	    }
14517e4823a9Schristos             ND_TCHECK2(bp[group + 4], sizeof(struct in6_addr));
14527e4823a9Schristos             ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[group + 4])));
14537e4823a9Schristos 	    ND_PRINT((ndo," %s", tok2str(mldv2report2str, " [v2-report-#%d]",
14547e4823a9Schristos                                          bp[group])));
1455546f56c3Schristos             nsrcs = (bp[group + 2] << 8) + bp[group + 3];
1456546f56c3Schristos 	    /* Check the number of sources and print them */
1457546f56c3Schristos 	    if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
14587e4823a9Schristos                     ND_PRINT((ndo," [invalid number of sources %d]", nsrcs));
1459546f56c3Schristos                     return;
1460546f56c3Schristos 	    }
14617e4823a9Schristos             if (ndo->ndo_vflag == 1)
14627e4823a9Schristos                     ND_PRINT((ndo,", %d source(s)", nsrcs));
1463546f56c3Schristos             else {
1464546f56c3Schristos 		/* Print the sources */
14657e4823a9Schristos                     ND_PRINT((ndo," {"));
1466546f56c3Schristos                 for (j = 0; j < nsrcs; j++) {
14677e4823a9Schristos                     ND_TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
1468546f56c3Schristos                             sizeof(struct in6_addr));
14697e4823a9Schristos 		    ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[group + 20 + j * sizeof(struct in6_addr)])));
1470546f56c3Schristos 		}
14717e4823a9Schristos                 ND_PRINT((ndo," }"));
1472546f56c3Schristos             }
1473546f56c3Schristos 	    /* Next group record */
1474546f56c3Schristos             group += 20 + nsrcs * sizeof(struct in6_addr);
14757e4823a9Schristos 	    ND_PRINT((ndo,"]"));
1476546f56c3Schristos         }
1477546f56c3Schristos     }
1478546f56c3Schristos     return;
1479546f56c3Schristos trunc:
1480193b2145Schristos     ND_PRINT((ndo, "%s", mldv2_tstr));
1481546f56c3Schristos     return;
1482546f56c3Schristos }
1483546f56c3Schristos 
1484141b0ad2Skamil UNALIGNED_OK
1485546f56c3Schristos static void
mldv2_query_print(netdissect_options * ndo,const u_char * bp,u_int len)14867e4823a9Schristos mldv2_query_print(netdissect_options *ndo, const u_char *bp, u_int len)
1487546f56c3Schristos {
1488c746cb4fSchristos     const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp;
1489546f56c3Schristos     u_int mrc;
1490546f56c3Schristos     int mrt, qqi;
1491546f56c3Schristos     u_int nsrcs;
1492546f56c3Schristos     register u_int i;
1493546f56c3Schristos 
1494546f56c3Schristos     /* Minimum len is 28 */
1495546f56c3Schristos     if (len < 28) {
14967e4823a9Schristos             ND_PRINT((ndo," [invalid len %d]", len));
1497546f56c3Schristos 	return;
1498546f56c3Schristos     }
14997e4823a9Schristos     ND_TCHECK(icp->icmp6_data16[0]);
1500546f56c3Schristos     mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
1501546f56c3Schristos     if (mrc < 32768) {
1502546f56c3Schristos 	mrt = mrc;
1503546f56c3Schristos     } else {
1504546f56c3Schristos         mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
1505546f56c3Schristos     }
15067e4823a9Schristos     if (ndo->ndo_vflag) {
15077e4823a9Schristos             ND_PRINT((ndo," [max resp delay=%d]", mrt));
1508546f56c3Schristos     }
15097e4823a9Schristos     ND_TCHECK2(bp[8], sizeof(struct in6_addr));
15107e4823a9Schristos     ND_PRINT((ndo," [gaddr %s", ip6addr_string(ndo, &bp[8])));
1511546f56c3Schristos 
15127e4823a9Schristos     if (ndo->ndo_vflag) {
15137e4823a9Schristos         ND_TCHECK(bp[25]);
1514546f56c3Schristos 	if (bp[24] & 0x08) {
15157e4823a9Schristos 		ND_PRINT((ndo," sflag"));
1516546f56c3Schristos 	}
1517546f56c3Schristos 	if (bp[24] & 0x07) {
15187e4823a9Schristos 		ND_PRINT((ndo," robustness=%d", bp[24] & 0x07));
1519546f56c3Schristos 	}
1520546f56c3Schristos 	if (bp[25] < 128) {
1521546f56c3Schristos 		qqi = bp[25];
1522546f56c3Schristos 	} else {
1523546f56c3Schristos 		qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
1524546f56c3Schristos 	}
15257e4823a9Schristos 	ND_PRINT((ndo," qqi=%d", qqi));
1526546f56c3Schristos     }
1527546f56c3Schristos 
15287e4823a9Schristos     ND_TCHECK2(bp[26], 2);
1529546f56c3Schristos     nsrcs = EXTRACT_16BITS(&bp[26]);
1530546f56c3Schristos     if (nsrcs > 0) {
1531546f56c3Schristos 	if (len < 28 + nsrcs * sizeof(struct in6_addr))
15327e4823a9Schristos 	    ND_PRINT((ndo," [invalid number of sources]"));
15337e4823a9Schristos 	else if (ndo->ndo_vflag > 1) {
15347e4823a9Schristos 	    ND_PRINT((ndo," {"));
1535546f56c3Schristos 	    for (i = 0; i < nsrcs; i++) {
15367e4823a9Schristos 		ND_TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
1537546f56c3Schristos                         sizeof(struct in6_addr));
15387e4823a9Schristos 		ND_PRINT((ndo," %s", ip6addr_string(ndo, &bp[28 + i * sizeof(struct in6_addr)])));
1539546f56c3Schristos 	    }
15407e4823a9Schristos 	    ND_PRINT((ndo," }"));
1541546f56c3Schristos 	} else
15427e4823a9Schristos                 ND_PRINT((ndo,", %d source(s)", nsrcs));
1543546f56c3Schristos     }
15447e4823a9Schristos     ND_PRINT((ndo,"]"));
1545546f56c3Schristos     return;
1546546f56c3Schristos trunc:
1547193b2145Schristos     ND_PRINT((ndo, "%s", mldv2_tstr));
1548546f56c3Schristos     return;
1549546f56c3Schristos }
1550546f56c3Schristos 
1551546f56c3Schristos static void
dnsname_print(netdissect_options * ndo,const u_char * cp,const u_char * ep)15527e4823a9Schristos dnsname_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
1553546f56c3Schristos {
1554546f56c3Schristos 	int i;
1555546f56c3Schristos 
1556546f56c3Schristos 	/* DNS name decoding - no decompression */
15577e4823a9Schristos 	ND_PRINT((ndo,", \""));
1558546f56c3Schristos 	while (cp < ep) {
1559546f56c3Schristos 		i = *cp++;
1560546f56c3Schristos 		if (i) {
1561546f56c3Schristos 			if (i > ep - cp) {
15627e4823a9Schristos 				ND_PRINT((ndo,"???"));
1563546f56c3Schristos 				break;
1564546f56c3Schristos 			}
1565546f56c3Schristos 			while (i-- && cp < ep) {
15667e4823a9Schristos 				safeputchar(ndo, *cp);
1567546f56c3Schristos 				cp++;
1568546f56c3Schristos 			}
1569546f56c3Schristos 			if (cp + 1 < ep && *cp)
15707e4823a9Schristos 				ND_PRINT((ndo,"."));
1571546f56c3Schristos 		} else {
1572546f56c3Schristos 			if (cp == ep) {
1573546f56c3Schristos 				/* FQDN */
15747e4823a9Schristos 				ND_PRINT((ndo,"."));
1575546f56c3Schristos 			} else if (cp + 1 == ep && *cp == '\0') {
1576546f56c3Schristos 				/* truncated */
1577546f56c3Schristos 			} else {
1578546f56c3Schristos 				/* invalid */
15797e4823a9Schristos 				ND_PRINT((ndo,"???"));
1580546f56c3Schristos 			}
1581546f56c3Schristos 			break;
1582546f56c3Schristos 		}
1583546f56c3Schristos 	}
15847e4823a9Schristos 	ND_PRINT((ndo,"\""));
1585546f56c3Schristos }
1586546f56c3Schristos 
1587546f56c3Schristos static void
icmp6_nodeinfo_print(netdissect_options * ndo,u_int icmp6len,const u_char * bp,const u_char * ep)15887e4823a9Schristos icmp6_nodeinfo_print(netdissect_options *ndo, u_int icmp6len, const u_char *bp, const u_char *ep)
1589546f56c3Schristos {
15907e4823a9Schristos 	const struct icmp6_nodeinfo *ni6;
15917e4823a9Schristos 	const struct icmp6_hdr *dp;
1592546f56c3Schristos 	const u_char *cp;
1593546f56c3Schristos 	size_t siz, i;
1594546f56c3Schristos 	int needcomma;
1595546f56c3Schristos 
1596546f56c3Schristos 	if (ep < bp)
1597546f56c3Schristos 		return;
1598c746cb4fSchristos 	dp = (const struct icmp6_hdr *)bp;
1599c746cb4fSchristos 	ni6 = (const struct icmp6_nodeinfo *)bp;
1600546f56c3Schristos 	siz = ep - bp;
1601546f56c3Schristos 
1602546f56c3Schristos 	switch (ni6->ni_type) {
1603546f56c3Schristos 	case ICMP6_NI_QUERY:
1604546f56c3Schristos 		if (siz == sizeof(*dp) + 4) {
1605546f56c3Schristos 			/* KAME who-are-you */
16067e4823a9Schristos 			ND_PRINT((ndo," who-are-you request"));
1607546f56c3Schristos 			break;
1608546f56c3Schristos 		}
16097e4823a9Schristos 		ND_PRINT((ndo," node information query"));
1610546f56c3Schristos 
16117e4823a9Schristos 		ND_TCHECK2(*dp, sizeof(*ni6));
1612c746cb4fSchristos 		ni6 = (const struct icmp6_nodeinfo *)dp;
16137e4823a9Schristos 		ND_PRINT((ndo," ("));	/*)*/
1614546f56c3Schristos 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1615546f56c3Schristos 		case NI_QTYPE_NOOP:
16167e4823a9Schristos 			ND_PRINT((ndo,"noop"));
1617546f56c3Schristos 			break;
1618546f56c3Schristos 		case NI_QTYPE_SUPTYPES:
16197e4823a9Schristos 			ND_PRINT((ndo,"supported qtypes"));
1620546f56c3Schristos 			i = EXTRACT_16BITS(&ni6->ni_flags);
1621546f56c3Schristos 			if (i)
16227e4823a9Schristos 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1623546f56c3Schristos 			break;
1624546f56c3Schristos 		case NI_QTYPE_FQDN:
16257e4823a9Schristos 			ND_PRINT((ndo,"DNS name"));
1626546f56c3Schristos 			break;
1627546f56c3Schristos 		case NI_QTYPE_NODEADDR:
16287e4823a9Schristos 			ND_PRINT((ndo,"node addresses"));
1629546f56c3Schristos 			i = ni6->ni_flags;
1630546f56c3Schristos 			if (!i)
1631546f56c3Schristos 				break;
1632546f56c3Schristos 			/* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
16337e4823a9Schristos 			ND_PRINT((ndo," [%s%s%s%s%s%s]",
1634546f56c3Schristos 			    (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1635546f56c3Schristos 			    (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1636546f56c3Schristos 			    (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1637546f56c3Schristos 			    (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1638546f56c3Schristos 			    (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
16397e4823a9Schristos 			    (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""));
1640546f56c3Schristos 			break;
1641546f56c3Schristos 		default:
16427e4823a9Schristos 			ND_PRINT((ndo,"unknown"));
1643546f56c3Schristos 			break;
1644546f56c3Schristos 		}
1645546f56c3Schristos 
1646546f56c3Schristos 		if (ni6->ni_qtype == NI_QTYPE_NOOP ||
1647546f56c3Schristos 		    ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
1648546f56c3Schristos 			if (siz != sizeof(*ni6))
16497e4823a9Schristos 				if (ndo->ndo_vflag)
16507e4823a9Schristos 					ND_PRINT((ndo,", invalid len"));
1651546f56c3Schristos 			/*(*/
16527e4823a9Schristos 			ND_PRINT((ndo,")"));
1653546f56c3Schristos 			break;
1654546f56c3Schristos 		}
1655546f56c3Schristos 
1656546f56c3Schristos 
1657546f56c3Schristos 		/* XXX backward compat, icmp-name-lookup-03 */
1658546f56c3Schristos 		if (siz == sizeof(*ni6)) {
16597e4823a9Schristos 			ND_PRINT((ndo,", 03 draft"));
1660546f56c3Schristos 			/*(*/
16617e4823a9Schristos 			ND_PRINT((ndo,")"));
1662546f56c3Schristos 			break;
1663546f56c3Schristos 		}
1664546f56c3Schristos 
1665546f56c3Schristos 		switch (ni6->ni_code) {
1666546f56c3Schristos 		case ICMP6_NI_SUBJ_IPV6:
16677e4823a9Schristos 			if (!ND_TTEST2(*dp,
1668546f56c3Schristos 			    sizeof(*ni6) + sizeof(struct in6_addr)))
1669546f56c3Schristos 				break;
1670546f56c3Schristos 			if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
16717e4823a9Schristos 				if (ndo->ndo_vflag)
16727e4823a9Schristos 					ND_PRINT((ndo,", invalid subject len"));
1673546f56c3Schristos 				break;
1674546f56c3Schristos 			}
16757e4823a9Schristos 			ND_PRINT((ndo,", subject=%s",
1676c746cb4fSchristos                                   ip6addr_string(ndo, ni6 + 1)));
1677546f56c3Schristos 			break;
1678546f56c3Schristos 		case ICMP6_NI_SUBJ_FQDN:
16797e4823a9Schristos 			ND_PRINT((ndo,", subject=DNS name"));
1680546f56c3Schristos 			cp = (const u_char *)(ni6 + 1);
1681546f56c3Schristos 			if (cp[0] == ep - cp - 1) {
1682546f56c3Schristos 				/* icmp-name-lookup-03, pascal string */
16837e4823a9Schristos 				if (ndo->ndo_vflag)
16847e4823a9Schristos 					ND_PRINT((ndo,", 03 draft"));
1685546f56c3Schristos 				cp++;
16867e4823a9Schristos 				ND_PRINT((ndo,", \""));
1687546f56c3Schristos 				while (cp < ep) {
16887e4823a9Schristos 					safeputchar(ndo, *cp);
1689546f56c3Schristos 					cp++;
1690546f56c3Schristos 				}
16917e4823a9Schristos 				ND_PRINT((ndo,"\""));
1692546f56c3Schristos 			} else
16937e4823a9Schristos 				dnsname_print(ndo, cp, ep);
1694546f56c3Schristos 			break;
1695546f56c3Schristos 		case ICMP6_NI_SUBJ_IPV4:
16967e4823a9Schristos 			if (!ND_TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
1697546f56c3Schristos 				break;
1698546f56c3Schristos 			if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
16997e4823a9Schristos 				if (ndo->ndo_vflag)
17007e4823a9Schristos 					ND_PRINT((ndo,", invalid subject len"));
1701546f56c3Schristos 				break;
1702546f56c3Schristos 			}
17037e4823a9Schristos 			ND_PRINT((ndo,", subject=%s",
1704c746cb4fSchristos                                   ipaddr_string(ndo, ni6 + 1)));
1705546f56c3Schristos 			break;
1706546f56c3Schristos 		default:
17077e4823a9Schristos 			ND_PRINT((ndo,", unknown subject"));
1708546f56c3Schristos 			break;
1709546f56c3Schristos 		}
1710546f56c3Schristos 
1711546f56c3Schristos 		/*(*/
17127e4823a9Schristos 		ND_PRINT((ndo,")"));
1713546f56c3Schristos 		break;
1714546f56c3Schristos 
1715546f56c3Schristos 	case ICMP6_NI_REPLY:
1716546f56c3Schristos 		if (icmp6len > siz) {
17177e4823a9Schristos 			ND_PRINT((ndo,"[|icmp6: node information reply]"));
1718546f56c3Schristos 			break;
1719546f56c3Schristos 		}
1720546f56c3Schristos 
1721546f56c3Schristos 		needcomma = 0;
1722546f56c3Schristos 
17231c9cc6b1Schristos 		ND_TCHECK2(*dp, sizeof(*ni6));
1724c746cb4fSchristos 		ni6 = (const struct icmp6_nodeinfo *)dp;
17257e4823a9Schristos 		ND_PRINT((ndo," node information reply"));
17267e4823a9Schristos 		ND_PRINT((ndo," ("));	/*)*/
1727546f56c3Schristos 		switch (ni6->ni_code) {
1728546f56c3Schristos 		case ICMP6_NI_SUCCESS:
17297e4823a9Schristos 			if (ndo->ndo_vflag) {
17307e4823a9Schristos 				ND_PRINT((ndo,"success"));
1731546f56c3Schristos 				needcomma++;
1732546f56c3Schristos 			}
1733546f56c3Schristos 			break;
1734546f56c3Schristos 		case ICMP6_NI_REFUSED:
17357e4823a9Schristos 			ND_PRINT((ndo,"refused"));
1736546f56c3Schristos 			needcomma++;
1737546f56c3Schristos 			if (siz != sizeof(*ni6))
17387e4823a9Schristos 				if (ndo->ndo_vflag)
17397e4823a9Schristos 					ND_PRINT((ndo,", invalid length"));
1740546f56c3Schristos 			break;
1741546f56c3Schristos 		case ICMP6_NI_UNKNOWN:
17427e4823a9Schristos 			ND_PRINT((ndo,"unknown"));
1743546f56c3Schristos 			needcomma++;
1744546f56c3Schristos 			if (siz != sizeof(*ni6))
17457e4823a9Schristos 				if (ndo->ndo_vflag)
17467e4823a9Schristos 					ND_PRINT((ndo,", invalid length"));
1747546f56c3Schristos 			break;
1748546f56c3Schristos 		}
1749546f56c3Schristos 
1750546f56c3Schristos 		if (ni6->ni_code != ICMP6_NI_SUCCESS) {
1751546f56c3Schristos 			/*(*/
17527e4823a9Schristos 			ND_PRINT((ndo,")"));
1753546f56c3Schristos 			break;
1754546f56c3Schristos 		}
1755546f56c3Schristos 
1756546f56c3Schristos 		switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
1757546f56c3Schristos 		case NI_QTYPE_NOOP:
1758546f56c3Schristos 			if (needcomma)
17597e4823a9Schristos 				ND_PRINT((ndo,", "));
17607e4823a9Schristos 			ND_PRINT((ndo,"noop"));
1761546f56c3Schristos 			if (siz != sizeof(*ni6))
17627e4823a9Schristos 				if (ndo->ndo_vflag)
17637e4823a9Schristos 					ND_PRINT((ndo,", invalid length"));
1764546f56c3Schristos 			break;
1765546f56c3Schristos 		case NI_QTYPE_SUPTYPES:
1766546f56c3Schristos 			if (needcomma)
17677e4823a9Schristos 				ND_PRINT((ndo,", "));
17687e4823a9Schristos 			ND_PRINT((ndo,"supported qtypes"));
1769546f56c3Schristos 			i = EXTRACT_16BITS(&ni6->ni_flags);
1770546f56c3Schristos 			if (i)
17717e4823a9Schristos 				ND_PRINT((ndo," [%s]", (i & 0x01) ? "C" : ""));
1772546f56c3Schristos 			break;
1773546f56c3Schristos 		case NI_QTYPE_FQDN:
1774546f56c3Schristos 			if (needcomma)
17757e4823a9Schristos 				ND_PRINT((ndo,", "));
17767e4823a9Schristos 			ND_PRINT((ndo,"DNS name"));
1777546f56c3Schristos 			cp = (const u_char *)(ni6 + 1) + 4;
17781c9cc6b1Schristos 			ND_TCHECK(cp[0]);
1779546f56c3Schristos 			if (cp[0] == ep - cp - 1) {
1780546f56c3Schristos 				/* icmp-name-lookup-03, pascal string */
17817e4823a9Schristos 				if (ndo->ndo_vflag)
17827e4823a9Schristos 					ND_PRINT((ndo,", 03 draft"));
1783546f56c3Schristos 				cp++;
17847e4823a9Schristos 				ND_PRINT((ndo,", \""));
1785546f56c3Schristos 				while (cp < ep) {
17867e4823a9Schristos 					safeputchar(ndo, *cp);
1787546f56c3Schristos 					cp++;
1788546f56c3Schristos 				}
17897e4823a9Schristos 				ND_PRINT((ndo,"\""));
1790546f56c3Schristos 			} else
17917e4823a9Schristos 				dnsname_print(ndo, cp, ep);
1792546f56c3Schristos 			if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
1793c746cb4fSchristos 				ND_PRINT((ndo," [TTL=%u]", EXTRACT_32BITS(ni6 + 1)));
1794546f56c3Schristos 			break;
1795546f56c3Schristos 		case NI_QTYPE_NODEADDR:
1796546f56c3Schristos 			if (needcomma)
17977e4823a9Schristos 				ND_PRINT((ndo,", "));
17987e4823a9Schristos 			ND_PRINT((ndo,"node addresses"));
1799546f56c3Schristos 			i = sizeof(*ni6);
1800546f56c3Schristos 			while (i < siz) {
1801546f56c3Schristos 				if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
1802546f56c3Schristos 					break;
1803c746cb4fSchristos 				ND_PRINT((ndo," %s", ip6addr_string(ndo, bp + i)));
1804546f56c3Schristos 				i += sizeof(struct in6_addr);
18057e4823a9Schristos 				ND_PRINT((ndo,"(%d)", (int32_t)EXTRACT_32BITS(bp + i)));
1806546f56c3Schristos 				i += sizeof(int32_t);
1807546f56c3Schristos 			}
1808546f56c3Schristos 			i = ni6->ni_flags;
1809546f56c3Schristos 			if (!i)
1810546f56c3Schristos 				break;
18117e4823a9Schristos 			ND_PRINT((ndo," [%s%s%s%s%s%s%s]",
1812546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
1813546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
1814546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
1815546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
1816546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
1817546f56c3Schristos                                   (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
18187e4823a9Schristos                                   (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""));
1819546f56c3Schristos 			break;
1820546f56c3Schristos 		default:
1821546f56c3Schristos 			if (needcomma)
18227e4823a9Schristos 				ND_PRINT((ndo,", "));
18237e4823a9Schristos 			ND_PRINT((ndo,"unknown"));
1824546f56c3Schristos 			break;
1825546f56c3Schristos 		}
1826546f56c3Schristos 
1827546f56c3Schristos 		/*(*/
18287e4823a9Schristos 		ND_PRINT((ndo,")"));
1829546f56c3Schristos 		break;
1830546f56c3Schristos 	}
1831546f56c3Schristos 	return;
1832546f56c3Schristos 
1833546f56c3Schristos trunc:
1834193b2145Schristos 	ND_PRINT((ndo, "%s", icmp6_tstr));
1835546f56c3Schristos }
1836546f56c3Schristos 
1837546f56c3Schristos static void
icmp6_rrenum_print(netdissect_options * ndo,const u_char * bp,const u_char * ep)18387e4823a9Schristos icmp6_rrenum_print(netdissect_options *ndo, const u_char *bp, const u_char *ep)
1839546f56c3Schristos {
18407e4823a9Schristos 	const struct icmp6_router_renum *rr6;
1841546f56c3Schristos 	const char *cp;
1842c746cb4fSchristos 	const struct rr_pco_match *match;
1843c746cb4fSchristos 	const struct rr_pco_use *use;
1844546f56c3Schristos 	char hbuf[NI_MAXHOST];
1845546f56c3Schristos 	int n;
1846546f56c3Schristos 
1847546f56c3Schristos 	if (ep < bp)
1848546f56c3Schristos 		return;
1849c746cb4fSchristos 	rr6 = (const struct icmp6_router_renum *)bp;
1850546f56c3Schristos 	cp = (const char *)(rr6 + 1);
1851546f56c3Schristos 
18527e4823a9Schristos 	ND_TCHECK(rr6->rr_reserved);
1853546f56c3Schristos 	switch (rr6->rr_code) {
1854546f56c3Schristos 	case ICMP6_ROUTER_RENUMBERING_COMMAND:
18557e4823a9Schristos 		ND_PRINT((ndo,"router renum: command"));
1856546f56c3Schristos 		break;
1857546f56c3Schristos 	case ICMP6_ROUTER_RENUMBERING_RESULT:
18587e4823a9Schristos 		ND_PRINT((ndo,"router renum: result"));
1859546f56c3Schristos 		break;
1860546f56c3Schristos 	case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
18617e4823a9Schristos 		ND_PRINT((ndo,"router renum: sequence number reset"));
1862546f56c3Schristos 		break;
1863546f56c3Schristos 	default:
18647e4823a9Schristos 		ND_PRINT((ndo,"router renum: code-#%d", rr6->rr_code));
1865546f56c3Schristos 		break;
1866546f56c3Schristos 	}
1867546f56c3Schristos 
18687e4823a9Schristos         ND_PRINT((ndo,", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)));
1869546f56c3Schristos 
18707e4823a9Schristos 	if (ndo->ndo_vflag) {
1871546f56c3Schristos #define F(x, y)	((rr6->rr_flags) & (x) ? (y) : "")
18727e4823a9Schristos 		ND_PRINT((ndo,"["));	/*]*/
1873546f56c3Schristos 		if (rr6->rr_flags) {
18747e4823a9Schristos 			ND_PRINT((ndo,"%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
1875546f56c3Schristos                                   F(ICMP6_RR_FLAGS_REQRESULT, "R"),
1876546f56c3Schristos                                   F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
1877546f56c3Schristos                                   F(ICMP6_RR_FLAGS_SPECSITE, "S"),
18787e4823a9Schristos                                   F(ICMP6_RR_FLAGS_PREVDONE, "P")));
1879546f56c3Schristos 		}
18807e4823a9Schristos                 ND_PRINT((ndo,"seg=%u,", rr6->rr_segnum));
18817e4823a9Schristos                 ND_PRINT((ndo,"maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)));
1882546f56c3Schristos 		if (rr6->rr_reserved)
18837e4823a9Schristos 			ND_PRINT((ndo,"rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)));
1884546f56c3Schristos 		/*[*/
18857e4823a9Schristos 		ND_PRINT((ndo,"]"));
1886546f56c3Schristos #undef F
1887546f56c3Schristos 	}
1888546f56c3Schristos 
1889546f56c3Schristos 	if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
1890c746cb4fSchristos 		match = (const struct rr_pco_match *)cp;
1891546f56c3Schristos 		cp = (const char *)(match + 1);
1892546f56c3Schristos 
18937e4823a9Schristos 		ND_TCHECK(match->rpm_prefix);
1894546f56c3Schristos 
18957e4823a9Schristos 		if (ndo->ndo_vflag > 1)
18967e4823a9Schristos 			ND_PRINT((ndo,"\n\t"));
1897546f56c3Schristos 		else
18987e4823a9Schristos 			ND_PRINT((ndo," "));
18997e4823a9Schristos 		ND_PRINT((ndo,"match("));	/*)*/
1900546f56c3Schristos 		switch (match->rpm_code) {
19017e4823a9Schristos 		case RPM_PCO_ADD:	ND_PRINT((ndo,"add")); break;
19027e4823a9Schristos 		case RPM_PCO_CHANGE:	ND_PRINT((ndo,"change")); break;
19037e4823a9Schristos 		case RPM_PCO_SETGLOBAL:	ND_PRINT((ndo,"setglobal")); break;
19047e4823a9Schristos 		default:		ND_PRINT((ndo,"#%u", match->rpm_code)); break;
1905546f56c3Schristos 		}
1906546f56c3Schristos 
19077e4823a9Schristos 		if (ndo->ndo_vflag) {
19087e4823a9Schristos 			ND_PRINT((ndo,",ord=%u", match->rpm_ordinal));
19097e4823a9Schristos 			ND_PRINT((ndo,",min=%u", match->rpm_minlen));
19107e4823a9Schristos 			ND_PRINT((ndo,",max=%u", match->rpm_maxlen));
1911546f56c3Schristos 		}
1912c746cb4fSchristos 		if (addrtostr6(&match->rpm_prefix, hbuf, sizeof(hbuf)))
19137e4823a9Schristos 			ND_PRINT((ndo,",%s/%u", hbuf, match->rpm_matchlen));
1914546f56c3Schristos 		else
19157e4823a9Schristos 			ND_PRINT((ndo,",?/%u", match->rpm_matchlen));
1916546f56c3Schristos 		/*(*/
19177e4823a9Schristos 		ND_PRINT((ndo,")"));
1918546f56c3Schristos 
1919546f56c3Schristos 		n = match->rpm_len - 3;
1920546f56c3Schristos 		if (n % 4)
1921546f56c3Schristos 			goto trunc;
1922546f56c3Schristos 		n /= 4;
1923546f56c3Schristos 		while (n-- > 0) {
1924c746cb4fSchristos 			use = (const struct rr_pco_use *)cp;
1925546f56c3Schristos 			cp = (const char *)(use + 1);
1926546f56c3Schristos 
19277e4823a9Schristos 			ND_TCHECK(use->rpu_prefix);
1928546f56c3Schristos 
19297e4823a9Schristos 			if (ndo->ndo_vflag > 1)
19307e4823a9Schristos 				ND_PRINT((ndo,"\n\t"));
1931546f56c3Schristos 			else
19327e4823a9Schristos 				ND_PRINT((ndo," "));
19337e4823a9Schristos 			ND_PRINT((ndo,"use("));	/*)*/
1934546f56c3Schristos 			if (use->rpu_flags) {
1935546f56c3Schristos #define F(x, y)	((use->rpu_flags) & (x) ? (y) : "")
19367e4823a9Schristos 				ND_PRINT((ndo,"%s%s,",
1937546f56c3Schristos                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
19387e4823a9Schristos                                           F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")));
1939546f56c3Schristos #undef F
1940546f56c3Schristos 			}
19417e4823a9Schristos 			if (ndo->ndo_vflag) {
19427e4823a9Schristos 				ND_PRINT((ndo,"mask=0x%x,", use->rpu_ramask));
19437e4823a9Schristos 				ND_PRINT((ndo,"raflags=0x%x,", use->rpu_raflags));
1944546f56c3Schristos 				if (~use->rpu_vltime == 0)
19457e4823a9Schristos 					ND_PRINT((ndo,"vltime=infty,"));
1946546f56c3Schristos 				else
19477e4823a9Schristos 					ND_PRINT((ndo,"vltime=%u,",
19487e4823a9Schristos                                                   EXTRACT_32BITS(&use->rpu_vltime)));
1949546f56c3Schristos 				if (~use->rpu_pltime == 0)
19507e4823a9Schristos 					ND_PRINT((ndo,"pltime=infty,"));
1951546f56c3Schristos 				else
19527e4823a9Schristos 					ND_PRINT((ndo,"pltime=%u,",
19537e4823a9Schristos                                                   EXTRACT_32BITS(&use->rpu_pltime)));
1954546f56c3Schristos 			}
1955c746cb4fSchristos 			if (addrtostr6(&use->rpu_prefix, hbuf, sizeof(hbuf)))
19567e4823a9Schristos 				ND_PRINT((ndo,"%s/%u/%u", hbuf, use->rpu_uselen,
19577e4823a9Schristos                                           use->rpu_keeplen));
1958546f56c3Schristos 			else
19597e4823a9Schristos 				ND_PRINT((ndo,"?/%u/%u", use->rpu_uselen,
19607e4823a9Schristos                                           use->rpu_keeplen));
1961546f56c3Schristos 			/*(*/
19627e4823a9Schristos                         ND_PRINT((ndo,")"));
1963546f56c3Schristos 		}
1964546f56c3Schristos 	}
1965546f56c3Schristos 
1966546f56c3Schristos 	return;
1967546f56c3Schristos 
1968546f56c3Schristos trunc:
1969193b2145Schristos 	ND_PRINT((ndo, "%s", icmp6_tstr));
1970546f56c3Schristos }
1971546f56c3Schristos 
19727e4823a9Schristos /*
19737e4823a9Schristos  * Local Variables:
19747e4823a9Schristos  * c-style: whitesmith
19757e4823a9Schristos  * c-basic-offset: 8
19767e4823a9Schristos  * End:
19777e4823a9Schristos  */
1978