10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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-ip6.c,v 1.10 2024/09/02 16:15:31 christos Exp $"); 250f74e101Schristos #endif 260f74e101Schristos 27dc860a36Sspz /* \summary: IPv6 printer */ 28dc860a36Sspz 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 330f74e101Schristos #include <string.h> 340f74e101Schristos 35fdccd7e4Schristos #include "netdissect.h" 360f74e101Schristos #include "addrtoname.h" 370f74e101Schristos #include "extract.h" 380f74e101Schristos 390f74e101Schristos #include "ip6.h" 400f74e101Schristos #include "ipproto.h" 410f74e101Schristos 420f74e101Schristos /* 43fdccd7e4Schristos * If routing headers are presend and valid, set dst to the final destination. 44fdccd7e4Schristos * Otherwise, set it to the IPv6 destination. 45fdccd7e4Schristos * 46fdccd7e4Schristos * This is used for UDP and TCP pseudo-header in the checksum 47fdccd7e4Schristos * calculation. 48fdccd7e4Schristos */ 49fdccd7e4Schristos static void 50c74ad251Schristos ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst, 51fdccd7e4Schristos const struct ip6_hdr *ip6) 52fdccd7e4Schristos { 53fdccd7e4Schristos const u_char *cp; 54c74ad251Schristos u_int advance; 55fdccd7e4Schristos u_int nh; 56c74ad251Schristos const void *dst_addr; 57fdccd7e4Schristos const struct ip6_rthdr *dp; 58fdccd7e4Schristos const struct ip6_rthdr0 *dp0; 59c74ad251Schristos const struct ip6_srh *srh; 60c74ad251Schristos const u_char *p; 61fdccd7e4Schristos int i, len; 62fdccd7e4Schristos 63fdccd7e4Schristos cp = (const u_char *)ip6; 64fdccd7e4Schristos advance = sizeof(struct ip6_hdr); 65c74ad251Schristos nh = GET_U_1(ip6->ip6_nxt); 66c74ad251Schristos dst_addr = (const void *)ip6->ip6_dst; 67fdccd7e4Schristos 68fdccd7e4Schristos while (cp < ndo->ndo_snapend) { 69fdccd7e4Schristos cp += advance; 70fdccd7e4Schristos 71fdccd7e4Schristos switch (nh) { 72fdccd7e4Schristos 73fdccd7e4Schristos case IPPROTO_HOPOPTS: 74fdccd7e4Schristos case IPPROTO_DSTOPTS: 75fdccd7e4Schristos case IPPROTO_MOBILITY_OLD: 76fdccd7e4Schristos case IPPROTO_MOBILITY: 77fdccd7e4Schristos /* 78fdccd7e4Schristos * These have a header length byte, following 79fdccd7e4Schristos * the next header byte, giving the length of 80fdccd7e4Schristos * the header, in units of 8 octets, excluding 81fdccd7e4Schristos * the first 8 octets. 82fdccd7e4Schristos */ 83c74ad251Schristos advance = (GET_U_1(cp + 1) + 1) << 3; 84c74ad251Schristos nh = GET_U_1(cp); 85fdccd7e4Schristos break; 86fdccd7e4Schristos 87fdccd7e4Schristos case IPPROTO_FRAGMENT: 88fdccd7e4Schristos /* 89fdccd7e4Schristos * The byte following the next header byte is 90fdccd7e4Schristos * marked as reserved, and the header is always 91fdccd7e4Schristos * the same size. 92fdccd7e4Schristos */ 93fdccd7e4Schristos advance = sizeof(struct ip6_frag); 94c74ad251Schristos nh = GET_U_1(cp); 95fdccd7e4Schristos break; 96fdccd7e4Schristos 97fdccd7e4Schristos case IPPROTO_ROUTING: 98fdccd7e4Schristos /* 99fdccd7e4Schristos * OK, we found it. 100fdccd7e4Schristos */ 101fdccd7e4Schristos dp = (const struct ip6_rthdr *)cp; 102c74ad251Schristos ND_TCHECK_SIZE(dp); 103c74ad251Schristos len = GET_U_1(dp->ip6r_len); 104c74ad251Schristos switch (GET_U_1(dp->ip6r_type)) { 105fdccd7e4Schristos 106fdccd7e4Schristos case IPV6_RTHDR_TYPE_0: 107fdccd7e4Schristos case IPV6_RTHDR_TYPE_2: /* Mobile IPv6 ID-20 */ 108fdccd7e4Schristos dp0 = (const struct ip6_rthdr0 *)dp; 109fdccd7e4Schristos if (len % 2 == 1) 110fdccd7e4Schristos goto trunc; 111fdccd7e4Schristos len >>= 1; 112c74ad251Schristos p = (const u_char *) dp0->ip6r0_addr; 113fdccd7e4Schristos for (i = 0; i < len; i++) { 114c74ad251Schristos ND_TCHECK_16(p); 115c74ad251Schristos dst_addr = (const void *)p; 116c74ad251Schristos p += 16; 117fdccd7e4Schristos } 118fdccd7e4Schristos break; 119c74ad251Schristos case IPV6_RTHDR_TYPE_4: 120c74ad251Schristos /* IPv6 Segment Routing Header (SRH) */ 121c74ad251Schristos srh = (const struct ip6_srh *)dp; 122c74ad251Schristos if (len % 2 == 1) 123c74ad251Schristos goto trunc; 124c74ad251Schristos p = (const u_char *) srh->srh_segments; 125c74ad251Schristos /* 126c74ad251Schristos * The list of segments are encoded in the reverse order. 127c74ad251Schristos * Accordingly, the final DA is encoded in srh_segments[0] 128c74ad251Schristos */ 129c74ad251Schristos ND_TCHECK_16(p); 130c74ad251Schristos dst_addr = (const void *)p; 131c74ad251Schristos break; 132fdccd7e4Schristos 133fdccd7e4Schristos default: 134fdccd7e4Schristos break; 135fdccd7e4Schristos } 136fdccd7e4Schristos 137fdccd7e4Schristos /* 138fdccd7e4Schristos * Only one routing header to a customer. 139fdccd7e4Schristos */ 140fdccd7e4Schristos goto done; 141fdccd7e4Schristos 142fdccd7e4Schristos case IPPROTO_AH: 143fdccd7e4Schristos case IPPROTO_ESP: 144fdccd7e4Schristos case IPPROTO_IPCOMP: 145fdccd7e4Schristos default: 146fdccd7e4Schristos /* 147fdccd7e4Schristos * AH and ESP are, in the RFCs that describe them, 148fdccd7e4Schristos * described as being "viewed as an end-to-end 149fdccd7e4Schristos * payload" "in the IPv6 context, so that they 150fdccd7e4Schristos * "should appear after hop-by-hop, routing, and 151fdccd7e4Schristos * fragmentation extension headers". We assume 152fdccd7e4Schristos * that's the case, and stop as soon as we see 153fdccd7e4Schristos * one. (We can't handle an ESP header in 154fdccd7e4Schristos * the general case anyway, as its length depends 155fdccd7e4Schristos * on the encryption algorithm.) 156fdccd7e4Schristos * 157fdccd7e4Schristos * IPComp is also "viewed as an end-to-end 158fdccd7e4Schristos * payload" "in the IPv6 context". 159fdccd7e4Schristos * 160fdccd7e4Schristos * All other protocols are assumed to be the final 161fdccd7e4Schristos * protocol. 162fdccd7e4Schristos */ 163fdccd7e4Schristos goto done; 164fdccd7e4Schristos } 165fdccd7e4Schristos } 166fdccd7e4Schristos 167fdccd7e4Schristos done: 168fdccd7e4Schristos trunc: 169c74ad251Schristos GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6)); 170fdccd7e4Schristos } 171fdccd7e4Schristos 172fdccd7e4Schristos /* 1730f74e101Schristos * Compute a V6-style checksum by building a pseudoheader. 1740f74e101Schristos */ 175c74ad251Schristos uint16_t 176fdccd7e4Schristos nextproto6_cksum(netdissect_options *ndo, 177fdccd7e4Schristos const struct ip6_hdr *ip6, const uint8_t *data, 178c74ad251Schristos u_int len, u_int covlen, uint8_t next_proto) 1790f74e101Schristos { 1800e9868baSchristos struct { 181c74ad251Schristos nd_ipv6 ph_src; 182c74ad251Schristos nd_ipv6 ph_dst; 183b3a00663Schristos uint32_t ph_len; 184b3a00663Schristos uint8_t ph_zero[3]; 185b3a00663Schristos uint8_t ph_nxt; 1860e9868baSchristos } ph; 1870e9868baSchristos struct cksum_vec vec[2]; 188c74ad251Schristos u_int nh; 1890f74e101Schristos 1900f74e101Schristos /* pseudo-header */ 1910e9868baSchristos memset(&ph, 0, sizeof(ph)); 192c74ad251Schristos GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6)); 193c74ad251Schristos nh = GET_U_1(ip6->ip6_nxt); 194c74ad251Schristos switch (nh) { 195fdccd7e4Schristos 196fdccd7e4Schristos case IPPROTO_HOPOPTS: 197fdccd7e4Schristos case IPPROTO_DSTOPTS: 198fdccd7e4Schristos case IPPROTO_MOBILITY_OLD: 199fdccd7e4Schristos case IPPROTO_MOBILITY: 200fdccd7e4Schristos case IPPROTO_FRAGMENT: 201fdccd7e4Schristos case IPPROTO_ROUTING: 202fdccd7e4Schristos /* 203fdccd7e4Schristos * The next header is either a routing header or a header 204fdccd7e4Schristos * after which there might be a routing header, so scan 205fdccd7e4Schristos * for a routing header. 206fdccd7e4Schristos */ 207fdccd7e4Schristos ip6_finddst(ndo, &ph.ph_dst, ip6); 208fdccd7e4Schristos break; 209fdccd7e4Schristos 210fdccd7e4Schristos default: 211c74ad251Schristos GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6)); 212fdccd7e4Schristos break; 213fdccd7e4Schristos } 2140e9868baSchristos ph.ph_len = htonl(len); 2150e9868baSchristos ph.ph_nxt = next_proto; 2160f74e101Schristos 217b3a00663Schristos vec[0].ptr = (const uint8_t *)(void *)&ph; 2180e9868baSchristos vec[0].len = sizeof(ph); 2190e9868baSchristos vec[1].ptr = data; 220b3a00663Schristos vec[1].len = covlen; 2210f74e101Schristos 2220e9868baSchristos return in_cksum(vec, 2); 2230f74e101Schristos } 2240f74e101Schristos 2250f74e101Schristos /* 2260f74e101Schristos * print an IP6 datagram. 2270f74e101Schristos */ 2280f74e101Schristos void 2290e9868baSchristos ip6_print(netdissect_options *ndo, const u_char *bp, u_int length) 2300f74e101Schristos { 231c74ad251Schristos const struct ip6_hdr *ip6; 232c74ad251Schristos int advance; 2330f74e101Schristos u_int len; 234c74ad251Schristos u_int total_advance; 235c74ad251Schristos const u_char *cp; 236c74ad251Schristos uint32_t payload_len; 237c74ad251Schristos uint8_t ph, nh; 2380f74e101Schristos int fragmented = 0; 2390f74e101Schristos u_int flow; 240c74ad251Schristos int found_extension_header; 241c74ad251Schristos int found_jumbo; 242c74ad251Schristos int found_hbh; 2430f74e101Schristos 244c74ad251Schristos ndo->ndo_protocol = "ip6"; 2450f74e101Schristos ip6 = (const struct ip6_hdr *)bp; 2460f74e101Schristos 247*26ba0b50Schristos if (!ndo->ndo_eflag) { 248*26ba0b50Schristos nd_print_protocol_caps(ndo); 249*26ba0b50Schristos ND_PRINT(" "); 2500f74e101Schristos } 2510f74e101Schristos 252*26ba0b50Schristos ND_ICHECK_ZU(length, <, sizeof (struct ip6_hdr)); 253*26ba0b50Schristos ND_ICHECKMSG_U("version", IP6_VERSION(ip6), !=, 6); 254b3a00663Schristos 255c74ad251Schristos payload_len = GET_BE_U_2(ip6->ip6_plen); 256c74ad251Schristos /* 257c74ad251Schristos * RFC 1883 says: 258c74ad251Schristos * 259c74ad251Schristos * The Payload Length field in the IPv6 header must be set to zero 260c74ad251Schristos * in every packet that carries the Jumbo Payload option. If a 261c74ad251Schristos * packet is received with a valid Jumbo Payload option present and 262c74ad251Schristos * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem 263c74ad251Schristos * message, Code 0, should be sent to the packet's source, pointing 264c74ad251Schristos * to the Option Type field of the Jumbo Payload option. 265c74ad251Schristos * 266c74ad251Schristos * Later versions of the IPv6 spec don't discuss the Jumbo Payload 267c74ad251Schristos * option. 268c74ad251Schristos * 269c74ad251Schristos * If the payload length is 0, we temporarily just set the total 270c74ad251Schristos * length to the remaining data in the packet (which, for Ethernet, 271c74ad251Schristos * could include frame padding, but if it's a Jumbo Payload frame, 272c74ad251Schristos * it shouldn't even be sendable over Ethernet, so we don't worry 273c74ad251Schristos * about that), so we can process the extension headers in order 274c74ad251Schristos * to *find* a Jumbo Payload hop-by-hop option and, when we've 275c74ad251Schristos * processed all the extension headers, check whether we found 276c74ad251Schristos * a Jumbo Payload option, and fail if we haven't. 277c74ad251Schristos */ 278c74ad251Schristos if (payload_len != 0) { 2790f74e101Schristos len = payload_len + sizeof(struct ip6_hdr); 280*26ba0b50Schristos if (len > length) { 281*26ba0b50Schristos ND_PRINT("[header+payload length %u > length %u]", 282*26ba0b50Schristos len, length); 283*26ba0b50Schristos nd_print_invalid(ndo); 284*26ba0b50Schristos ND_PRINT(" "); 285*26ba0b50Schristos } 286c74ad251Schristos } else 287c74ad251Schristos len = length + sizeof(struct ip6_hdr); 2880f74e101Schristos 289c74ad251Schristos ph = 255; 290c74ad251Schristos nh = GET_U_1(ip6->ip6_nxt); 2910e9868baSchristos if (ndo->ndo_vflag) { 292c74ad251Schristos flow = GET_BE_U_4(ip6->ip6_flow); 293c74ad251Schristos ND_PRINT("("); 2940f74e101Schristos /* RFC 2460 */ 2950f74e101Schristos if (flow & 0x0ff00000) 296c74ad251Schristos ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20); 2970f74e101Schristos if (flow & 0x000fffff) 298c74ad251Schristos ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff); 2990f74e101Schristos 300c74ad251Schristos ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ", 301c74ad251Schristos GET_U_1(ip6->ip6_hlim), 302c74ad251Schristos tok2str(ipproto_values,"unknown",nh), 303c74ad251Schristos nh, 304c74ad251Schristos payload_len); 3050f74e101Schristos } 306*26ba0b50Schristos ND_TCHECK_SIZE(ip6); 3070f74e101Schristos 3080f74e101Schristos /* 3090f74e101Schristos * Cut off the snapshot length to the end of the IP payload. 3100f74e101Schristos */ 311c74ad251Schristos if (!nd_push_snaplen(ndo, bp, len)) { 312c74ad251Schristos (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 313c74ad251Schristos "%s: can't push snaplen on buffer stack", __func__); 314c74ad251Schristos } 3150f74e101Schristos 3160f74e101Schristos cp = (const u_char *)ip6; 3170f74e101Schristos advance = sizeof(struct ip6_hdr); 318c74ad251Schristos total_advance = 0; 319c74ad251Schristos /* Process extension headers */ 320c74ad251Schristos found_extension_header = 0; 321c74ad251Schristos found_jumbo = 0; 322c74ad251Schristos found_hbh = 0; 3230e9868baSchristos while (cp < ndo->ndo_snapend && advance > 0) { 32472c96ff3Schristos if (len < (u_int)advance) 32572c96ff3Schristos goto trunc; 3260f74e101Schristos cp += advance; 3270f74e101Schristos len -= advance; 328c74ad251Schristos total_advance += advance; 3290f74e101Schristos 3300f74e101Schristos if (cp == (const u_char *)(ip6 + 1) && 3310f74e101Schristos nh != IPPROTO_TCP && nh != IPPROTO_UDP && 3320f74e101Schristos nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) { 333c74ad251Schristos ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src), 334c74ad251Schristos GET_IP6ADDR_STRING(ip6->ip6_dst)); 3350f74e101Schristos } 3360f74e101Schristos 3370f74e101Schristos switch (nh) { 338c74ad251Schristos 3390f74e101Schristos case IPPROTO_HOPOPTS: 340c74ad251Schristos /* 341c74ad251Schristos * The Hop-by-Hop Options header, when present, 342c74ad251Schristos * must immediately follow the IPv6 header (RFC 8200) 343c74ad251Schristos */ 344c74ad251Schristos if (found_hbh == 1) { 345c74ad251Schristos ND_PRINT("[The Hop-by-Hop Options header was already found]"); 346c74ad251Schristos nd_print_invalid(ndo); 347dc860a36Sspz return; 348c74ad251Schristos } 349c74ad251Schristos if (ph != 255) { 350c74ad251Schristos ND_PRINT("[The Hop-by-Hop Options header don't follow the IPv6 header]"); 351c74ad251Schristos nd_print_invalid(ndo); 352c74ad251Schristos return; 353c74ad251Schristos } 354c74ad251Schristos advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len); 355c74ad251Schristos if (payload_len == 0 && found_jumbo == 0) { 356c74ad251Schristos ND_PRINT("[No valid Jumbo Payload Hop-by-Hop option found]"); 357c74ad251Schristos nd_print_invalid(ndo); 358c74ad251Schristos return; 359c74ad251Schristos } 360c74ad251Schristos if (advance < 0) { 361c74ad251Schristos nd_pop_packet_info(ndo); 362c74ad251Schristos return; 363c74ad251Schristos } 364c74ad251Schristos found_extension_header = 1; 365c74ad251Schristos found_hbh = 1; 366c74ad251Schristos nh = GET_U_1(cp); 3670f74e101Schristos break; 368c74ad251Schristos 3690f74e101Schristos case IPPROTO_DSTOPTS: 370c74ad251Schristos advance = dstopt_process(ndo, cp); 371c74ad251Schristos if (advance < 0) { 372c74ad251Schristos nd_pop_packet_info(ndo); 373dc860a36Sspz return; 374c74ad251Schristos } 375c74ad251Schristos found_extension_header = 1; 376c74ad251Schristos nh = GET_U_1(cp); 3770f74e101Schristos break; 378c74ad251Schristos 3790f74e101Schristos case IPPROTO_FRAGMENT: 380b3a00663Schristos advance = frag6_print(ndo, cp, (const u_char *)ip6); 381c74ad251Schristos if (advance < 0 || ndo->ndo_snapend <= cp + advance) { 382c74ad251Schristos nd_pop_packet_info(ndo); 3830f74e101Schristos return; 384c74ad251Schristos } 385c74ad251Schristos found_extension_header = 1; 386c74ad251Schristos nh = GET_U_1(cp); 3870f74e101Schristos fragmented = 1; 3880f74e101Schristos break; 3890f74e101Schristos 3900f74e101Schristos case IPPROTO_MOBILITY_OLD: 3910f74e101Schristos case IPPROTO_MOBILITY: 3920f74e101Schristos /* 393*26ba0b50Schristos * RFC 3775 says that 3940f74e101Schristos * the next header field in a mobility header 3950f74e101Schristos * should be IPPROTO_NONE, but speaks of 396c74ad251Schristos * the possibility of a future extension in 3970f74e101Schristos * which payload can be piggybacked atop a 3980f74e101Schristos * mobility header. 3990f74e101Schristos */ 400b3a00663Schristos advance = mobility_print(ndo, cp, (const u_char *)ip6); 401c74ad251Schristos if (advance < 0) { 402c74ad251Schristos nd_pop_packet_info(ndo); 40372c96ff3Schristos return; 404c74ad251Schristos } 405c74ad251Schristos found_extension_header = 1; 406c74ad251Schristos nh = GET_U_1(cp); 407c74ad251Schristos nd_pop_packet_info(ndo); 4080f74e101Schristos return; 409c74ad251Schristos 4100f74e101Schristos case IPPROTO_ROUTING: 411c74ad251Schristos ND_TCHECK_1(cp); 412b3a00663Schristos advance = rt6_print(ndo, cp, (const u_char *)ip6); 413c74ad251Schristos if (advance < 0) { 414c74ad251Schristos nd_pop_packet_info(ndo); 41572c96ff3Schristos return; 4160f74e101Schristos } 417c74ad251Schristos found_extension_header = 1; 418c74ad251Schristos nh = GET_U_1(cp); 4190f74e101Schristos break; 4200f74e101Schristos 4210f74e101Schristos default: 422c74ad251Schristos /* 423c74ad251Schristos * Not an extension header; hand off to the 424c74ad251Schristos * IP protocol demuxer. 425c74ad251Schristos */ 426c74ad251Schristos if (found_jumbo) { 427c74ad251Schristos /* 428c74ad251Schristos * We saw a Jumbo Payload option. 429c74ad251Schristos * Set the length to the payload length 430c74ad251Schristos * plus the IPv6 header length, and 431c74ad251Schristos * change the snapshot length accordingly. 432c74ad251Schristos * 433c74ad251Schristos * But make sure it's not shorter than 434c74ad251Schristos * the total number of bytes we've 435c74ad251Schristos * processed so far. 436c74ad251Schristos */ 437c74ad251Schristos len = payload_len + sizeof(struct ip6_hdr); 438c74ad251Schristos if (len < total_advance) 439c74ad251Schristos goto trunc; 440*26ba0b50Schristos if (len > length) { 441*26ba0b50Schristos ND_PRINT("[header+payload length %u > length %u]", 442*26ba0b50Schristos len, length); 443*26ba0b50Schristos nd_print_invalid(ndo); 444*26ba0b50Schristos ND_PRINT(" "); 445*26ba0b50Schristos } 446c74ad251Schristos nd_change_snaplen(ndo, bp, len); 447c74ad251Schristos 448c74ad251Schristos /* 449c74ad251Schristos * Now subtract the length of the IPv6 450c74ad251Schristos * header plus extension headers to get 451c74ad251Schristos * the payload length. 452c74ad251Schristos */ 453c74ad251Schristos len -= total_advance; 454c74ad251Schristos } else { 455c74ad251Schristos /* 456c74ad251Schristos * We didn't see a Jumbo Payload option; 457c74ad251Schristos * was the payload length zero? 458c74ad251Schristos */ 459c74ad251Schristos if (payload_len == 0) { 460c74ad251Schristos /* 461c74ad251Schristos * Yes. If we found an extension 462c74ad251Schristos * header, treat that as a truncated 463c74ad251Schristos * packet header, as there was 464c74ad251Schristos * no payload to contain an 465c74ad251Schristos * extension header. 466c74ad251Schristos */ 467c74ad251Schristos if (found_extension_header) 468c74ad251Schristos goto trunc; 469c74ad251Schristos 470c74ad251Schristos /* 471c74ad251Schristos * OK, we didn't see any extension 472c74ad251Schristos * header, but that means we have 473c74ad251Schristos * no payload, so set the length 474c74ad251Schristos * to the IPv6 header length, 475c74ad251Schristos * and change the snapshot length 476c74ad251Schristos * accordingly. 477c74ad251Schristos */ 478c74ad251Schristos len = sizeof(struct ip6_hdr); 479c74ad251Schristos nd_change_snaplen(ndo, bp, len); 480c74ad251Schristos 481c74ad251Schristos /* 482c74ad251Schristos * Now subtract the length of 483c74ad251Schristos * the IPv6 header plus extension 484c74ad251Schristos * headers (there weren't any, so 485c74ad251Schristos * that's just the IPv6 header 486c74ad251Schristos * length) to get the payload length. 487c74ad251Schristos */ 488c74ad251Schristos len -= total_advance; 489c74ad251Schristos } 490c74ad251Schristos } 491c74ad251Schristos ip_demux_print(ndo, cp, len, 6, fragmented, 492c74ad251Schristos GET_U_1(ip6->ip6_hlim), nh, bp); 493c74ad251Schristos nd_pop_packet_info(ndo); 4940f74e101Schristos return; 4950f74e101Schristos } 496c74ad251Schristos ph = nh; 497c74ad251Schristos 498c74ad251Schristos /* ndo_protocol reassignment after xxx_print() calls */ 499c74ad251Schristos ndo->ndo_protocol = "ip6"; 5000f74e101Schristos } 5010f74e101Schristos 502c74ad251Schristos nd_pop_packet_info(ndo); 5030f74e101Schristos return; 5040f74e101Schristos trunc: 505c74ad251Schristos nd_print_trunc(ndo); 506*26ba0b50Schristos return; 507*26ba0b50Schristos 508*26ba0b50Schristos invalid: 509*26ba0b50Schristos nd_print_invalid(ndo); 5100f74e101Schristos } 511