xref: /netbsd-src/external/bsd/tcpdump/dist/print-ip6.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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