10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos */ 210f74e101Schristos 2211b3aaa1Schristos #include <sys/cdefs.h> 230f74e101Schristos #ifndef lint 24*26ba0b50Schristos __RCSID("$NetBSD: print-icmp6.c,v 1.16 2024/09/02 16:15:31 christos Exp $"); 250f74e101Schristos #endif 260f74e101Schristos 27dc860a36Sspz /* \summary: IPv6 Internet Control Message Protocol (ICMPv6) printer */ 28dc860a36Sspz 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 330f74e101Schristos #include <stdio.h> 340f74e101Schristos #include <string.h> 350f74e101Schristos 36fdccd7e4Schristos #include "netdissect.h" 370f74e101Schristos #include "addrtoname.h" 38fdccd7e4Schristos #include "addrtostr.h" 390f74e101Schristos #include "extract.h" 400f74e101Schristos 410f74e101Schristos #include "ip6.h" 420f74e101Schristos #include "ipproto.h" 430f74e101Schristos 440f74e101Schristos #include "udp.h" 450f74e101Schristos #include "ah.h" 460f74e101Schristos 47b3a00663Schristos /* NetBSD: icmp6.h,v 1.13 2000/08/03 16:30:37 itojun Exp */ 48b3a00663Schristos /* $KAME: icmp6.h,v 1.22 2000/08/03 15:25:16 jinmei Exp $ */ 49b3a00663Schristos 50b3a00663Schristos /* 51b3a00663Schristos * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 52b3a00663Schristos * All rights reserved. 53b3a00663Schristos * 54b3a00663Schristos * Redistribution and use in source and binary forms, with or without 55b3a00663Schristos * modification, are permitted provided that the following conditions 56b3a00663Schristos * are met: 57b3a00663Schristos * 1. Redistributions of source code must retain the above copyright 58b3a00663Schristos * notice, this list of conditions and the following disclaimer. 59b3a00663Schristos * 2. Redistributions in binary form must reproduce the above copyright 60b3a00663Schristos * notice, this list of conditions and the following disclaimer in the 61b3a00663Schristos * documentation and/or other materials provided with the distribution. 62b3a00663Schristos * 3. Neither the name of the project nor the names of its contributors 63b3a00663Schristos * may be used to endorse or promote products derived from this software 64b3a00663Schristos * without specific prior written permission. 65b3a00663Schristos * 66b3a00663Schristos * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 67b3a00663Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68b3a00663Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69b3a00663Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 70b3a00663Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 71b3a00663Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 72b3a00663Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 73b3a00663Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 74b3a00663Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 75b3a00663Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 76b3a00663Schristos * SUCH DAMAGE. 77b3a00663Schristos */ 78b3a00663Schristos 79b3a00663Schristos struct icmp6_hdr { 80c74ad251Schristos nd_uint8_t icmp6_type; /* type field */ 81c74ad251Schristos nd_uint8_t icmp6_code; /* code field */ 82c74ad251Schristos nd_uint16_t icmp6_cksum; /* checksum field */ 83b3a00663Schristos union { 84c74ad251Schristos nd_uint32_t icmp6_un_data32[1]; /* type-specific field */ 85c74ad251Schristos nd_uint16_t icmp6_un_data16[2]; /* type-specific field */ 86c74ad251Schristos nd_uint8_t icmp6_un_data8[4]; /* type-specific field */ 87c74ad251Schristos nd_byte icmp6_un_data[1]; /* type-specific field */ 88b3a00663Schristos } icmp6_dataun; 89c74ad251Schristos }; 90b3a00663Schristos 91b3a00663Schristos #define icmp6_data32 icmp6_dataun.icmp6_un_data32 92b3a00663Schristos #define icmp6_data16 icmp6_dataun.icmp6_un_data16 93b3a00663Schristos #define icmp6_data8 icmp6_dataun.icmp6_un_data8 94c74ad251Schristos #define icmp6_data icmp6_dataun.icmp6_un_data 95b3a00663Schristos #define icmp6_pptr icmp6_data32[0] /* parameter prob */ 96b3a00663Schristos #define icmp6_mtu icmp6_data32[0] /* packet too big */ 97b3a00663Schristos #define icmp6_id icmp6_data16[0] /* echo request/reply */ 98b3a00663Schristos #define icmp6_seq icmp6_data16[1] /* echo request/reply */ 99b3a00663Schristos #define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */ 100b3a00663Schristos 101b3a00663Schristos #define ICMP6_DST_UNREACH 1 /* dest unreachable, codes: */ 102b3a00663Schristos #define ICMP6_PACKET_TOO_BIG 2 /* packet too big */ 103b3a00663Schristos #define ICMP6_TIME_EXCEEDED 3 /* time exceeded, code: */ 104b3a00663Schristos #define ICMP6_PARAM_PROB 4 /* ip6 header bad */ 105b3a00663Schristos 106b3a00663Schristos #define ICMP6_ECHO_REQUEST 128 /* echo service */ 107b3a00663Schristos #define ICMP6_ECHO_REPLY 129 /* echo reply */ 108b3a00663Schristos #define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */ 109b3a00663Schristos #define MLD6_LISTENER_QUERY 130 /* multicast listener query */ 110b3a00663Schristos #define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */ 111b3a00663Schristos #define MLD6_LISTENER_REPORT 131 /* multicast listener report */ 112b3a00663Schristos #define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */ 113b3a00663Schristos #define MLD6_LISTENER_DONE 132 /* multicast listener done */ 114b3a00663Schristos 115b3a00663Schristos #define ND_ROUTER_SOLICIT 133 /* router solicitation */ 116b3a00663Schristos #define ND_ROUTER_ADVERT 134 /* router advertisement */ 117b3a00663Schristos #define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */ 118b3a00663Schristos #define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisement */ 119b3a00663Schristos #define ND_REDIRECT 137 /* redirect */ 120b3a00663Schristos 121b3a00663Schristos #define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */ 122b3a00663Schristos 123b3a00663Schristos #define ICMP6_WRUREQUEST 139 /* who are you request */ 124b3a00663Schristos #define ICMP6_WRUREPLY 140 /* who are you reply */ 125b3a00663Schristos #define ICMP6_FQDN_QUERY 139 /* FQDN query */ 126b3a00663Schristos #define ICMP6_FQDN_REPLY 140 /* FQDN reply */ 127c74ad251Schristos #define ICMP6_NI_QUERY 139 /* node information request - RFC 4620 */ 128c74ad251Schristos #define ICMP6_NI_REPLY 140 /* node information reply - RFC 4620 */ 129b3a00663Schristos #define IND_SOLICIT 141 /* inverse neighbor solicitation */ 130b3a00663Schristos #define IND_ADVERT 142 /* inverse neighbor advertisement */ 131b3a00663Schristos 132b3a00663Schristos #define ICMP6_V2_MEMBERSHIP_REPORT 143 /* v2 membership report */ 133b3a00663Schristos #define MLDV2_LISTENER_REPORT 143 /* v2 multicast listener report */ 134b3a00663Schristos #define ICMP6_HADISCOV_REQUEST 144 135b3a00663Schristos #define ICMP6_HADISCOV_REPLY 145 136b3a00663Schristos #define ICMP6_MOBILEPREFIX_SOLICIT 146 137b3a00663Schristos #define ICMP6_MOBILEPREFIX_ADVERT 147 138b3a00663Schristos 139b3a00663Schristos #define MLD6_MTRACE_RESP 200 /* mtrace response(to sender) */ 140b3a00663Schristos #define MLD6_MTRACE 201 /* mtrace messages */ 141b3a00663Schristos 142b3a00663Schristos #define ICMP6_MAXTYPE 201 143b3a00663Schristos 144b3a00663Schristos #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ 145b3a00663Schristos #define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */ 146b3a00663Schristos #define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 /* not a neighbor(obsolete) */ 147b3a00663Schristos #define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */ 148b3a00663Schristos #define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ 149b3a00663Schristos #define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */ 150b3a00663Schristos 151b3a00663Schristos #define ICMP6_TIME_EXCEED_TRANSIT 0 /* ttl==0 in transit */ 152b3a00663Schristos #define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* ttl==0 in reass */ 153b3a00663Schristos 154b3a00663Schristos #define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ 155b3a00663Schristos #define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized next header */ 156b3a00663Schristos #define ICMP6_PARAMPROB_OPTION 2 /* unrecognized option */ 157c74ad251Schristos #define ICMP6_PARAMPROB_FRAGHDRCHAIN 3 /* incomplete header chain */ 158b3a00663Schristos 159b3a00663Schristos #define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */ 160b3a00663Schristos 161b3a00663Schristos #define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */ 162b3a00663Schristos #define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */ 163b3a00663Schristos #define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */ 164b3a00663Schristos 165b3a00663Schristos #define ICMP6_NI_SUCCESS 0 /* node information successful reply */ 166b3a00663Schristos #define ICMP6_NI_REFUSED 1 /* node information request is refused */ 167b3a00663Schristos #define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ 168b3a00663Schristos 169b3a00663Schristos #define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */ 170b3a00663Schristos #define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */ 171b3a00663Schristos #define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 /* rr seq num reset */ 172b3a00663Schristos 173b3a00663Schristos /* Used in kernel only */ 174b3a00663Schristos #define ND_REDIRECT_ONLINK 0 /* redirect to an on-link node */ 175b3a00663Schristos #define ND_REDIRECT_ROUTER 1 /* redirect to a better router */ 176b3a00663Schristos 177b3a00663Schristos /* 178b3a00663Schristos * Multicast Listener Discovery 179b3a00663Schristos */ 180b3a00663Schristos struct mld6_hdr { 181b3a00663Schristos struct icmp6_hdr mld6_hdr; 182c74ad251Schristos nd_ipv6 mld6_addr; /* multicast address */ 183c74ad251Schristos }; 184b3a00663Schristos 185b3a00663Schristos #define mld6_type mld6_hdr.icmp6_type 186b3a00663Schristos #define mld6_code mld6_hdr.icmp6_code 187b3a00663Schristos #define mld6_cksum mld6_hdr.icmp6_cksum 188b3a00663Schristos #define mld6_maxdelay mld6_hdr.icmp6_data16[0] 189b3a00663Schristos #define mld6_reserved mld6_hdr.icmp6_data16[1] 190b3a00663Schristos 191b3a00663Schristos #define MLD_MINLEN 24 192b3a00663Schristos #define MLDV2_MINLEN 28 193b3a00663Schristos 194b3a00663Schristos /* 195b3a00663Schristos * Neighbor Discovery 196b3a00663Schristos */ 197b3a00663Schristos 198b3a00663Schristos struct nd_router_solicit { /* router solicitation */ 199b3a00663Schristos struct icmp6_hdr nd_rs_hdr; 200b3a00663Schristos /* could be followed by options */ 201c74ad251Schristos }; 202b3a00663Schristos 203b3a00663Schristos #define nd_rs_type nd_rs_hdr.icmp6_type 204b3a00663Schristos #define nd_rs_code nd_rs_hdr.icmp6_code 205b3a00663Schristos #define nd_rs_cksum nd_rs_hdr.icmp6_cksum 206b3a00663Schristos #define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] 207b3a00663Schristos 208b3a00663Schristos struct nd_router_advert { /* router advertisement */ 209b3a00663Schristos struct icmp6_hdr nd_ra_hdr; 210c74ad251Schristos nd_uint32_t nd_ra_reachable; /* reachable time */ 211c74ad251Schristos nd_uint32_t nd_ra_retransmit; /* retransmit timer */ 212b3a00663Schristos /* could be followed by options */ 213c74ad251Schristos }; 214b3a00663Schristos 215b3a00663Schristos #define nd_ra_type nd_ra_hdr.icmp6_type 216b3a00663Schristos #define nd_ra_code nd_ra_hdr.icmp6_code 217b3a00663Schristos #define nd_ra_cksum nd_ra_hdr.icmp6_cksum 218b3a00663Schristos #define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] 219b3a00663Schristos #define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] 220b3a00663Schristos #define ND_RA_FLAG_MANAGED 0x80 221b3a00663Schristos #define ND_RA_FLAG_OTHER 0x40 222b3a00663Schristos #define ND_RA_FLAG_HOME_AGENT 0x20 223c74ad251Schristos #define ND_RA_FLAG_IPV6ONLY 0x02 224b3a00663Schristos 225b3a00663Schristos /* 226b3a00663Schristos * Router preference values based on draft-draves-ipngwg-router-selection-01. 227b3a00663Schristos * These are non-standard definitions. 228b3a00663Schristos */ 229b3a00663Schristos #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 230b3a00663Schristos 231b3a00663Schristos #define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */ 232b3a00663Schristos #define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */ 233b3a00663Schristos #define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */ 234b3a00663Schristos #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ 235b3a00663Schristos 236b3a00663Schristos #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] 237b3a00663Schristos 238b3a00663Schristos struct nd_neighbor_solicit { /* neighbor solicitation */ 239b3a00663Schristos struct icmp6_hdr nd_ns_hdr; 240c74ad251Schristos nd_ipv6 nd_ns_target; /*target address */ 241b3a00663Schristos /* could be followed by options */ 242c74ad251Schristos }; 243b3a00663Schristos 244b3a00663Schristos #define nd_ns_type nd_ns_hdr.icmp6_type 245b3a00663Schristos #define nd_ns_code nd_ns_hdr.icmp6_code 246b3a00663Schristos #define nd_ns_cksum nd_ns_hdr.icmp6_cksum 247b3a00663Schristos #define nd_ns_reserved nd_ns_hdr.icmp6_data32[0] 248b3a00663Schristos 249b3a00663Schristos struct nd_neighbor_advert { /* neighbor advertisement */ 250b3a00663Schristos struct icmp6_hdr nd_na_hdr; 251c74ad251Schristos nd_ipv6 nd_na_target; /* target address */ 252b3a00663Schristos /* could be followed by options */ 253c74ad251Schristos }; 254b3a00663Schristos 255b3a00663Schristos #define nd_na_type nd_na_hdr.icmp6_type 256b3a00663Schristos #define nd_na_code nd_na_hdr.icmp6_code 257b3a00663Schristos #define nd_na_cksum nd_na_hdr.icmp6_cksum 258b3a00663Schristos #define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] 259b3a00663Schristos 260b3a00663Schristos #define ND_NA_FLAG_ROUTER 0x80000000 261b3a00663Schristos #define ND_NA_FLAG_SOLICITED 0x40000000 262b3a00663Schristos #define ND_NA_FLAG_OVERRIDE 0x20000000 263b3a00663Schristos 264b3a00663Schristos struct nd_redirect { /* redirect */ 265b3a00663Schristos struct icmp6_hdr nd_rd_hdr; 266c74ad251Schristos nd_ipv6 nd_rd_target; /* target address */ 267c74ad251Schristos nd_ipv6 nd_rd_dst; /* destination address */ 268b3a00663Schristos /* could be followed by options */ 269c74ad251Schristos }; 270b3a00663Schristos 271b3a00663Schristos #define nd_rd_type nd_rd_hdr.icmp6_type 272b3a00663Schristos #define nd_rd_code nd_rd_hdr.icmp6_code 273b3a00663Schristos #define nd_rd_cksum nd_rd_hdr.icmp6_cksum 274b3a00663Schristos #define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] 275b3a00663Schristos 276b3a00663Schristos struct nd_opt_hdr { /* Neighbor discovery option header */ 277c74ad251Schristos nd_uint8_t nd_opt_type; 278c74ad251Schristos nd_uint8_t nd_opt_len; 279b3a00663Schristos /* followed by option specific data*/ 280b3a00663Schristos }; 281b3a00663Schristos 282b3a00663Schristos #define ND_OPT_SOURCE_LINKADDR 1 283b3a00663Schristos #define ND_OPT_TARGET_LINKADDR 2 284b3a00663Schristos #define ND_OPT_PREFIX_INFORMATION 3 285b3a00663Schristos #define ND_OPT_REDIRECTED_HEADER 4 286b3a00663Schristos #define ND_OPT_MTU 5 287b3a00663Schristos #define ND_OPT_ADVINTERVAL 7 288b3a00663Schristos #define ND_OPT_HOMEAGENT_INFO 8 289b3a00663Schristos #define ND_OPT_ROUTE_INFO 24 /* RFC4191 */ 290b3a00663Schristos #define ND_OPT_RDNSS 25 291b3a00663Schristos #define ND_OPT_DNSSL 31 292b3a00663Schristos 293b3a00663Schristos struct nd_opt_prefix_info { /* prefix information */ 294dc860a36Sspz nd_uint8_t nd_opt_pi_type; 295dc860a36Sspz nd_uint8_t nd_opt_pi_len; 296dc860a36Sspz nd_uint8_t nd_opt_pi_prefix_len; 297dc860a36Sspz nd_uint8_t nd_opt_pi_flags_reserved; 298dc860a36Sspz nd_uint32_t nd_opt_pi_valid_time; 299dc860a36Sspz nd_uint32_t nd_opt_pi_preferred_time; 300dc860a36Sspz nd_uint32_t nd_opt_pi_reserved2; 301c74ad251Schristos nd_ipv6 nd_opt_pi_prefix; 302c74ad251Schristos }; 303b3a00663Schristos 304b3a00663Schristos #define ND_OPT_PI_FLAG_ONLINK 0x80 305b3a00663Schristos #define ND_OPT_PI_FLAG_AUTO 0x40 306b3a00663Schristos #define ND_OPT_PI_FLAG_ROUTER 0x20 /*2292bis*/ 307b3a00663Schristos 308b3a00663Schristos struct nd_opt_rd_hdr { /* redirected header */ 309c74ad251Schristos nd_uint8_t nd_opt_rh_type; 310c74ad251Schristos nd_uint8_t nd_opt_rh_len; 311c74ad251Schristos nd_uint16_t nd_opt_rh_reserved1; 312c74ad251Schristos nd_uint32_t nd_opt_rh_reserved2; 313b3a00663Schristos /* followed by IP header and data */ 314c74ad251Schristos }; 315b3a00663Schristos 316b3a00663Schristos struct nd_opt_mtu { /* MTU option */ 317c74ad251Schristos nd_uint8_t nd_opt_mtu_type; 318c74ad251Schristos nd_uint8_t nd_opt_mtu_len; 319c74ad251Schristos nd_uint16_t nd_opt_mtu_reserved; 320c74ad251Schristos nd_uint32_t nd_opt_mtu_mtu; 321c74ad251Schristos }; 322b3a00663Schristos 323b3a00663Schristos struct nd_opt_rdnss { /* RDNSS RFC 6106 5.1 */ 324c74ad251Schristos nd_uint8_t nd_opt_rdnss_type; 325c74ad251Schristos nd_uint8_t nd_opt_rdnss_len; 326c74ad251Schristos nd_uint16_t nd_opt_rdnss_reserved; 327c74ad251Schristos nd_uint32_t nd_opt_rdnss_lifetime; 328c74ad251Schristos nd_ipv6 nd_opt_rdnss_addr[1]; /* variable-length */ 329c74ad251Schristos }; 330b3a00663Schristos 331b3a00663Schristos struct nd_opt_dnssl { /* DNSSL RFC 6106 5.2 */ 332c74ad251Schristos nd_uint8_t nd_opt_dnssl_type; 333c74ad251Schristos nd_uint8_t nd_opt_dnssl_len; 334c74ad251Schristos nd_uint16_t nd_opt_dnssl_reserved; 335c74ad251Schristos nd_uint32_t nd_opt_dnssl_lifetime; 336b3a00663Schristos /* followed by list of DNS search domains, variable-length */ 337c74ad251Schristos }; 338b3a00663Schristos 339b3a00663Schristos struct nd_opt_advinterval { /* Advertisement interval option */ 340c74ad251Schristos nd_uint8_t nd_opt_adv_type; 341c74ad251Schristos nd_uint8_t nd_opt_adv_len; 342c74ad251Schristos nd_uint16_t nd_opt_adv_reserved; 343c74ad251Schristos nd_uint32_t nd_opt_adv_interval; 344c74ad251Schristos }; 345b3a00663Schristos 346b3a00663Schristos struct nd_opt_homeagent_info { /* Home Agent info */ 347c74ad251Schristos nd_uint8_t nd_opt_hai_type; 348c74ad251Schristos nd_uint8_t nd_opt_hai_len; 349c74ad251Schristos nd_uint16_t nd_opt_hai_reserved; 350c74ad251Schristos nd_uint16_t nd_opt_hai_preference; 351c74ad251Schristos nd_uint16_t nd_opt_hai_lifetime; 352c74ad251Schristos }; 353b3a00663Schristos 354b3a00663Schristos struct nd_opt_route_info { /* route info */ 355c74ad251Schristos nd_uint8_t nd_opt_rti_type; 356c74ad251Schristos nd_uint8_t nd_opt_rti_len; 357c74ad251Schristos nd_uint8_t nd_opt_rti_prefixlen; 358c74ad251Schristos nd_uint8_t nd_opt_rti_flags; 359c74ad251Schristos nd_uint32_t nd_opt_rti_lifetime; 360b3a00663Schristos /* prefix follows */ 361c74ad251Schristos }; 362b3a00663Schristos 363b3a00663Schristos /* 364b3a00663Schristos * icmp6 namelookup 365b3a00663Schristos */ 366b3a00663Schristos 367b3a00663Schristos struct icmp6_namelookup { 368b3a00663Schristos struct icmp6_hdr icmp6_nl_hdr; 369c74ad251Schristos nd_byte icmp6_nl_nonce[8]; 370c74ad251Schristos nd_int32_t icmp6_nl_ttl; 371b3a00663Schristos #if 0 372c74ad251Schristos nd_uint8_t icmp6_nl_len; 373c74ad251Schristos nd_byte icmp6_nl_name[3]; 374b3a00663Schristos #endif 375b3a00663Schristos /* could be followed by options */ 376c74ad251Schristos }; 377b3a00663Schristos 378b3a00663Schristos /* 379b3a00663Schristos * icmp6 node information 380b3a00663Schristos */ 381b3a00663Schristos struct icmp6_nodeinfo { 382b3a00663Schristos struct icmp6_hdr icmp6_ni_hdr; 383c74ad251Schristos nd_byte icmp6_ni_nonce[8]; 384b3a00663Schristos /* could be followed by reply data */ 385c74ad251Schristos }; 386b3a00663Schristos 387b3a00663Schristos #define ni_type icmp6_ni_hdr.icmp6_type 388b3a00663Schristos #define ni_code icmp6_ni_hdr.icmp6_code 389b3a00663Schristos #define ni_cksum icmp6_ni_hdr.icmp6_cksum 390b3a00663Schristos #define ni_qtype icmp6_ni_hdr.icmp6_data16[0] 391b3a00663Schristos #define ni_flags icmp6_ni_hdr.icmp6_data16[1] 392b3a00663Schristos 393b3a00663Schristos #define NI_QTYPE_NOOP 0 /* NOOP */ 394c74ad251Schristos #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes (drafts up to 09) */ 395b3a00663Schristos #define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ 396b3a00663Schristos #define NI_QTYPE_DNSNAME 2 /* DNS Name */ 397b3a00663Schristos #define NI_QTYPE_NODEADDR 3 /* Node Addresses */ 398b3a00663Schristos #define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ 399b3a00663Schristos 400c74ad251Schristos #define NI_NODEADDR_FLAG_TRUNCATE 0x0001 401c74ad251Schristos #define NI_NODEADDR_FLAG_ALL 0x0002 402c74ad251Schristos #define NI_NODEADDR_FLAG_COMPAT 0x0004 403c74ad251Schristos #define NI_NODEADDR_FLAG_LINKLOCAL 0x0008 404c74ad251Schristos #define NI_NODEADDR_FLAG_SITELOCAL 0x0010 405c74ad251Schristos #define NI_NODEADDR_FLAG_GLOBAL 0x0020 406c74ad251Schristos #define NI_NODEADDR_FLAG_ANYCAST 0x0040 /* just experimental. not in spec */ 407b3a00663Schristos 408b3a00663Schristos struct ni_reply_fqdn { 409c74ad251Schristos nd_uint32_t ni_fqdn_ttl; /* TTL */ 410c74ad251Schristos nd_uint8_t ni_fqdn_namelen; /* length in octets of the FQDN */ 411c74ad251Schristos nd_byte ni_fqdn_name[3]; /* XXX: alignment */ 412c74ad251Schristos }; 413b3a00663Schristos 414b3a00663Schristos /* 415b3a00663Schristos * Router Renumbering. as router-renum-08.txt 416b3a00663Schristos */ 417b3a00663Schristos struct icmp6_router_renum { /* router renumbering header */ 418b3a00663Schristos struct icmp6_hdr rr_hdr; 419c74ad251Schristos nd_uint8_t rr_segnum; 420c74ad251Schristos nd_uint8_t rr_flags; 421c74ad251Schristos nd_uint16_t rr_maxdelay; 422c74ad251Schristos nd_uint32_t rr_reserved; 423c74ad251Schristos }; 424b3a00663Schristos #define ICMP6_RR_FLAGS_TEST 0x80 425b3a00663Schristos #define ICMP6_RR_FLAGS_REQRESULT 0x40 426b3a00663Schristos #define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 427b3a00663Schristos #define ICMP6_RR_FLAGS_SPECSITE 0x10 428b3a00663Schristos #define ICMP6_RR_FLAGS_PREVDONE 0x08 429b3a00663Schristos 430b3a00663Schristos #define rr_type rr_hdr.icmp6_type 431b3a00663Schristos #define rr_code rr_hdr.icmp6_code 432b3a00663Schristos #define rr_cksum rr_hdr.icmp6_cksum 433b3a00663Schristos #define rr_seqnum rr_hdr.icmp6_data32[0] 434b3a00663Schristos 435b3a00663Schristos struct rr_pco_match { /* match prefix part */ 436c74ad251Schristos nd_uint8_t rpm_code; 437c74ad251Schristos nd_uint8_t rpm_len; 438c74ad251Schristos nd_uint8_t rpm_ordinal; 439c74ad251Schristos nd_uint8_t rpm_matchlen; 440c74ad251Schristos nd_uint8_t rpm_minlen; 441c74ad251Schristos nd_uint8_t rpm_maxlen; 442c74ad251Schristos nd_uint16_t rpm_reserved; 443c74ad251Schristos nd_ipv6 rpm_prefix; 444c74ad251Schristos }; 445b3a00663Schristos 446b3a00663Schristos #define RPM_PCO_ADD 1 447b3a00663Schristos #define RPM_PCO_CHANGE 2 448b3a00663Schristos #define RPM_PCO_SETGLOBAL 3 449b3a00663Schristos #define RPM_PCO_MAX 4 450b3a00663Schristos 451b3a00663Schristos struct rr_pco_use { /* use prefix part */ 452c74ad251Schristos nd_uint8_t rpu_uselen; 453c74ad251Schristos nd_uint8_t rpu_keeplen; 454c74ad251Schristos nd_uint8_t rpu_ramask; 455c74ad251Schristos nd_uint8_t rpu_raflags; 456c74ad251Schristos nd_uint32_t rpu_vltime; 457c74ad251Schristos nd_uint32_t rpu_pltime; 458c74ad251Schristos nd_uint32_t rpu_flags; 459c74ad251Schristos nd_ipv6 rpu_prefix; 460c74ad251Schristos }; 461b3a00663Schristos #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80 462b3a00663Schristos #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40 463b3a00663Schristos 464b3a00663Schristos /* network endian */ 465b3a00663Schristos #define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME ((uint32_t)htonl(0x80000000)) 466b3a00663Schristos #define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME ((uint32_t)htonl(0x40000000)) 467b3a00663Schristos 468b3a00663Schristos struct rr_result { /* router renumbering result message */ 469c74ad251Schristos nd_uint16_t rrr_flags; 470c74ad251Schristos nd_uint8_t rrr_ordinal; 471c74ad251Schristos nd_uint8_t rrr_matchedlen; 472c74ad251Schristos nd_uint32_t rrr_ifid; 473c74ad251Schristos nd_ipv6 rrr_prefix; 474c74ad251Schristos }; 475b3a00663Schristos /* network endian */ 476b3a00663Schristos #define ICMP6_RR_RESULT_FLAGS_OOB ((uint16_t)htons(0x0002)) 477b3a00663Schristos #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN ((uint16_t)htons(0x0001)) 478b3a00663Schristos 4790f74e101Schristos static const char *get_rtpref(u_int); 480b3a00663Schristos static const char *get_lifetime(uint32_t); 481b3a00663Schristos static void print_lladdr(netdissect_options *ndo, const u_char *, size_t); 482c74ad251Schristos static int icmp6_opt_print(netdissect_options *ndo, const u_char *, int); 483b3a00663Schristos static void mld6_print(netdissect_options *ndo, const u_char *); 484b3a00663Schristos static void mldv2_report_print(netdissect_options *ndo, const u_char *, u_int); 485b3a00663Schristos static void mldv2_query_print(netdissect_options *ndo, const u_char *, u_int); 486b3a00663Schristos static const struct udphdr *get_upperlayer(netdissect_options *ndo, const u_char *, u_int *); 487b3a00663Schristos static void dnsname_print(netdissect_options *ndo, const u_char *, const u_char *); 488b3a00663Schristos static void icmp6_nodeinfo_print(netdissect_options *ndo, u_int, const u_char *, const u_char *); 489b3a00663Schristos static void icmp6_rrenum_print(netdissect_options *ndo, const u_char *, const u_char *); 4900f74e101Schristos 491c74ad251Schristos /* 492c74ad251Schristos * DIO: Updated to RFC6550, as published in 2012: section 6. (page 30) 493c74ad251Schristos */ 4940f74e101Schristos 495c74ad251Schristos #define ND_RPL_MESSAGE 155 /* 0x9B */ 496c74ad251Schristos 497c74ad251Schristos enum ND_RPL_CODE { 498c74ad251Schristos ND_RPL_DAG_IS=0x00, 499c74ad251Schristos ND_RPL_DAG_IO=0x01, 500c74ad251Schristos ND_RPL_DAO =0x02, 501c74ad251Schristos ND_RPL_DAO_ACK=0x03, 502c74ad251Schristos ND_RPL_SEC_DAG_IS = 0x80, 503c74ad251Schristos ND_RPL_SEC_DAG_IO = 0x81, 504c74ad251Schristos ND_RPL_SEC_DAG = 0x82, 505c74ad251Schristos ND_RPL_SEC_DAG_ACK= 0x83, 506c74ad251Schristos ND_RPL_SEC_CONSIST= 0x8A 507c74ad251Schristos }; 508c74ad251Schristos 509c74ad251Schristos enum ND_RPL_DIO_FLAGS { 510c74ad251Schristos ND_RPL_DIO_GROUNDED = 0x80, 511c74ad251Schristos ND_RPL_DIO_DATRIG = 0x40, 512c74ad251Schristos ND_RPL_DIO_DASUPPORT= 0x20, 513c74ad251Schristos ND_RPL_DIO_RES4 = 0x10, 514c74ad251Schristos ND_RPL_DIO_RES3 = 0x08, 515c74ad251Schristos ND_RPL_DIO_PRF_MASK = 0x07 /* 3-bit preference */ 516c74ad251Schristos }; 517c74ad251Schristos 518c74ad251Schristos #define DAGID_LEN 16 519c74ad251Schristos 520c74ad251Schristos /* section 6 of draft-ietf-roll-rpl-19 */ 521c74ad251Schristos struct nd_rpl_security { 522c74ad251Schristos nd_uint8_t rpl_sec_t_reserved; /* bit 7 is T-bit */ 523c74ad251Schristos nd_uint8_t rpl_sec_algo; 524c74ad251Schristos nd_uint16_t rpl_sec_kim_lvl_flags; /* bit 15/14, KIM */ 525c74ad251Schristos /* bit 10-8, LVL, bit 7-0 flags */ 526c74ad251Schristos nd_uint32_t rpl_sec_counter; 527c74ad251Schristos #if 0 528c74ad251Schristos nd_byte rpl_sec_ki[0]; /* depends upon kim */ 529c74ad251Schristos #endif 530c74ad251Schristos }; 531c74ad251Schristos 532*26ba0b50Schristos /* section 6.2.1, DODAG Information Solicitation (DIS_IS) */ 533c74ad251Schristos struct nd_rpl_dis_is { 534c74ad251Schristos nd_uint8_t rpl_dis_flags; 535c74ad251Schristos nd_uint8_t rpl_dis_reserved; 536c74ad251Schristos #if 0 537c74ad251Schristos nd_byte rpl_dis_options[0]; 538c74ad251Schristos #endif 539c74ad251Schristos }; 540c74ad251Schristos 541c74ad251Schristos /* section 6.3.1, DODAG Information Object (DIO) */ 542c74ad251Schristos struct nd_rpl_dio { 543c74ad251Schristos nd_uint8_t rpl_instanceid; 544c74ad251Schristos nd_uint8_t rpl_version; 545c74ad251Schristos nd_uint16_t rpl_dagrank; 546c74ad251Schristos nd_uint8_t rpl_mopprf; /* bit 7=G, 5-3=MOP, 2-0=PRF */ 547c74ad251Schristos nd_uint8_t rpl_dtsn; /* Dest. Advertisement Trigger Sequence Number */ 548c74ad251Schristos nd_uint8_t rpl_flags; /* no flags defined yet */ 549c74ad251Schristos nd_uint8_t rpl_resv1; 550c74ad251Schristos nd_byte rpl_dagid[DAGID_LEN]; 551c74ad251Schristos }; 552c74ad251Schristos #define RPL_DIO_GROUND_FLAG 0x80 553c74ad251Schristos #define RPL_DIO_MOP_SHIFT 3 554c74ad251Schristos #define RPL_DIO_MOP_MASK (7 << RPL_DIO_MOP_SHIFT) 555c74ad251Schristos #define RPL_DIO_PRF_SHIFT 0 556c74ad251Schristos #define RPL_DIO_PRF_MASK (7 << RPL_DIO_PRF_SHIFT) 557c74ad251Schristos #define RPL_DIO_GROUNDED(X) ((X)&RPL_DIO_GROUND_FLAG) 558c74ad251Schristos #define RPL_DIO_MOP(X) (enum RPL_DIO_MOP)(((X)&RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT) 559c74ad251Schristos #define RPL_DIO_PRF(X) (((X)&RPL_DIO_PRF_MASK) >> RPL_DIO_PRF_SHIFT) 560c74ad251Schristos 561c74ad251Schristos enum RPL_DIO_MOP { 562c74ad251Schristos RPL_DIO_NONSTORING= 0x0, 563c74ad251Schristos RPL_DIO_STORING = 0x1, 564c74ad251Schristos RPL_DIO_NONSTORING_MULTICAST = 0x2, 565c74ad251Schristos RPL_DIO_STORING_MULTICAST = 0x3 566c74ad251Schristos }; 567c74ad251Schristos 568c74ad251Schristos enum RPL_SUBOPT { 569c74ad251Schristos RPL_OPT_PAD1 = 0, 570c74ad251Schristos RPL_OPT_PADN = 1, 571c74ad251Schristos RPL_DIO_METRICS = 2, 572c74ad251Schristos RPL_DIO_ROUTINGINFO = 3, 573c74ad251Schristos RPL_DIO_CONFIG = 4, 574c74ad251Schristos RPL_DAO_RPLTARGET = 5, 575c74ad251Schristos RPL_DAO_TRANSITINFO = 6, 576c74ad251Schristos RPL_DIO_DESTPREFIX = 8, 577c74ad251Schristos RPL_DAO_RPLTARGET_DESC=9 578c74ad251Schristos }; 579c74ad251Schristos 580c74ad251Schristos struct rpl_genoption { 581c74ad251Schristos nd_uint8_t rpl_dio_type; 582c74ad251Schristos nd_uint8_t rpl_dio_len; /* suboption length, not including type/len */ 583c74ad251Schristos }; 584c74ad251Schristos #define RPL_GENOPTION_LEN 2 585c74ad251Schristos 586c74ad251Schristos #define RPL_DIO_LIFETIME_INFINITE 0xffffffff 587c74ad251Schristos #define RPL_DIO_LIFETIME_DISCONNECT 0 588c74ad251Schristos 589c74ad251Schristos struct rpl_dio_destprefix { 590c74ad251Schristos nd_uint8_t rpl_dio_type; 591c74ad251Schristos nd_uint8_t rpl_dio_len; 592c74ad251Schristos nd_uint8_t rpl_dio_prefixlen; /* in bits */ 593c74ad251Schristos nd_uint8_t rpl_dio_prf; /* flags, including Route Preference */ 594c74ad251Schristos nd_uint32_t rpl_dio_prefixlifetime; /* in seconds */ 595c74ad251Schristos #if 0 596c74ad251Schristos nd_byte rpl_dio_prefix[0]; /* variable number of bytes */ 597c74ad251Schristos #endif 598c74ad251Schristos }; 599c74ad251Schristos 600c74ad251Schristos /* section 6.4.1, DODAG Information Object (DIO) */ 601c74ad251Schristos struct nd_rpl_dao { 602c74ad251Schristos nd_uint8_t rpl_instanceid; 603c74ad251Schristos nd_uint8_t rpl_flags; /* bit 7=K, 6=D */ 604c74ad251Schristos nd_uint8_t rpl_resv; 605c74ad251Schristos nd_uint8_t rpl_daoseq; 606c74ad251Schristos nd_byte rpl_dagid[DAGID_LEN]; /* present when D set. */ 607c74ad251Schristos }; 608c74ad251Schristos #define ND_RPL_DAO_MIN_LEN 4 /* length without DAGID */ 609c74ad251Schristos 610c74ad251Schristos /* indicates if this DAO is to be acK'ed */ 611c74ad251Schristos #define RPL_DAO_K_SHIFT 7 612c74ad251Schristos #define RPL_DAO_K_MASK (1 << RPL_DAO_K_SHIFT) 613c74ad251Schristos #define RPL_DAO_K(X) (((X)&RPL_DAO_K_MASK) >> RPL_DAO_K_SHIFT) 614c74ad251Schristos 615c74ad251Schristos /* indicates if the DAGID is present */ 616c74ad251Schristos #define RPL_DAO_D_SHIFT 6 617c74ad251Schristos #define RPL_DAO_D_MASK (1 << RPL_DAO_D_SHIFT) 618c74ad251Schristos #define RPL_DAO_D(X) (((X)&RPL_DAO_D_MASK) >> RPL_DAO_D_SHIFT) 619c74ad251Schristos 620c74ad251Schristos struct rpl_dao_target { 621c74ad251Schristos nd_uint8_t rpl_dao_type; 622c74ad251Schristos nd_uint8_t rpl_dao_len; 623c74ad251Schristos nd_uint8_t rpl_dao_flags; /* unused */ 624c74ad251Schristos nd_uint8_t rpl_dao_prefixlen; /* in bits */ 625c74ad251Schristos #if 0 626c74ad251Schristos nd_byte rpl_dao_prefix[0]; /* variable number of bytes */ 627c74ad251Schristos #endif 628c74ad251Schristos }; 629c74ad251Schristos 630c74ad251Schristos /* section 6.5.1, Destination Advertisement Object Acknowledgement (DAO-ACK) */ 631c74ad251Schristos struct nd_rpl_daoack { 632c74ad251Schristos nd_uint8_t rpl_instanceid; 633c74ad251Schristos nd_uint8_t rpl_flags; /* bit 7=D */ 634c74ad251Schristos nd_uint8_t rpl_daoseq; 635c74ad251Schristos nd_uint8_t rpl_status; 636c74ad251Schristos nd_byte rpl_dagid[DAGID_LEN]; /* present when D set. */ 637c74ad251Schristos }; 638c74ad251Schristos #define ND_RPL_DAOACK_MIN_LEN 4 /* length without DAGID */ 639c74ad251Schristos /* indicates if the DAGID is present */ 640c74ad251Schristos #define RPL_DAOACK_D_SHIFT 7 641c74ad251Schristos #define RPL_DAOACK_D_MASK (1 << RPL_DAOACK_D_SHIFT) 642c74ad251Schristos #define RPL_DAOACK_D(X) (((X)&RPL_DAOACK_D_MASK) >> RPL_DAOACK_D_SHIFT) 6430f74e101Schristos 644870189d2Schristos static const struct tok icmp6_type_values[] = { 6450f74e101Schristos { ICMP6_DST_UNREACH, "destination unreachable"}, 6460f74e101Schristos { ICMP6_PACKET_TOO_BIG, "packet too big"}, 6470f74e101Schristos { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 6480f74e101Schristos { ICMP6_PARAM_PROB, "parameter problem"}, 6490f74e101Schristos { ICMP6_ECHO_REQUEST, "echo request"}, 6500f74e101Schristos { ICMP6_ECHO_REPLY, "echo reply"}, 6510f74e101Schristos { MLD6_LISTENER_QUERY, "multicast listener query"}, 6520f74e101Schristos { MLD6_LISTENER_REPORT, "multicast listener report"}, 6530f74e101Schristos { MLD6_LISTENER_DONE, "multicast listener done"}, 6540f74e101Schristos { ND_ROUTER_SOLICIT, "router solicitation"}, 6550f74e101Schristos { ND_ROUTER_ADVERT, "router advertisement"}, 6560f74e101Schristos { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 6570f74e101Schristos { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, 6580f74e101Schristos { ND_REDIRECT, "redirect"}, 6590f74e101Schristos { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 6600f74e101Schristos { IND_SOLICIT, "inverse neighbor solicitation"}, 6610f74e101Schristos { IND_ADVERT, "inverse neighbor advertisement"}, 6620f74e101Schristos { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 6630f74e101Schristos { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 6640f74e101Schristos { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 6650f74e101Schristos { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 6660f74e101Schristos { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 6670f74e101Schristos { ICMP6_WRUREQUEST, "who-are-you request"}, 6680f74e101Schristos { ICMP6_WRUREPLY, "who-are-you reply"}, 6690f74e101Schristos { ICMP6_NI_QUERY, "node information query"}, 6700f74e101Schristos { ICMP6_NI_REPLY, "node information reply"}, 6710f74e101Schristos { MLD6_MTRACE, "mtrace message"}, 6720f74e101Schristos { MLD6_MTRACE_RESP, "mtrace response"}, 6730f74e101Schristos { ND_RPL_MESSAGE, "RPL"}, 6740f74e101Schristos { 0, NULL } 6750f74e101Schristos }; 6760f74e101Schristos 677870189d2Schristos static const struct tok icmp6_dst_unreach_code_values[] = { 6780f74e101Schristos { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 6790f74e101Schristos { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 6800f74e101Schristos { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 6810f74e101Schristos { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 6820f74e101Schristos { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 6830f74e101Schristos { 0, NULL } 6840f74e101Schristos }; 6850f74e101Schristos 686870189d2Schristos static const struct tok icmp6_opt_pi_flag_values[] = { 6870f74e101Schristos { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 6880f74e101Schristos { ND_OPT_PI_FLAG_AUTO, "auto" }, 6890f74e101Schristos { ND_OPT_PI_FLAG_ROUTER, "router" }, 6900f74e101Schristos { 0, NULL } 6910f74e101Schristos }; 6920f74e101Schristos 693870189d2Schristos static const struct tok icmp6_opt_ra_flag_values[] = { 6940f74e101Schristos { ND_RA_FLAG_MANAGED, "managed" }, 6950f74e101Schristos { ND_RA_FLAG_OTHER, "other stateful"}, 6960f74e101Schristos { ND_RA_FLAG_HOME_AGENT, "home agent"}, 697c74ad251Schristos { ND_RA_FLAG_IPV6ONLY, "ipv6 only"}, 6980f74e101Schristos { 0, NULL } 6990f74e101Schristos }; 7000f74e101Schristos 701870189d2Schristos static const struct tok icmp6_nd_na_flag_values[] = { 7020f74e101Schristos { ND_NA_FLAG_ROUTER, "router" }, 7030f74e101Schristos { ND_NA_FLAG_SOLICITED, "solicited" }, 7040f74e101Schristos { ND_NA_FLAG_OVERRIDE, "override" }, 7050f74e101Schristos { 0, NULL } 7060f74e101Schristos }; 7070f74e101Schristos 708870189d2Schristos static const struct tok icmp6_opt_values[] = { 7090f74e101Schristos { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 7100f74e101Schristos { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 7110f74e101Schristos { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 7120f74e101Schristos { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 7130f74e101Schristos { ND_OPT_MTU, "mtu"}, 7140f74e101Schristos { ND_OPT_RDNSS, "rdnss"}, 715870189d2Schristos { ND_OPT_DNSSL, "dnssl"}, 7160f74e101Schristos { ND_OPT_ADVINTERVAL, "advertisement interval"}, 7170f74e101Schristos { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 7180f74e101Schristos { ND_OPT_ROUTE_INFO, "route info"}, 7190f74e101Schristos { 0, NULL } 7200f74e101Schristos }; 7210f74e101Schristos 7220f74e101Schristos /* mldv2 report types */ 723870189d2Schristos static const struct tok mldv2report2str[] = { 7240f74e101Schristos { 1, "is_in" }, 7250f74e101Schristos { 2, "is_ex" }, 7260f74e101Schristos { 3, "to_in" }, 7270f74e101Schristos { 4, "to_ex" }, 7280f74e101Schristos { 5, "allow" }, 7290f74e101Schristos { 6, "block" }, 7300f74e101Schristos { 0, NULL } 7310f74e101Schristos }; 7320f74e101Schristos 7330f74e101Schristos static const char * 7340f74e101Schristos get_rtpref(u_int v) 7350f74e101Schristos { 7360f74e101Schristos static const char *rtpref_str[] = { 7370f74e101Schristos "medium", /* 00 */ 7380f74e101Schristos "high", /* 01 */ 7390f74e101Schristos "rsv", /* 10 */ 7400f74e101Schristos "low" /* 11 */ 7410f74e101Schristos }; 7420f74e101Schristos 7430f74e101Schristos return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 7440f74e101Schristos } 7450f74e101Schristos 7460f74e101Schristos static const char * 747b3a00663Schristos get_lifetime(uint32_t v) 7480f74e101Schristos { 7490f74e101Schristos static char buf[20]; 7500f74e101Schristos 751b3a00663Schristos if (v == (uint32_t)~0UL) 7520f74e101Schristos return "infinity"; 7530f74e101Schristos else { 754870189d2Schristos snprintf(buf, sizeof(buf), "%us", v); 7550f74e101Schristos return buf; 7560f74e101Schristos } 7570f74e101Schristos } 7580f74e101Schristos 7590f74e101Schristos static void 760b3a00663Schristos print_lladdr(netdissect_options *ndo, const uint8_t *p, size_t l) 7610f74e101Schristos { 762b3a00663Schristos const uint8_t *ep, *q; 7630f74e101Schristos 7640f74e101Schristos q = p; 7650f74e101Schristos ep = p + l; 7660f74e101Schristos while (l > 0 && q < ep) { 7670f74e101Schristos if (q > p) 768c74ad251Schristos ND_PRINT(":"); 769c74ad251Schristos ND_PRINT("%02x", GET_U_1(q)); 770c74ad251Schristos q++; 7710f74e101Schristos l--; 7720f74e101Schristos } 7730f74e101Schristos } 7740f74e101Schristos 775c74ad251Schristos static uint16_t icmp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6, 776fdccd7e4Schristos const struct icmp6_hdr *icp, u_int len) 7770f74e101Schristos { 778fdccd7e4Schristos return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)icp, len, len, 779b3a00663Schristos IPPROTO_ICMPV6); 7800f74e101Schristos } 7810f74e101Schristos 782dc860a36Sspz static const struct tok rpl_mop_values[] = { 783b3a00663Schristos { RPL_DIO_NONSTORING, "nonstoring"}, 784b3a00663Schristos { RPL_DIO_STORING, "storing"}, 785b3a00663Schristos { RPL_DIO_NONSTORING_MULTICAST, "nonstoring-multicast"}, 786b3a00663Schristos { RPL_DIO_STORING_MULTICAST, "storing-multicast"}, 787b3a00663Schristos { 0, NULL}, 7880f74e101Schristos }; 7890f74e101Schristos 790dc860a36Sspz static const struct tok rpl_subopt_values[] = { 791c74ad251Schristos { RPL_OPT_PAD1, "pad1"}, 792b3a00663Schristos { RPL_OPT_PADN, "padN"}, 793b3a00663Schristos { RPL_DIO_METRICS, "metrics"}, 794b3a00663Schristos { RPL_DIO_ROUTINGINFO, "routinginfo"}, 795b3a00663Schristos { RPL_DIO_CONFIG, "config"}, 796b3a00663Schristos { RPL_DAO_RPLTARGET, "rpltarget"}, 797b3a00663Schristos { RPL_DAO_TRANSITINFO, "transitinfo"}, 798b3a00663Schristos { RPL_DIO_DESTPREFIX, "destprefix"}, 799b3a00663Schristos { RPL_DAO_RPLTARGET_DESC, "rpltargetdesc"}, 800b3a00663Schristos { 0, NULL}, 8010f74e101Schristos }; 8020f74e101Schristos 803b3a00663Schristos static void 804c74ad251Schristos rpl_printopts(netdissect_options *ndo, const uint8_t *opts, u_int length) 805b3a00663Schristos { 806c74ad251Schristos const struct rpl_genoption *opt; 807c74ad251Schristos uint8_t dio_type; 808c74ad251Schristos u_int optlen; 809b3a00663Schristos 810c74ad251Schristos while (length != 0) { 811c74ad251Schristos opt = (const struct rpl_genoption *)opts; 812c74ad251Schristos dio_type = GET_U_1(opt->rpl_dio_type); 813c74ad251Schristos if (dio_type == RPL_OPT_PAD1) { 814b3a00663Schristos optlen = 1; 815c74ad251Schristos ND_PRINT(" opt:pad1"); 816b3a00663Schristos } else { 817c74ad251Schristos if (length < RPL_GENOPTION_LEN) 818c74ad251Schristos goto trunc; 819c74ad251Schristos optlen = GET_U_1(opt->rpl_dio_len)+RPL_GENOPTION_LEN; 820c74ad251Schristos ND_PRINT(" opt:%s len:%u ", 821c74ad251Schristos tok2str(rpl_subopt_values, "subopt:%u", dio_type), 822c74ad251Schristos optlen); 823c74ad251Schristos ND_TCHECK_LEN(opt, optlen); 824c74ad251Schristos if (length < optlen) 825c74ad251Schristos goto trunc; 826b3a00663Schristos if (ndo->ndo_vflag > 2) { 827b3a00663Schristos hex_print(ndo, 828b3a00663Schristos " ", 829c74ad251Schristos opts + RPL_GENOPTION_LEN, /* content of DIO option */ 830c74ad251Schristos optlen - RPL_GENOPTION_LEN); 831b3a00663Schristos } 832b3a00663Schristos } 833c74ad251Schristos opts += optlen; 834b3a00663Schristos length -= optlen; 835b3a00663Schristos } 836b3a00663Schristos return; 837b3a00663Schristos trunc: 838c74ad251Schristos nd_print_trunc(ndo); 839b3a00663Schristos } 840b3a00663Schristos 841b3a00663Schristos static void 842b3a00663Schristos rpl_dio_print(netdissect_options *ndo, 843b3a00663Schristos const u_char *bp, u_int length) 844b3a00663Schristos { 845fdccd7e4Schristos const struct nd_rpl_dio *dio = (const struct nd_rpl_dio *)bp; 846b3a00663Schristos 847*26ba0b50Schristos ND_ICHECK_ZU(length, <, sizeof(struct nd_rpl_dio)); 848c74ad251Schristos ND_PRINT(" [dagid:%s,seq:%u,instance:%u,rank:%u,%smop:%s,prf:%u]", 849c74ad251Schristos GET_IP6ADDR_STRING(dio->rpl_dagid), 850c74ad251Schristos GET_U_1(dio->rpl_dtsn), 851c74ad251Schristos GET_U_1(dio->rpl_instanceid), 852c74ad251Schristos GET_BE_U_2(dio->rpl_dagrank), 853c74ad251Schristos RPL_DIO_GROUNDED(GET_U_1(dio->rpl_mopprf)) ? "grounded,":"", 854c74ad251Schristos tok2str(rpl_mop_values, "mop%u", 855c74ad251Schristos RPL_DIO_MOP(GET_U_1(dio->rpl_mopprf))), 856c74ad251Schristos RPL_DIO_PRF(GET_U_1(dio->rpl_mopprf))); 857b3a00663Schristos 858b3a00663Schristos if(ndo->ndo_vflag > 1) { 859c74ad251Schristos rpl_printopts(ndo, bp + sizeof(struct nd_rpl_dio), 860c74ad251Schristos length - sizeof(struct nd_rpl_dio)); 861b3a00663Schristos } 862b3a00663Schristos return; 863c74ad251Schristos invalid: 864c74ad251Schristos nd_print_invalid(ndo); 865b3a00663Schristos } 866b3a00663Schristos 867b3a00663Schristos static void 868b3a00663Schristos rpl_dao_print(netdissect_options *ndo, 869b3a00663Schristos const u_char *bp, u_int length) 870b3a00663Schristos { 871fdccd7e4Schristos const struct nd_rpl_dao *dao = (const struct nd_rpl_dao *)bp; 872fdccd7e4Schristos const char *dagid_str = "<elided>"; 873c74ad251Schristos uint8_t rpl_flags; 874b3a00663Schristos 875c74ad251Schristos ND_TCHECK_SIZE(dao); 876b3a00663Schristos if (length < ND_RPL_DAO_MIN_LEN) 877b3a00663Schristos goto tooshort; 878b3a00663Schristos 879b3a00663Schristos bp += ND_RPL_DAO_MIN_LEN; 880b3a00663Schristos length -= ND_RPL_DAO_MIN_LEN; 881c74ad251Schristos rpl_flags = GET_U_1(dao->rpl_flags); 882c74ad251Schristos if(RPL_DAO_D(rpl_flags)) { 883c74ad251Schristos ND_TCHECK_LEN(dao->rpl_dagid, DAGID_LEN); 884b3a00663Schristos if (length < DAGID_LEN) 885b3a00663Schristos goto tooshort; 886fdccd7e4Schristos dagid_str = ip6addr_string (ndo, dao->rpl_dagid); 887b3a00663Schristos bp += DAGID_LEN; 888b3a00663Schristos length -= DAGID_LEN; 889b3a00663Schristos } 890b3a00663Schristos 891c74ad251Schristos ND_PRINT(" [dagid:%s,seq:%u,instance:%u%s%s,flags:%02x]", 892b3a00663Schristos dagid_str, 893c74ad251Schristos GET_U_1(dao->rpl_daoseq), 894c74ad251Schristos GET_U_1(dao->rpl_instanceid), 895c74ad251Schristos RPL_DAO_K(rpl_flags) ? ",acK":"", 896c74ad251Schristos RPL_DAO_D(rpl_flags) ? ",Dagid":"", 897c74ad251Schristos rpl_flags); 898b3a00663Schristos 899b3a00663Schristos if(ndo->ndo_vflag > 1) { 900c74ad251Schristos rpl_printopts(ndo, bp, length); 901b3a00663Schristos } 902b3a00663Schristos return; 903b3a00663Schristos 904b3a00663Schristos trunc: 905c74ad251Schristos nd_print_trunc(ndo); 906b3a00663Schristos return; 907b3a00663Schristos 908b3a00663Schristos tooshort: 909c74ad251Schristos ND_PRINT(" [|length too short]"); 910b3a00663Schristos } 911b3a00663Schristos 912b3a00663Schristos static void 913b3a00663Schristos rpl_daoack_print(netdissect_options *ndo, 914b3a00663Schristos const u_char *bp, u_int length) 915b3a00663Schristos { 916fdccd7e4Schristos const struct nd_rpl_daoack *daoack = (const struct nd_rpl_daoack *)bp; 917fdccd7e4Schristos const char *dagid_str = "<elided>"; 918b3a00663Schristos 919c74ad251Schristos ND_TCHECK_LEN(daoack, ND_RPL_DAOACK_MIN_LEN); 920b3a00663Schristos if (length < ND_RPL_DAOACK_MIN_LEN) 921b3a00663Schristos goto tooshort; 922b3a00663Schristos 923b3a00663Schristos bp += ND_RPL_DAOACK_MIN_LEN; 924b3a00663Schristos length -= ND_RPL_DAOACK_MIN_LEN; 925c74ad251Schristos if(RPL_DAOACK_D(GET_U_1(daoack->rpl_flags))) { 926c74ad251Schristos ND_TCHECK_LEN(daoack->rpl_dagid, DAGID_LEN); 927b3a00663Schristos if (length < DAGID_LEN) 928b3a00663Schristos goto tooshort; 929fdccd7e4Schristos dagid_str = ip6addr_string (ndo, daoack->rpl_dagid); 930b3a00663Schristos bp += DAGID_LEN; 931b3a00663Schristos length -= DAGID_LEN; 932b3a00663Schristos } 933b3a00663Schristos 934c74ad251Schristos ND_PRINT(" [dagid:%s,seq:%u,instance:%u,status:%u]", 935b3a00663Schristos dagid_str, 936c74ad251Schristos GET_U_1(daoack->rpl_daoseq), 937c74ad251Schristos GET_U_1(daoack->rpl_instanceid), 938c74ad251Schristos GET_U_1(daoack->rpl_status)); 939b3a00663Schristos 940b3a00663Schristos /* no officially defined options for DAOACK, but print any we find */ 941b3a00663Schristos if(ndo->ndo_vflag > 1) { 942c74ad251Schristos rpl_printopts(ndo, bp, length); 943b3a00663Schristos } 944b3a00663Schristos return; 945b3a00663Schristos 946b3a00663Schristos trunc: 947c74ad251Schristos nd_print_trunc(ndo); 948b3a00663Schristos return; 949b3a00663Schristos 950b3a00663Schristos tooshort: 951c74ad251Schristos ND_PRINT(" [|dao-length too short]"); 952b3a00663Schristos } 9530f74e101Schristos 954a8e08e94Skamil UNALIGNED_OK 9550f74e101Schristos static void 9560f74e101Schristos rpl_print(netdissect_options *ndo, 957c74ad251Schristos uint8_t icmp6_code, 958b3a00663Schristos const u_char *bp, u_int length) 9590f74e101Schristos { 960c74ad251Schristos int secured = icmp6_code & 0x80; 961c74ad251Schristos int basecode= icmp6_code & 0x7f; 9620f74e101Schristos 9630e9868baSchristos if(secured) { 964c74ad251Schristos ND_PRINT(", (SEC) [worktodo]"); 965b3a00663Schristos /* XXX 966b3a00663Schristos * the next header pointer needs to move forward to 967b3a00663Schristos * skip the secure part. 968b3a00663Schristos */ 969b3a00663Schristos return; 9700e9868baSchristos } else { 971c74ad251Schristos ND_PRINT(", (CLR)"); 9720e9868baSchristos } 9730e9868baSchristos 9740e9868baSchristos switch(basecode) { 975b3a00663Schristos case ND_RPL_DAG_IS: 976c74ad251Schristos ND_PRINT("DODAG Information Solicitation"); 9770f74e101Schristos if(ndo->ndo_vflag) { 9780f74e101Schristos } 9790f74e101Schristos break; 980b3a00663Schristos case ND_RPL_DAG_IO: 981c74ad251Schristos ND_PRINT("DODAG Information Object"); 9820f74e101Schristos if(ndo->ndo_vflag) { 983b3a00663Schristos rpl_dio_print(ndo, bp, length); 9840f74e101Schristos } 9850f74e101Schristos break; 9860f74e101Schristos case ND_RPL_DAO: 987c74ad251Schristos ND_PRINT("Destination Advertisement Object"); 9880e9868baSchristos if(ndo->ndo_vflag) { 989b3a00663Schristos rpl_dao_print(ndo, bp, length); 9900e9868baSchristos } 9910e9868baSchristos break; 9920e9868baSchristos case ND_RPL_DAO_ACK: 993c74ad251Schristos ND_PRINT("Destination Advertisement Object Ack"); 9940f74e101Schristos if(ndo->ndo_vflag) { 995b3a00663Schristos rpl_daoack_print(ndo, bp, length); 9960f74e101Schristos } 9970f74e101Schristos break; 9980f74e101Schristos default: 999c74ad251Schristos ND_PRINT("RPL message, unknown code %u",icmp6_code); 10000f74e101Schristos break; 10010f74e101Schristos } 10020f74e101Schristos return; 1003b3a00663Schristos 1004b3a00663Schristos #if 0 10050f74e101Schristos trunc: 1006c74ad251Schristos nd_print_trunc(ndo); 10070f74e101Schristos return; 1008b3a00663Schristos #endif 10090f74e101Schristos 10100f74e101Schristos } 10110f74e101Schristos 10120f74e101Schristos void 10130f74e101Schristos icmp6_print(netdissect_options *ndo, 10140f74e101Schristos const u_char *bp, u_int length, const u_char *bp2, int fragmented) 10150f74e101Schristos { 10160f74e101Schristos const struct icmp6_hdr *dp; 1017c74ad251Schristos uint8_t icmp6_type, icmp6_code; 10180f74e101Schristos const struct ip6_hdr *ip; 10190f74e101Schristos const struct ip6_hdr *oip; 10200f74e101Schristos const struct udphdr *ouh; 1021c74ad251Schristos uint16_t dport; 10220f74e101Schristos const u_char *ep; 10230f74e101Schristos u_int prot; 10240f74e101Schristos 1025c74ad251Schristos ndo->ndo_protocol = "icmp6"; 1026fdccd7e4Schristos dp = (const struct icmp6_hdr *)bp; 1027fdccd7e4Schristos ip = (const struct ip6_hdr *)bp2; 1028fdccd7e4Schristos oip = (const struct ip6_hdr *)(dp + 1); 10290f74e101Schristos /* 'ep' points to the end of available data. */ 1030b3a00663Schristos ep = ndo->ndo_snapend; 1031c74ad251Schristos if (length == 0) { 1032c74ad251Schristos ND_PRINT("ICMP6, length 0"); 1033c74ad251Schristos nd_print_invalid(ndo); 1034c74ad251Schristos return; 1035c74ad251Schristos } 10360f74e101Schristos 1037b3a00663Schristos if (ndo->ndo_vflag && !fragmented) { 1038b3a00663Schristos uint16_t sum, udp_sum; 10390f74e101Schristos 1040c74ad251Schristos if (ND_TTEST_LEN(bp, length)) { 1041c74ad251Schristos udp_sum = GET_BE_U_2(dp->icmp6_cksum); 1042fdccd7e4Schristos sum = icmp6_cksum(ndo, ip, dp, length); 10430f74e101Schristos if (sum != 0) 1044c74ad251Schristos ND_PRINT("[bad icmp6 cksum 0x%04x -> 0x%04x!] ", 10450e9868baSchristos udp_sum, 1046c74ad251Schristos in_cksum_shouldbe(udp_sum, sum)); 10470f74e101Schristos else 1048c74ad251Schristos ND_PRINT("[icmp6 sum ok] "); 10490f74e101Schristos } 10500f74e101Schristos } 10510f74e101Schristos 1052c74ad251Schristos icmp6_type = GET_U_1(dp->icmp6_type); 1053c74ad251Schristos ND_PRINT("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",icmp6_type)); 10540f74e101Schristos 10550f74e101Schristos /* display cosmetics: print the packet length for printer that use the vflag now */ 1056c74ad251Schristos if (ndo->ndo_vflag && (icmp6_type == ND_ROUTER_SOLICIT || 1057c74ad251Schristos icmp6_type == ND_ROUTER_ADVERT || 1058c74ad251Schristos icmp6_type == ND_NEIGHBOR_ADVERT || 1059c74ad251Schristos icmp6_type == ND_NEIGHBOR_SOLICIT || 1060c74ad251Schristos icmp6_type == ND_REDIRECT || 1061c74ad251Schristos icmp6_type == ICMP6_HADISCOV_REPLY || 1062c74ad251Schristos icmp6_type == ICMP6_MOBILEPREFIX_ADVERT )) 1063c74ad251Schristos ND_PRINT(", length %u", length); 10640f74e101Schristos 1065c74ad251Schristos icmp6_code = GET_U_1(dp->icmp6_code); 1066c74ad251Schristos 1067c74ad251Schristos switch (icmp6_type) { 10680f74e101Schristos case ICMP6_DST_UNREACH: 1069c74ad251Schristos ND_PRINT(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",icmp6_code)); 1070c74ad251Schristos switch (icmp6_code) { 10710f74e101Schristos 10720f74e101Schristos case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 10730f74e101Schristos case ICMP6_DST_UNREACH_ADMIN: 10740f74e101Schristos case ICMP6_DST_UNREACH_ADDR: 1075c74ad251Schristos ND_PRINT(" %s",GET_IP6ADDR_STRING(oip->ip6_dst)); 10760f74e101Schristos break; 10770f74e101Schristos case ICMP6_DST_UNREACH_BEYONDSCOPE: 1078c74ad251Schristos ND_PRINT(" %s, source address %s", 1079c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_dst), 1080c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_src)); 10810f74e101Schristos break; 10820f74e101Schristos case ICMP6_DST_UNREACH_NOPORT: 1083fdccd7e4Schristos if ((ouh = get_upperlayer(ndo, (const u_char *)oip, &prot)) 10840f74e101Schristos == NULL) 10850f74e101Schristos goto trunc; 10860f74e101Schristos 1087c74ad251Schristos dport = GET_BE_U_2(ouh->uh_dport); 10880f74e101Schristos switch (prot) { 10890f74e101Schristos case IPPROTO_TCP: 1090c74ad251Schristos ND_PRINT(", %s tcp port %s", 1091c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_dst), 1092c74ad251Schristos tcpport_string(ndo, dport)); 10930f74e101Schristos break; 10940f74e101Schristos case IPPROTO_UDP: 1095c74ad251Schristos ND_PRINT(", %s udp port %s", 1096c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_dst), 1097c74ad251Schristos udpport_string(ndo, dport)); 10980f74e101Schristos break; 10990f74e101Schristos default: 1100c74ad251Schristos ND_PRINT(", %s protocol %u port %u unreachable", 1101c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_dst), 1102c74ad251Schristos prot, dport); 11030f74e101Schristos break; 11040f74e101Schristos } 11050f74e101Schristos break; 11060f74e101Schristos default: 1107b3a00663Schristos if (ndo->ndo_vflag <= 1) { 1108b3a00663Schristos print_unknown_data(ndo, bp,"\n\t",length); 11090f74e101Schristos return; 11100f74e101Schristos } 11110f74e101Schristos break; 11120f74e101Schristos } 11130f74e101Schristos break; 11140f74e101Schristos case ICMP6_PACKET_TOO_BIG: 1115c74ad251Schristos ND_PRINT(", mtu %u", GET_BE_U_4(dp->icmp6_mtu)); 11160f74e101Schristos break; 11170f74e101Schristos case ICMP6_TIME_EXCEEDED: 1118c74ad251Schristos switch (icmp6_code) { 11190f74e101Schristos case ICMP6_TIME_EXCEED_TRANSIT: 1120c74ad251Schristos ND_PRINT(" for %s", 1121c74ad251Schristos GET_IP6ADDR_STRING(oip->ip6_dst)); 11220f74e101Schristos break; 11230f74e101Schristos case ICMP6_TIME_EXCEED_REASSEMBLY: 1124c74ad251Schristos ND_PRINT(" (reassembly)"); 11250f74e101Schristos break; 11260f74e101Schristos default: 1127c74ad251Schristos ND_PRINT(", unknown code (%u)", icmp6_code); 11280f74e101Schristos break; 11290f74e101Schristos } 11300f74e101Schristos break; 11310f74e101Schristos case ICMP6_PARAM_PROB: 1132c74ad251Schristos ND_TCHECK_16(oip->ip6_dst); 1133c74ad251Schristos switch (icmp6_code) { 11340f74e101Schristos case ICMP6_PARAMPROB_HEADER: 1135c74ad251Schristos ND_PRINT(", erroneous - octet %u", 1136c74ad251Schristos GET_BE_U_4(dp->icmp6_pptr)); 11370f74e101Schristos break; 11380f74e101Schristos case ICMP6_PARAMPROB_NEXTHEADER: 1139c74ad251Schristos ND_PRINT(", next header - octet %u", 1140c74ad251Schristos GET_BE_U_4(dp->icmp6_pptr)); 11410f74e101Schristos break; 11420f74e101Schristos case ICMP6_PARAMPROB_OPTION: 1143c74ad251Schristos ND_PRINT(", option - octet %u", 1144c74ad251Schristos GET_BE_U_4(dp->icmp6_pptr)); 1145c74ad251Schristos break; 1146c74ad251Schristos case ICMP6_PARAMPROB_FRAGHDRCHAIN: 1147c74ad251Schristos ND_PRINT(", incomplete header chain - octet %u", 1148c74ad251Schristos GET_BE_U_4(dp->icmp6_pptr)); 11490f74e101Schristos break; 11500f74e101Schristos default: 1151c74ad251Schristos ND_PRINT(", code-#%u", 1152c74ad251Schristos icmp6_code); 11530f74e101Schristos break; 11540f74e101Schristos } 11550f74e101Schristos break; 11560f74e101Schristos case ICMP6_ECHO_REQUEST: 11570f74e101Schristos case ICMP6_ECHO_REPLY: 1158c74ad251Schristos ND_PRINT(", id %u, seq %u", GET_BE_U_2(dp->icmp6_id), 1159c74ad251Schristos GET_BE_U_2(dp->icmp6_seq)); 11600f74e101Schristos break; 11610f74e101Schristos case ICMP6_MEMBERSHIP_QUERY: 11620f74e101Schristos if (length == MLD_MINLEN) { 1163b3a00663Schristos mld6_print(ndo, (const u_char *)dp); 11640f74e101Schristos } else if (length >= MLDV2_MINLEN) { 1165c74ad251Schristos ND_PRINT(" v2"); 1166b3a00663Schristos mldv2_query_print(ndo, (const u_char *)dp, length); 11670f74e101Schristos } else { 1168c74ad251Schristos ND_PRINT(" unknown-version (len %u) ", length); 11690f74e101Schristos } 11700f74e101Schristos break; 11710f74e101Schristos case ICMP6_MEMBERSHIP_REPORT: 1172b3a00663Schristos mld6_print(ndo, (const u_char *)dp); 11730f74e101Schristos break; 11740f74e101Schristos case ICMP6_MEMBERSHIP_REDUCTION: 1175b3a00663Schristos mld6_print(ndo, (const u_char *)dp); 11760f74e101Schristos break; 11770f74e101Schristos case ND_ROUTER_SOLICIT: 11780f74e101Schristos #define RTSOLLEN 8 1179b3a00663Schristos if (ndo->ndo_vflag) { 1180c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + RTSOLLEN, 1181c74ad251Schristos length - RTSOLLEN) == -1) 1182c74ad251Schristos goto trunc; 11830f74e101Schristos } 11840f74e101Schristos break; 11850f74e101Schristos case ND_ROUTER_ADVERT: 11860f74e101Schristos #define RTADVLEN 16 1187b3a00663Schristos if (ndo->ndo_vflag) { 1188fdccd7e4Schristos const struct nd_router_advert *p; 11890f74e101Schristos 1190fdccd7e4Schristos p = (const struct nd_router_advert *)dp; 1191c74ad251Schristos ND_PRINT("\n\thop limit %u, Flags [%s]" 1192817e9a7eSchristos ", pref %s, router lifetime %us, reachable time %ums, retrans timer %ums", 1193c74ad251Schristos GET_U_1(p->nd_ra_curhoplimit), 1194c74ad251Schristos bittok2str(icmp6_opt_ra_flag_values,"none",GET_U_1(p->nd_ra_flags_reserved)), 1195c74ad251Schristos get_rtpref(GET_U_1(p->nd_ra_flags_reserved)), 1196c74ad251Schristos GET_BE_U_2(p->nd_ra_router_lifetime), 1197c74ad251Schristos GET_BE_U_4(p->nd_ra_reachable), 1198c74ad251Schristos GET_BE_U_4(p->nd_ra_retransmit)); 11990f74e101Schristos 1200c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + RTADVLEN, 1201c74ad251Schristos length - RTADVLEN) == -1) 1202c74ad251Schristos goto trunc; 12030f74e101Schristos } 12040f74e101Schristos break; 12050f74e101Schristos case ND_NEIGHBOR_SOLICIT: 12060f74e101Schristos { 1207fdccd7e4Schristos const struct nd_neighbor_solicit *p; 1208fdccd7e4Schristos p = (const struct nd_neighbor_solicit *)dp; 1209c74ad251Schristos ND_PRINT(", who has %s", GET_IP6ADDR_STRING(p->nd_ns_target)); 1210b3a00663Schristos if (ndo->ndo_vflag) { 12110f74e101Schristos #define NDSOLLEN 24 1212c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + NDSOLLEN, 1213c74ad251Schristos length - NDSOLLEN) == -1) 1214c74ad251Schristos goto trunc; 12150f74e101Schristos } 12160f74e101Schristos } 12170f74e101Schristos break; 12180f74e101Schristos case ND_NEIGHBOR_ADVERT: 12190f74e101Schristos { 1220fdccd7e4Schristos const struct nd_neighbor_advert *p; 12210f74e101Schristos 1222fdccd7e4Schristos p = (const struct nd_neighbor_advert *)dp; 1223c74ad251Schristos ND_PRINT(", tgt is %s", 1224c74ad251Schristos GET_IP6ADDR_STRING(p->nd_na_target)); 1225b3a00663Schristos if (ndo->ndo_vflag) { 1226c74ad251Schristos ND_PRINT(", Flags [%s]", 12270f74e101Schristos bittok2str(icmp6_nd_na_flag_values, 12280f74e101Schristos "none", 1229c74ad251Schristos GET_BE_U_4(p->nd_na_flags_reserved))); 12300f74e101Schristos #define NDADVLEN 24 1231c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + NDADVLEN, 1232c74ad251Schristos length - NDADVLEN) == -1) 1233c74ad251Schristos goto trunc; 12340f74e101Schristos #undef NDADVLEN 12350f74e101Schristos } 12360f74e101Schristos } 12370f74e101Schristos break; 12380f74e101Schristos case ND_REDIRECT: 1239c74ad251Schristos { 1240c74ad251Schristos const struct nd_redirect *p; 1241c74ad251Schristos 1242c74ad251Schristos p = (const struct nd_redirect *)dp; 1243c74ad251Schristos ND_PRINT(", %s", GET_IP6ADDR_STRING(p->nd_rd_dst)); 1244c74ad251Schristos ND_PRINT(" to %s", GET_IP6ADDR_STRING(p->nd_rd_target)); 12450f74e101Schristos #define REDIRECTLEN 40 1246b3a00663Schristos if (ndo->ndo_vflag) { 1247c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + REDIRECTLEN, 1248c74ad251Schristos length - REDIRECTLEN) == -1) 1249c74ad251Schristos goto trunc; 1250c74ad251Schristos #undef REDIRECTLEN 1251c74ad251Schristos } 12520f74e101Schristos } 12530f74e101Schristos break; 12540f74e101Schristos case ICMP6_ROUTER_RENUMBERING: 1255b3a00663Schristos icmp6_rrenum_print(ndo, bp, ep); 12560f74e101Schristos break; 12570f74e101Schristos case ICMP6_NI_QUERY: 12580f74e101Schristos case ICMP6_NI_REPLY: 1259b3a00663Schristos icmp6_nodeinfo_print(ndo, length, bp, ep); 12600f74e101Schristos break; 12610f74e101Schristos case IND_SOLICIT: 12620f74e101Schristos case IND_ADVERT: 12630f74e101Schristos break; 12640f74e101Schristos case ICMP6_V2_MEMBERSHIP_REPORT: 1265b3a00663Schristos mldv2_report_print(ndo, (const u_char *) dp, length); 12660f74e101Schristos break; 12670f74e101Schristos case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 12680f74e101Schristos case ICMP6_HADISCOV_REQUEST: 1269c74ad251Schristos ND_PRINT(", id 0x%04x", GET_BE_U_2(dp->icmp6_data16[0])); 12700f74e101Schristos break; 12710f74e101Schristos case ICMP6_HADISCOV_REPLY: 1272b3a00663Schristos if (ndo->ndo_vflag) { 1273fdccd7e4Schristos const u_char *cp; 1274c74ad251Schristos const u_char *p; 12750f74e101Schristos 1276c74ad251Schristos ND_PRINT(", id 0x%04x", 1277c74ad251Schristos GET_BE_U_2(dp->icmp6_data16[0])); 1278*26ba0b50Schristos cp = (const u_char *)dp + 1279*26ba0b50Schristos ND_MIN(length, ND_BYTES_AVAILABLE_AFTER(dp)); 1280c74ad251Schristos p = (const u_char *)(dp + 1); 1281c74ad251Schristos while (p < cp) { 1282c74ad251Schristos ND_PRINT(", %s", GET_IP6ADDR_STRING(p)); 1283c74ad251Schristos p += 16; 12840f74e101Schristos } 12850f74e101Schristos } 12860f74e101Schristos break; 12870f74e101Schristos case ICMP6_MOBILEPREFIX_ADVERT: 1288b3a00663Schristos if (ndo->ndo_vflag) { 1289c74ad251Schristos uint16_t flags; 1290c74ad251Schristos 1291c74ad251Schristos ND_PRINT(", id 0x%04x", 1292c74ad251Schristos GET_BE_U_2(dp->icmp6_data16[0])); 1293c74ad251Schristos flags = GET_BE_U_2(dp->icmp6_data16[1]); 1294c74ad251Schristos if (flags & 0xc000) 1295c74ad251Schristos ND_PRINT(" "); 1296c74ad251Schristos if (flags & 0x8000) 1297c74ad251Schristos ND_PRINT("M"); 1298c74ad251Schristos if (flags & 0x4000) 1299c74ad251Schristos ND_PRINT("O"); 13000f74e101Schristos #define MPADVLEN 8 1301c74ad251Schristos if (icmp6_opt_print(ndo, (const u_char *)dp + MPADVLEN, 1302c74ad251Schristos length - MPADVLEN) == -1) 1303c74ad251Schristos goto trunc; 13040f74e101Schristos } 13050f74e101Schristos break; 13060f74e101Schristos case ND_RPL_MESSAGE: 1307b3a00663Schristos /* plus 4, because struct icmp6_hdr contains 4 bytes of icmp payload */ 1308c74ad251Schristos rpl_print(ndo, icmp6_code, dp->icmp6_data, length-sizeof(struct icmp6_hdr)+4); 13090f74e101Schristos break; 13100f74e101Schristos default: 1311c74ad251Schristos ND_PRINT(", length %u", length); 1312b3a00663Schristos if (ndo->ndo_vflag <= 1) 1313b3a00663Schristos print_unknown_data(ndo, bp,"\n\t", length); 13140f74e101Schristos return; 13150f74e101Schristos } 1316b3a00663Schristos if (!ndo->ndo_vflag) 1317c74ad251Schristos ND_PRINT(", length %u", length); 13180f74e101Schristos return; 13190f74e101Schristos trunc: 1320c74ad251Schristos nd_print_trunc(ndo); 13210f74e101Schristos } 13220f74e101Schristos 1323b3a00663Schristos static const struct udphdr * 1324b3a00663Schristos get_upperlayer(netdissect_options *ndo, const u_char *bp, u_int *prot) 13250f74e101Schristos { 13260f74e101Schristos const u_char *ep; 1327fdccd7e4Schristos const struct ip6_hdr *ip6 = (const struct ip6_hdr *)bp; 1328b3a00663Schristos const struct udphdr *uh; 1329b3a00663Schristos const struct ip6_hbh *hbh; 1330b3a00663Schristos const struct ip6_frag *fragh; 1331b3a00663Schristos const struct ah *ah; 13320f74e101Schristos u_int nh; 13330f74e101Schristos int hlen; 13340f74e101Schristos 13350f74e101Schristos /* 'ep' points to the end of available data. */ 1336b3a00663Schristos ep = ndo->ndo_snapend; 13370f74e101Schristos 1338c74ad251Schristos if (!ND_TTEST_1(ip6->ip6_nxt)) 13390f74e101Schristos return NULL; 13400f74e101Schristos 1341c74ad251Schristos nh = GET_U_1(ip6->ip6_nxt); 13420f74e101Schristos hlen = sizeof(struct ip6_hdr); 13430f74e101Schristos 13440f74e101Schristos while (bp < ep) { 13450f74e101Schristos bp += hlen; 13460f74e101Schristos 13470f74e101Schristos switch(nh) { 13480f74e101Schristos case IPPROTO_UDP: 13490f74e101Schristos case IPPROTO_TCP: 1350fdccd7e4Schristos uh = (const struct udphdr *)bp; 1351c74ad251Schristos if (ND_TTEST_2(uh->uh_dport)) { 13520f74e101Schristos *prot = nh; 13530f74e101Schristos return(uh); 1354*26ba0b50Schristos } else 13550f74e101Schristos return(NULL); 13560f74e101Schristos /* NOTREACHED */ 13570f74e101Schristos 13580f74e101Schristos case IPPROTO_HOPOPTS: 13590f74e101Schristos case IPPROTO_DSTOPTS: 13600f74e101Schristos case IPPROTO_ROUTING: 1361fdccd7e4Schristos hbh = (const struct ip6_hbh *)bp; 1362c74ad251Schristos if (!ND_TTEST_1(hbh->ip6h_len)) 13630f74e101Schristos return(NULL); 1364c74ad251Schristos nh = GET_U_1(hbh->ip6h_nxt); 1365c74ad251Schristos hlen = (GET_U_1(hbh->ip6h_len) + 1) << 3; 13660f74e101Schristos break; 13670f74e101Schristos 13680f74e101Schristos case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 1369fdccd7e4Schristos fragh = (const struct ip6_frag *)bp; 1370c74ad251Schristos if (!ND_TTEST_2(fragh->ip6f_offlg)) 13710f74e101Schristos return(NULL); 13720f74e101Schristos /* fragments with non-zero offset are meaningless */ 1373c74ad251Schristos if ((GET_BE_U_2(fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 13740f74e101Schristos return(NULL); 1375c74ad251Schristos nh = GET_U_1(fragh->ip6f_nxt); 13760f74e101Schristos hlen = sizeof(struct ip6_frag); 13770f74e101Schristos break; 13780f74e101Schristos 13790f74e101Schristos case IPPROTO_AH: 1380fdccd7e4Schristos ah = (const struct ah *)bp; 1381c74ad251Schristos if (!ND_TTEST_1(ah->ah_len)) 13820f74e101Schristos return(NULL); 1383c74ad251Schristos nh = GET_U_1(ah->ah_nxt); 1384c74ad251Schristos hlen = (GET_U_1(ah->ah_len) + 2) << 2; 13850f74e101Schristos break; 13860f74e101Schristos 13870f74e101Schristos default: /* unknown or undecodable header */ 13880f74e101Schristos *prot = nh; /* meaningless, but set here anyway */ 13890f74e101Schristos return(NULL); 13900f74e101Schristos } 13910f74e101Schristos } 13920f74e101Schristos 13930f74e101Schristos return(NULL); /* should be notreached, though */ 13940f74e101Schristos } 13950f74e101Schristos 1396c74ad251Schristos static int 1397b3a00663Schristos icmp6_opt_print(netdissect_options *ndo, const u_char *bp, int resid) 13980f74e101Schristos { 13990f74e101Schristos const struct nd_opt_hdr *op; 1400c74ad251Schristos uint8_t opt_type; 1401c74ad251Schristos u_int opt_len; 14020f74e101Schristos const struct nd_opt_prefix_info *opp; 14030f74e101Schristos const struct nd_opt_mtu *opm; 14040f74e101Schristos const struct nd_opt_rdnss *oprd; 1405870189d2Schristos const struct nd_opt_dnssl *opds; 14060f74e101Schristos const struct nd_opt_advinterval *opa; 14070f74e101Schristos const struct nd_opt_homeagent_info *oph; 14080f74e101Schristos const struct nd_opt_route_info *opri; 1409870189d2Schristos const u_char *cp, *ep, *domp; 1410c74ad251Schristos nd_ipv6 in6; 14110f74e101Schristos size_t l; 14120f74e101Schristos u_int i; 14130f74e101Schristos 14140f74e101Schristos cp = bp; 14150f74e101Schristos /* 'ep' points to the end of available data. */ 1416b3a00663Schristos ep = ndo->ndo_snapend; 14170f74e101Schristos 14180f74e101Schristos while (cp < ep) { 1419fdccd7e4Schristos op = (const struct nd_opt_hdr *)cp; 14200f74e101Schristos 1421c74ad251Schristos ND_TCHECK_1(op->nd_opt_len); 14220f74e101Schristos if (resid <= 0) 1423c74ad251Schristos return 0; 1424c74ad251Schristos opt_type = GET_U_1(op->nd_opt_type); 1425c74ad251Schristos opt_len = GET_U_1(op->nd_opt_len); 1426c74ad251Schristos if (opt_len == 0) 14270f74e101Schristos goto trunc; 1428c74ad251Schristos if (cp + (opt_len << 3) > ep) 14290f74e101Schristos goto trunc; 14300f74e101Schristos 1431c74ad251Schristos ND_PRINT("\n\t %s option (%u), length %u (%u): ", 1432c74ad251Schristos tok2str(icmp6_opt_values, "unknown", opt_type), 1433c74ad251Schristos opt_type, 1434c74ad251Schristos opt_len << 3, 1435c74ad251Schristos opt_len); 14360f74e101Schristos 1437c74ad251Schristos switch (opt_type) { 14380f74e101Schristos case ND_OPT_SOURCE_LINKADDR: 1439c74ad251Schristos l = (opt_len << 3) - 2; 1440b3a00663Schristos print_lladdr(ndo, cp + 2, l); 14410f74e101Schristos break; 14420f74e101Schristos case ND_OPT_TARGET_LINKADDR: 1443c74ad251Schristos l = (opt_len << 3) - 2; 1444b3a00663Schristos print_lladdr(ndo, cp + 2, l); 14450f74e101Schristos break; 14460f74e101Schristos case ND_OPT_PREFIX_INFORMATION: 1447fdccd7e4Schristos opp = (const struct nd_opt_prefix_info *)op; 1448c74ad251Schristos ND_PRINT("%s/%u%s, Flags [%s], valid time %s", 1449c74ad251Schristos GET_IP6ADDR_STRING(opp->nd_opt_pi_prefix), 1450c74ad251Schristos GET_U_1(opp->nd_opt_pi_prefix_len), 1451c74ad251Schristos (opt_len != 4) ? "badlen" : "", 1452c74ad251Schristos bittok2str(icmp6_opt_pi_flag_values, "none", GET_U_1(opp->nd_opt_pi_flags_reserved)), 1453c74ad251Schristos get_lifetime(GET_BE_U_4(opp->nd_opt_pi_valid_time))); 1454c74ad251Schristos ND_PRINT(", pref. time %s", 1455c74ad251Schristos get_lifetime(GET_BE_U_4(opp->nd_opt_pi_preferred_time))); 14560f74e101Schristos break; 14570f74e101Schristos case ND_OPT_REDIRECTED_HEADER: 1458c74ad251Schristos print_unknown_data(ndo, bp,"\n\t ",opt_len<<3); 14590f74e101Schristos /* xxx */ 14600f74e101Schristos break; 14610f74e101Schristos case ND_OPT_MTU: 1462fdccd7e4Schristos opm = (const struct nd_opt_mtu *)op; 1463c74ad251Schristos ND_PRINT(" %u%s", 1464c74ad251Schristos GET_BE_U_4(opm->nd_opt_mtu_mtu), 1465c74ad251Schristos (opt_len != 1) ? "bad option length" : "" ); 14660f74e101Schristos break; 14670f74e101Schristos case ND_OPT_RDNSS: 1468fdccd7e4Schristos oprd = (const struct nd_opt_rdnss *)op; 1469c74ad251Schristos l = (opt_len - 1) / 2; 1470c74ad251Schristos ND_PRINT(" lifetime %us,", 1471c74ad251Schristos GET_BE_U_4(oprd->nd_opt_rdnss_lifetime)); 14720f74e101Schristos for (i = 0; i < l; i++) { 1473c74ad251Schristos ND_PRINT(" addr: %s", 1474c74ad251Schristos GET_IP6ADDR_STRING(oprd->nd_opt_rdnss_addr[i])); 14750f74e101Schristos } 14760f74e101Schristos break; 1477870189d2Schristos case ND_OPT_DNSSL: 1478fdccd7e4Schristos opds = (const struct nd_opt_dnssl *)op; 1479c74ad251Schristos ND_PRINT(" lifetime %us, domain(s):", 1480c74ad251Schristos GET_BE_U_4(opds->nd_opt_dnssl_lifetime)); 1481870189d2Schristos domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */ 1482*26ba0b50Schristos while (domp < cp + (opt_len << 3) && GET_U_1(domp) != '\0') { 1483c74ad251Schristos ND_PRINT(" "); 1484c74ad251Schristos if ((domp = fqdn_print(ndo, domp, bp)) == NULL) 1485870189d2Schristos goto trunc; 1486870189d2Schristos } 1487870189d2Schristos break; 14880f74e101Schristos case ND_OPT_ADVINTERVAL: 1489fdccd7e4Schristos opa = (const struct nd_opt_advinterval *)op; 1490c74ad251Schristos ND_PRINT(" %ums", 1491c74ad251Schristos GET_BE_U_4(opa->nd_opt_adv_interval)); 14920f74e101Schristos break; 14930f74e101Schristos case ND_OPT_HOMEAGENT_INFO: 1494fdccd7e4Schristos oph = (const struct nd_opt_homeagent_info *)op; 1495c74ad251Schristos ND_PRINT(" preference %u, lifetime %u", 1496c74ad251Schristos GET_BE_U_2(oph->nd_opt_hai_preference), 1497c74ad251Schristos GET_BE_U_2(oph->nd_opt_hai_lifetime)); 14980f74e101Schristos break; 14990f74e101Schristos case ND_OPT_ROUTE_INFO: 1500fdccd7e4Schristos opri = (const struct nd_opt_route_info *)op; 1501c74ad251Schristos ND_TCHECK_4(opri->nd_opt_rti_lifetime); 15020f74e101Schristos memset(&in6, 0, sizeof(in6)); 1503c74ad251Schristos switch (opt_len) { 15040f74e101Schristos case 1: 15050f74e101Schristos break; 15060f74e101Schristos case 2: 1507c74ad251Schristos GET_CPY_BYTES(&in6, opri + 1, 8); 15080f74e101Schristos break; 15090f74e101Schristos case 3: 1510c74ad251Schristos GET_CPY_BYTES(&in6, opri + 1, 16); 15110f74e101Schristos break; 15120f74e101Schristos default: 15130f74e101Schristos goto trunc; 15140f74e101Schristos } 1515c74ad251Schristos ND_PRINT(" %s/%u", ip6addr_string(ndo, (const u_char *)&in6), /* local buffer, not packet data; don't use GET_IP6ADDR_STRING() */ 1516c74ad251Schristos GET_U_1(opri->nd_opt_rti_prefixlen)); 1517c74ad251Schristos ND_PRINT(", pref=%s", 1518c74ad251Schristos get_rtpref(GET_U_1(opri->nd_opt_rti_flags))); 1519c74ad251Schristos ND_PRINT(", lifetime=%s", 1520c74ad251Schristos get_lifetime(GET_BE_U_4(opri->nd_opt_rti_lifetime))); 15210f74e101Schristos break; 15220f74e101Schristos default: 1523b3a00663Schristos if (ndo->ndo_vflag <= 1) { 1524c74ad251Schristos print_unknown_data(ndo,cp+2,"\n\t ", (opt_len << 3) - 2); /* skip option header */ 1525c74ad251Schristos return 0; 15260f74e101Schristos } 15270f74e101Schristos break; 15280f74e101Schristos } 15290f74e101Schristos /* do we want to see an additional hexdump ? */ 1530b3a00663Schristos if (ndo->ndo_vflag> 1) 1531c74ad251Schristos print_unknown_data(ndo, cp+2,"\n\t ", (opt_len << 3) - 2); /* skip option header */ 15320f74e101Schristos 1533c74ad251Schristos cp += opt_len << 3; 1534c74ad251Schristos resid -= opt_len << 3; 15350f74e101Schristos } 1536c74ad251Schristos return 0; 15370f74e101Schristos 15380f74e101Schristos trunc: 1539c74ad251Schristos return -1; 15400f74e101Schristos } 15410f74e101Schristos 1542a8e08e94Skamil UNALIGNED_OK 15430f74e101Schristos static void 1544b3a00663Schristos mld6_print(netdissect_options *ndo, const u_char *bp) 15450f74e101Schristos { 1546fdccd7e4Schristos const struct mld6_hdr *mp = (const struct mld6_hdr *)bp; 15470f74e101Schristos const u_char *ep; 15480f74e101Schristos 15490f74e101Schristos /* 'ep' points to the end of available data. */ 1550b3a00663Schristos ep = ndo->ndo_snapend; 15510f74e101Schristos 1552fdccd7e4Schristos if ((const u_char *)mp + sizeof(*mp) > ep) 15530f74e101Schristos return; 15540f74e101Schristos 1555c74ad251Schristos ND_PRINT("max resp delay: %u ", GET_BE_U_2(mp->mld6_maxdelay)); 1556c74ad251Schristos ND_PRINT("addr: %s", GET_IP6ADDR_STRING(mp->mld6_addr)); 15570f74e101Schristos } 15580f74e101Schristos 1559a8e08e94Skamil UNALIGNED_OK 15600f74e101Schristos static void 1561b3a00663Schristos mldv2_report_print(netdissect_options *ndo, const u_char *bp, u_int len) 15620f74e101Schristos { 1563fdccd7e4Schristos const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp; 15640f74e101Schristos u_int group, nsrcs, ngroups; 15650f74e101Schristos u_int i, j; 15660f74e101Schristos 15670f74e101Schristos /* Minimum len is 8 */ 15680f74e101Schristos if (len < 8) { 1569c74ad251Schristos ND_PRINT(" [invalid len %u]", len); 15700f74e101Schristos return; 15710f74e101Schristos } 15720f74e101Schristos 1573c74ad251Schristos ngroups = GET_BE_U_2(icp->icmp6_data16[1]); 1574c74ad251Schristos ND_PRINT(", %u group record(s)", ngroups); 1575b3a00663Schristos if (ndo->ndo_vflag > 0) { 15760f74e101Schristos /* Print the group records */ 15770f74e101Schristos group = 8; 15780f74e101Schristos for (i = 0; i < ngroups; i++) { 15790f74e101Schristos /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 15800f74e101Schristos if (len < group + 20) { 1581c74ad251Schristos ND_PRINT(" [invalid number of groups]"); 15820f74e101Schristos return; 15830f74e101Schristos } 1584c74ad251Schristos ND_PRINT(" [gaddr %s", GET_IP6ADDR_STRING(bp + group + 4)); 1585c74ad251Schristos ND_PRINT(" %s", tok2str(mldv2report2str, " [v2-report-#%u]", 1586c74ad251Schristos GET_U_1(bp + group))); 1587c74ad251Schristos nsrcs = GET_BE_U_2(bp + group + 2); 15880f74e101Schristos /* Check the number of sources and print them */ 1589c74ad251Schristos if (len < group + 20 + (nsrcs * sizeof(nd_ipv6))) { 1590c74ad251Schristos ND_PRINT(" [invalid number of sources %u]", nsrcs); 15910f74e101Schristos return; 15920f74e101Schristos } 1593b3a00663Schristos if (ndo->ndo_vflag == 1) 1594c74ad251Schristos ND_PRINT(", %u source(s)", nsrcs); 15950f74e101Schristos else { 15960f74e101Schristos /* Print the sources */ 1597c74ad251Schristos ND_PRINT(" {"); 15980f74e101Schristos for (j = 0; j < nsrcs; j++) { 1599c74ad251Schristos ND_PRINT(" %s", GET_IP6ADDR_STRING(bp + group + 20 + (j * sizeof(nd_ipv6)))); 16000f74e101Schristos } 1601c74ad251Schristos ND_PRINT(" }"); 16020f74e101Schristos } 16030f74e101Schristos /* Next group record */ 1604c74ad251Schristos group += 20 + nsrcs * sizeof(nd_ipv6); 1605c74ad251Schristos ND_PRINT("]"); 16060f74e101Schristos } 16070f74e101Schristos } 16080f74e101Schristos } 16090f74e101Schristos 1610a8e08e94Skamil UNALIGNED_OK 16110f74e101Schristos static void 1612b3a00663Schristos mldv2_query_print(netdissect_options *ndo, const u_char *bp, u_int len) 16130f74e101Schristos { 1614fdccd7e4Schristos const struct icmp6_hdr *icp = (const struct icmp6_hdr *) bp; 16150f74e101Schristos u_int mrc; 1616c74ad251Schristos u_int mrt, qqi; 16170f74e101Schristos u_int nsrcs; 1618c74ad251Schristos u_int i; 16190f74e101Schristos 16200f74e101Schristos /* Minimum len is 28 */ 16210f74e101Schristos if (len < 28) { 1622c74ad251Schristos ND_PRINT(" [invalid len %u]", len); 16230f74e101Schristos return; 16240f74e101Schristos } 1625c74ad251Schristos mrc = GET_BE_U_2(icp->icmp6_data16[0]); 16260f74e101Schristos if (mrc < 32768) { 16270f74e101Schristos mrt = mrc; 16280f74e101Schristos } else { 16290f74e101Schristos mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 16300f74e101Schristos } 1631b3a00663Schristos if (ndo->ndo_vflag) { 1632c74ad251Schristos ND_PRINT(" [max resp delay=%u]", mrt); 16330f74e101Schristos } 1634c74ad251Schristos ND_PRINT(" [gaddr %s", GET_IP6ADDR_STRING(bp + 8)); 16350f74e101Schristos 1636b3a00663Schristos if (ndo->ndo_vflag) { 1637c74ad251Schristos if (GET_U_1(bp + 24) & 0x08) { 1638c74ad251Schristos ND_PRINT(" sflag"); 16390f74e101Schristos } 1640c74ad251Schristos if (GET_U_1(bp + 24) & 0x07) { 1641c74ad251Schristos ND_PRINT(" robustness=%u", GET_U_1(bp + 24) & 0x07); 16420f74e101Schristos } 1643c74ad251Schristos if (GET_U_1(bp + 25) < 128) { 1644c74ad251Schristos qqi = GET_U_1(bp + 25); 16450f74e101Schristos } else { 1646c74ad251Schristos qqi = ((GET_U_1(bp + 25) & 0x0f) | 0x10) << 1647c74ad251Schristos (((GET_U_1(bp + 25) & 0x70) >> 4) + 3); 16480f74e101Schristos } 1649c74ad251Schristos ND_PRINT(" qqi=%u", qqi); 16500f74e101Schristos } 16510f74e101Schristos 1652c74ad251Schristos nsrcs = GET_BE_U_2(bp + 26); 16530f74e101Schristos if (nsrcs > 0) { 1654c74ad251Schristos if (len < 28 + nsrcs * sizeof(nd_ipv6)) 1655c74ad251Schristos ND_PRINT(" [invalid number of sources]"); 1656b3a00663Schristos else if (ndo->ndo_vflag > 1) { 1657c74ad251Schristos ND_PRINT(" {"); 16580f74e101Schristos for (i = 0; i < nsrcs; i++) { 1659c74ad251Schristos ND_PRINT(" %s", GET_IP6ADDR_STRING(bp + 28 + (i * sizeof(nd_ipv6)))); 16600f74e101Schristos } 1661c74ad251Schristos ND_PRINT(" }"); 16620f74e101Schristos } else 1663c74ad251Schristos ND_PRINT(", %u source(s)", nsrcs); 16640f74e101Schristos } 1665c74ad251Schristos ND_PRINT("]"); 16660f74e101Schristos } 16670f74e101Schristos 16680f74e101Schristos static void 1669b3a00663Schristos dnsname_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) 16700f74e101Schristos { 16710f74e101Schristos int i; 16720f74e101Schristos 16730f74e101Schristos /* DNS name decoding - no decompression */ 1674c74ad251Schristos ND_PRINT(", \""); 16750f74e101Schristos while (cp < ep) { 1676c74ad251Schristos i = GET_U_1(cp); 1677c74ad251Schristos cp++; 16780f74e101Schristos if (i) { 16790f74e101Schristos if (i > ep - cp) { 1680c74ad251Schristos ND_PRINT("???"); 16810f74e101Schristos break; 16820f74e101Schristos } 16830f74e101Schristos while (i-- && cp < ep) { 1684c74ad251Schristos fn_print_char(ndo, GET_U_1(cp)); 16850f74e101Schristos cp++; 16860f74e101Schristos } 1687c74ad251Schristos if (cp + 1 < ep && GET_U_1(cp)) 1688c74ad251Schristos ND_PRINT("."); 16890f74e101Schristos } else { 16900f74e101Schristos if (cp == ep) { 16910f74e101Schristos /* FQDN */ 1692c74ad251Schristos ND_PRINT("."); 1693c74ad251Schristos } else if (cp + 1 == ep && GET_U_1(cp) == '\0') { 16940f74e101Schristos /* truncated */ 16950f74e101Schristos } else { 16960f74e101Schristos /* invalid */ 1697c74ad251Schristos ND_PRINT("???"); 16980f74e101Schristos } 16990f74e101Schristos break; 17000f74e101Schristos } 17010f74e101Schristos } 1702c74ad251Schristos ND_PRINT("\""); 17030f74e101Schristos } 17040f74e101Schristos 17050f74e101Schristos static void 1706b3a00663Schristos icmp6_nodeinfo_print(netdissect_options *ndo, u_int icmp6len, const u_char *bp, const u_char *ep) 17070f74e101Schristos { 1708b3a00663Schristos const struct icmp6_nodeinfo *ni6; 1709b3a00663Schristos const struct icmp6_hdr *dp; 17100f74e101Schristos const u_char *cp; 17110f74e101Schristos size_t siz, i; 17120f74e101Schristos int needcomma; 17130f74e101Schristos 17140f74e101Schristos if (ep < bp) 17150f74e101Schristos return; 1716fdccd7e4Schristos dp = (const struct icmp6_hdr *)bp; 1717fdccd7e4Schristos ni6 = (const struct icmp6_nodeinfo *)bp; 17180f74e101Schristos siz = ep - bp; 17190f74e101Schristos 1720c74ad251Schristos switch (GET_U_1(ni6->ni_type)) { 17210f74e101Schristos case ICMP6_NI_QUERY: 17220f74e101Schristos if (siz == sizeof(*dp) + 4) { 17230f74e101Schristos /* KAME who-are-you */ 1724c74ad251Schristos ND_PRINT(" who-are-you request"); 17250f74e101Schristos break; 17260f74e101Schristos } 1727c74ad251Schristos ND_PRINT(" node information query"); 17280f74e101Schristos 1729c74ad251Schristos ND_TCHECK_LEN(dp, sizeof(*ni6)); 1730fdccd7e4Schristos ni6 = (const struct icmp6_nodeinfo *)dp; 1731c74ad251Schristos ND_PRINT(" ("); /*)*/ 1732c74ad251Schristos switch (GET_BE_U_2(ni6->ni_qtype)) { 17330f74e101Schristos case NI_QTYPE_NOOP: 1734c74ad251Schristos ND_PRINT("noop"); 17350f74e101Schristos break; 17360f74e101Schristos case NI_QTYPE_SUPTYPES: 1737c74ad251Schristos ND_PRINT("supported qtypes"); 1738c74ad251Schristos i = GET_BE_U_2(ni6->ni_flags); 17390f74e101Schristos if (i) 1740c74ad251Schristos ND_PRINT(" [%s]", (i & 0x01) ? "C" : ""); 17410f74e101Schristos break; 17420f74e101Schristos case NI_QTYPE_FQDN: 1743c74ad251Schristos ND_PRINT("DNS name"); 17440f74e101Schristos break; 17450f74e101Schristos case NI_QTYPE_NODEADDR: 1746c74ad251Schristos ND_PRINT("node addresses"); 1747c74ad251Schristos i = GET_BE_U_2(ni6->ni_flags); 17480f74e101Schristos if (!i) 17490f74e101Schristos break; 17500f74e101Schristos /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 1751c74ad251Schristos ND_PRINT(" [%s%s%s%s%s%s]", 17520f74e101Schristos (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 17530f74e101Schristos (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 17540f74e101Schristos (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 17550f74e101Schristos (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 17560f74e101Schristos (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1757c74ad251Schristos (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 17580f74e101Schristos break; 17590f74e101Schristos default: 1760c74ad251Schristos ND_PRINT("unknown"); 17610f74e101Schristos break; 17620f74e101Schristos } 17630f74e101Schristos 1764c74ad251Schristos if (GET_BE_U_2(ni6->ni_qtype) == NI_QTYPE_NOOP || 1765c74ad251Schristos GET_BE_U_2(ni6->ni_qtype) == NI_QTYPE_SUPTYPES) { 17660f74e101Schristos if (siz != sizeof(*ni6)) 1767b3a00663Schristos if (ndo->ndo_vflag) 1768c74ad251Schristos ND_PRINT(", invalid len"); 17690f74e101Schristos /*(*/ 1770c74ad251Schristos ND_PRINT(")"); 17710f74e101Schristos break; 17720f74e101Schristos } 17730f74e101Schristos 17740f74e101Schristos /* XXX backward compat, icmp-name-lookup-03 */ 17750f74e101Schristos if (siz == sizeof(*ni6)) { 1776c74ad251Schristos ND_PRINT(", 03 draft"); 17770f74e101Schristos /*(*/ 1778c74ad251Schristos ND_PRINT(")"); 17790f74e101Schristos break; 17800f74e101Schristos } 17810f74e101Schristos 1782c74ad251Schristos cp = (const u_char *)(ni6 + 1); 1783c74ad251Schristos switch (GET_U_1(ni6->ni_code)) { 17840f74e101Schristos case ICMP6_NI_SUBJ_IPV6: 1785c74ad251Schristos if (!ND_TTEST_LEN(dp, sizeof(*ni6) + sizeof(nd_ipv6))) 17860f74e101Schristos break; 1787c74ad251Schristos if (siz != sizeof(*ni6) + sizeof(nd_ipv6)) { 1788b3a00663Schristos if (ndo->ndo_vflag) 1789c74ad251Schristos ND_PRINT(", invalid subject len"); 17900f74e101Schristos break; 17910f74e101Schristos } 1792c74ad251Schristos ND_PRINT(", subject=%s", 1793c74ad251Schristos GET_IP6ADDR_STRING(cp)); 17940f74e101Schristos break; 17950f74e101Schristos case ICMP6_NI_SUBJ_FQDN: 1796c74ad251Schristos ND_PRINT(", subject=DNS name"); 1797c74ad251Schristos if (GET_U_1(cp) == ep - cp - 1) { 17980f74e101Schristos /* icmp-name-lookup-03, pascal string */ 1799b3a00663Schristos if (ndo->ndo_vflag) 1800c74ad251Schristos ND_PRINT(", 03 draft"); 18010f74e101Schristos cp++; 1802c74ad251Schristos ND_PRINT(", \""); 18030f74e101Schristos while (cp < ep) { 1804c74ad251Schristos fn_print_char(ndo, GET_U_1(cp)); 18050f74e101Schristos cp++; 18060f74e101Schristos } 1807c74ad251Schristos ND_PRINT("\""); 18080f74e101Schristos } else 1809b3a00663Schristos dnsname_print(ndo, cp, ep); 18100f74e101Schristos break; 18110f74e101Schristos case ICMP6_NI_SUBJ_IPV4: 1812c74ad251Schristos if (!ND_TTEST_LEN(dp, sizeof(*ni6) + sizeof(nd_ipv4))) 18130f74e101Schristos break; 1814c74ad251Schristos if (siz != sizeof(*ni6) + sizeof(nd_ipv4)) { 1815b3a00663Schristos if (ndo->ndo_vflag) 1816c74ad251Schristos ND_PRINT(", invalid subject len"); 18170f74e101Schristos break; 18180f74e101Schristos } 1819c74ad251Schristos ND_PRINT(", subject=%s", 1820c74ad251Schristos GET_IPADDR_STRING(cp)); 18210f74e101Schristos break; 18220f74e101Schristos default: 1823c74ad251Schristos ND_PRINT(", unknown subject"); 18240f74e101Schristos break; 18250f74e101Schristos } 18260f74e101Schristos 18270f74e101Schristos /*(*/ 1828c74ad251Schristos ND_PRINT(")"); 18290f74e101Schristos break; 18300f74e101Schristos 18310f74e101Schristos case ICMP6_NI_REPLY: 1832c74ad251Schristos if (icmp6len > siz) 1833c74ad251Schristos goto trunc; 18340f74e101Schristos 18350f74e101Schristos needcomma = 0; 18360f74e101Schristos 1837c74ad251Schristos ND_TCHECK_LEN(dp, sizeof(*ni6)); 1838fdccd7e4Schristos ni6 = (const struct icmp6_nodeinfo *)dp; 1839c74ad251Schristos ND_PRINT(" node information reply"); 1840c74ad251Schristos ND_PRINT(" ("); /*)*/ 1841c74ad251Schristos switch (GET_U_1(ni6->ni_code)) { 18420f74e101Schristos case ICMP6_NI_SUCCESS: 1843b3a00663Schristos if (ndo->ndo_vflag) { 1844c74ad251Schristos ND_PRINT("success"); 18450f74e101Schristos needcomma++; 18460f74e101Schristos } 18470f74e101Schristos break; 18480f74e101Schristos case ICMP6_NI_REFUSED: 1849c74ad251Schristos ND_PRINT("refused"); 18500f74e101Schristos needcomma++; 18510f74e101Schristos if (siz != sizeof(*ni6)) 1852b3a00663Schristos if (ndo->ndo_vflag) 1853c74ad251Schristos ND_PRINT(", invalid length"); 18540f74e101Schristos break; 18550f74e101Schristos case ICMP6_NI_UNKNOWN: 1856c74ad251Schristos ND_PRINT("unknown"); 18570f74e101Schristos needcomma++; 18580f74e101Schristos if (siz != sizeof(*ni6)) 1859b3a00663Schristos if (ndo->ndo_vflag) 1860c74ad251Schristos ND_PRINT(", invalid length"); 18610f74e101Schristos break; 18620f74e101Schristos } 18630f74e101Schristos 1864c74ad251Schristos if (GET_U_1(ni6->ni_code) != ICMP6_NI_SUCCESS) { 18650f74e101Schristos /*(*/ 1866c74ad251Schristos ND_PRINT(")"); 18670f74e101Schristos break; 18680f74e101Schristos } 18690f74e101Schristos 1870c74ad251Schristos switch (GET_BE_U_2(ni6->ni_qtype)) { 18710f74e101Schristos case NI_QTYPE_NOOP: 18720f74e101Schristos if (needcomma) 1873c74ad251Schristos ND_PRINT(", "); 1874c74ad251Schristos ND_PRINT("noop"); 18750f74e101Schristos if (siz != sizeof(*ni6)) 1876b3a00663Schristos if (ndo->ndo_vflag) 1877c74ad251Schristos ND_PRINT(", invalid length"); 18780f74e101Schristos break; 18790f74e101Schristos case NI_QTYPE_SUPTYPES: 18800f74e101Schristos if (needcomma) 1881c74ad251Schristos ND_PRINT(", "); 1882c74ad251Schristos ND_PRINT("supported qtypes"); 1883c74ad251Schristos i = GET_BE_U_2(ni6->ni_flags); 18840f74e101Schristos if (i) 1885c74ad251Schristos ND_PRINT(" [%s]", (i & 0x01) ? "C" : ""); 18860f74e101Schristos break; 18870f74e101Schristos case NI_QTYPE_FQDN: 18880f74e101Schristos if (needcomma) 1889c74ad251Schristos ND_PRINT(", "); 1890c74ad251Schristos ND_PRINT("DNS name"); 18910f74e101Schristos cp = (const u_char *)(ni6 + 1) + 4; 1892c74ad251Schristos if (GET_U_1(cp) == ep - cp - 1) { 18930f74e101Schristos /* icmp-name-lookup-03, pascal string */ 1894b3a00663Schristos if (ndo->ndo_vflag) 1895c74ad251Schristos ND_PRINT(", 03 draft"); 18960f74e101Schristos cp++; 1897c74ad251Schristos ND_PRINT(", \""); 18980f74e101Schristos while (cp < ep) { 1899c74ad251Schristos fn_print_char(ndo, GET_U_1(cp)); 19000f74e101Schristos cp++; 19010f74e101Schristos } 1902c74ad251Schristos ND_PRINT("\""); 19030f74e101Schristos } else 1904b3a00663Schristos dnsname_print(ndo, cp, ep); 1905c74ad251Schristos if ((GET_BE_U_2(ni6->ni_flags) & 0x01) != 0) 1906c74ad251Schristos ND_PRINT(" [TTL=%u]", GET_BE_U_4(ni6 + 1)); 19070f74e101Schristos break; 19080f74e101Schristos case NI_QTYPE_NODEADDR: 19090f74e101Schristos if (needcomma) 1910c74ad251Schristos ND_PRINT(", "); 1911c74ad251Schristos ND_PRINT("node addresses"); 19120f74e101Schristos i = sizeof(*ni6); 19130f74e101Schristos while (i < siz) { 1914c74ad251Schristos if (i + sizeof(uint32_t) + sizeof(nd_ipv6) > siz) 19150f74e101Schristos break; 1916c74ad251Schristos ND_PRINT(" %s(%u)", 1917c74ad251Schristos GET_IP6ADDR_STRING(bp + i + sizeof(uint32_t)), 1918c74ad251Schristos GET_BE_U_4(bp + i)); 1919c74ad251Schristos i += sizeof(uint32_t) + sizeof(nd_ipv6); 19200f74e101Schristos } 1921c74ad251Schristos i = GET_BE_U_2(ni6->ni_flags); 19220f74e101Schristos if (!i) 19230f74e101Schristos break; 1924c74ad251Schristos ND_PRINT(" [%s%s%s%s%s%s%s]", 19250f74e101Schristos (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 19260f74e101Schristos (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 19270f74e101Schristos (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 19280f74e101Schristos (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 19290f74e101Schristos (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 19300f74e101Schristos (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1931c74ad251Schristos (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 19320f74e101Schristos break; 19330f74e101Schristos default: 19340f74e101Schristos if (needcomma) 1935c74ad251Schristos ND_PRINT(", "); 1936c74ad251Schristos ND_PRINT("unknown"); 19370f74e101Schristos break; 19380f74e101Schristos } 19390f74e101Schristos 19400f74e101Schristos /*(*/ 1941c74ad251Schristos ND_PRINT(")"); 19420f74e101Schristos break; 19430f74e101Schristos } 19440f74e101Schristos return; 19450f74e101Schristos 19460f74e101Schristos trunc: 1947c74ad251Schristos nd_print_trunc(ndo); 19480f74e101Schristos } 19490f74e101Schristos 19500f74e101Schristos static void 1951b3a00663Schristos icmp6_rrenum_print(netdissect_options *ndo, const u_char *bp, const u_char *ep) 19520f74e101Schristos { 1953b3a00663Schristos const struct icmp6_router_renum *rr6; 19540f74e101Schristos const char *cp; 1955fdccd7e4Schristos const struct rr_pco_match *match; 1956fdccd7e4Schristos const struct rr_pco_use *use; 19570f74e101Schristos char hbuf[NI_MAXHOST]; 19580f74e101Schristos int n; 19590f74e101Schristos 19600f74e101Schristos if (ep < bp) 19610f74e101Schristos return; 1962fdccd7e4Schristos rr6 = (const struct icmp6_router_renum *)bp; 19630f74e101Schristos cp = (const char *)(rr6 + 1); 19640f74e101Schristos 1965c74ad251Schristos ND_TCHECK_4(rr6->rr_reserved); 1966c74ad251Schristos switch (GET_U_1(rr6->rr_code)) { 19670f74e101Schristos case ICMP6_ROUTER_RENUMBERING_COMMAND: 1968c74ad251Schristos ND_PRINT(", command"); 19690f74e101Schristos break; 19700f74e101Schristos case ICMP6_ROUTER_RENUMBERING_RESULT: 1971c74ad251Schristos ND_PRINT(", result"); 19720f74e101Schristos break; 19730f74e101Schristos case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1974c74ad251Schristos ND_PRINT(", sequence number reset"); 19750f74e101Schristos break; 19760f74e101Schristos default: 1977c74ad251Schristos ND_PRINT(", code-#%u", GET_U_1(rr6->rr_code)); 19780f74e101Schristos break; 19790f74e101Schristos } 19800f74e101Schristos 1981c74ad251Schristos ND_PRINT(", seq=%u", GET_BE_U_4(rr6->rr_seqnum)); 19820f74e101Schristos 1983b3a00663Schristos if (ndo->ndo_vflag) { 1984c74ad251Schristos uint8_t rr_flags = GET_U_1(rr6->rr_flags); 1985c74ad251Schristos #define F(x, y) (rr_flags & (x) ? (y) : "") 1986c74ad251Schristos ND_PRINT("["); /*]*/ 1987c74ad251Schristos if (rr_flags) { 1988c74ad251Schristos ND_PRINT("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 19890f74e101Schristos F(ICMP6_RR_FLAGS_REQRESULT, "R"), 19900f74e101Schristos F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 19910f74e101Schristos F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1992c74ad251Schristos F(ICMP6_RR_FLAGS_PREVDONE, "P")); 19930f74e101Schristos } 1994c74ad251Schristos ND_PRINT("seg=%u,", GET_U_1(rr6->rr_segnum)); 1995c74ad251Schristos ND_PRINT("maxdelay=%u", GET_BE_U_2(rr6->rr_maxdelay)); 1996c74ad251Schristos if (GET_BE_U_4(rr6->rr_reserved)) 1997c74ad251Schristos ND_PRINT("rsvd=0x%x", GET_BE_U_4(rr6->rr_reserved)); 19980f74e101Schristos /*[*/ 1999c74ad251Schristos ND_PRINT("]"); 20000f74e101Schristos #undef F 20010f74e101Schristos } 20020f74e101Schristos 2003c74ad251Schristos if (GET_U_1(rr6->rr_code) == ICMP6_ROUTER_RENUMBERING_COMMAND) { 2004fdccd7e4Schristos match = (const struct rr_pco_match *)cp; 20050f74e101Schristos cp = (const char *)(match + 1); 20060f74e101Schristos 2007c74ad251Schristos ND_TCHECK_16(match->rpm_prefix); 20080f74e101Schristos 2009b3a00663Schristos if (ndo->ndo_vflag > 1) 2010c74ad251Schristos ND_PRINT("\n\t"); 20110f74e101Schristos else 2012c74ad251Schristos ND_PRINT(" "); 2013c74ad251Schristos ND_PRINT("match("); /*)*/ 2014c74ad251Schristos switch (GET_U_1(match->rpm_code)) { 2015c74ad251Schristos case RPM_PCO_ADD: ND_PRINT("add"); break; 2016c74ad251Schristos case RPM_PCO_CHANGE: ND_PRINT("change"); break; 2017c74ad251Schristos case RPM_PCO_SETGLOBAL: ND_PRINT("setglobal"); break; 2018c74ad251Schristos default: ND_PRINT("#%u", 2019c74ad251Schristos GET_U_1(match->rpm_code)); break; 20200f74e101Schristos } 20210f74e101Schristos 2022b3a00663Schristos if (ndo->ndo_vflag) { 2023c74ad251Schristos ND_PRINT(",ord=%u", GET_U_1(match->rpm_ordinal)); 2024c74ad251Schristos ND_PRINT(",min=%u", GET_U_1(match->rpm_minlen)); 2025c74ad251Schristos ND_PRINT(",max=%u", GET_U_1(match->rpm_maxlen)); 20260f74e101Schristos } 2027c74ad251Schristos if (addrtostr6(match->rpm_prefix, hbuf, sizeof(hbuf))) 2028c74ad251Schristos ND_PRINT(",%s/%u", hbuf, GET_U_1(match->rpm_matchlen)); 20290f74e101Schristos else 2030c74ad251Schristos ND_PRINT(",?/%u", GET_U_1(match->rpm_matchlen)); 20310f74e101Schristos /*(*/ 2032c74ad251Schristos ND_PRINT(")"); 20330f74e101Schristos 2034c74ad251Schristos n = GET_U_1(match->rpm_len) - 3; 20350f74e101Schristos if (n % 4) 20360f74e101Schristos goto trunc; 20370f74e101Schristos n /= 4; 20380f74e101Schristos while (n-- > 0) { 2039fdccd7e4Schristos use = (const struct rr_pco_use *)cp; 20400f74e101Schristos cp = (const char *)(use + 1); 20410f74e101Schristos 2042c74ad251Schristos ND_TCHECK_16(use->rpu_prefix); 20430f74e101Schristos 2044b3a00663Schristos if (ndo->ndo_vflag > 1) 2045c74ad251Schristos ND_PRINT("\n\t"); 20460f74e101Schristos else 2047c74ad251Schristos ND_PRINT(" "); 2048c74ad251Schristos ND_PRINT("use("); /*)*/ 2049c74ad251Schristos if (GET_U_1(use->rpu_flags)) { 2050c74ad251Schristos #define F(x, y) (GET_U_1(use->rpu_flags) & (x) ? (y) : "") 2051c74ad251Schristos ND_PRINT("%s%s,", 20520f74e101Schristos F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 2053c74ad251Schristos F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 20540f74e101Schristos #undef F 20550f74e101Schristos } 2056b3a00663Schristos if (ndo->ndo_vflag) { 2057c74ad251Schristos ND_PRINT("mask=0x%x,", 2058c74ad251Schristos GET_U_1(use->rpu_ramask)); 2059c74ad251Schristos ND_PRINT("raflags=0x%x,", 2060c74ad251Schristos GET_U_1(use->rpu_raflags)); 2061c74ad251Schristos if (GET_BE_U_4(use->rpu_vltime) == 0xffffffff) 2062c74ad251Schristos ND_PRINT("vltime=infty,"); 20630f74e101Schristos else 2064c74ad251Schristos ND_PRINT("vltime=%u,", 2065c74ad251Schristos GET_BE_U_4(use->rpu_vltime)); 2066c74ad251Schristos if (GET_BE_U_4(use->rpu_pltime) == 0xffffffff) 2067c74ad251Schristos ND_PRINT("pltime=infty,"); 20680f74e101Schristos else 2069c74ad251Schristos ND_PRINT("pltime=%u,", 2070c74ad251Schristos GET_BE_U_4(use->rpu_pltime)); 20710f74e101Schristos } 2072c74ad251Schristos if (addrtostr6(use->rpu_prefix, hbuf, sizeof(hbuf))) 2073c74ad251Schristos ND_PRINT("%s/%u/%u", hbuf, 2074c74ad251Schristos GET_U_1(use->rpu_uselen), 2075c74ad251Schristos GET_U_1(use->rpu_keeplen)); 20760f74e101Schristos else 2077c74ad251Schristos ND_PRINT("?/%u/%u", GET_U_1(use->rpu_uselen), 2078c74ad251Schristos GET_U_1(use->rpu_keeplen)); 20790f74e101Schristos /*(*/ 2080c74ad251Schristos ND_PRINT(")"); 20810f74e101Schristos } 20820f74e101Schristos } 20830f74e101Schristos 20840f74e101Schristos return; 20850f74e101Schristos 20860f74e101Schristos trunc: 2087c74ad251Schristos nd_print_trunc(ndo); 20880f74e101Schristos } 2089