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