xref: /freebsd/contrib/tcpdump/print-ip6.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
1b0453382SBill Fenner /*
2b0453382SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
3b0453382SBill Fenner  *	The Regents of the University of California.  All rights reserved.
4b0453382SBill Fenner  *
5b0453382SBill Fenner  * Redistribution and use in source and binary forms, with or without
6b0453382SBill Fenner  * modification, are permitted provided that: (1) source code distributions
7b0453382SBill Fenner  * retain the above copyright notice and this paragraph in its entirety, (2)
8b0453382SBill Fenner  * distributions including binary code include the above copyright notice and
9b0453382SBill Fenner  * this paragraph in its entirety in the documentation or other materials
10b0453382SBill Fenner  * provided with the distribution, and (3) all advertising materials mentioning
11b0453382SBill Fenner  * features or use of this software display the following acknowledgement:
12b0453382SBill Fenner  * ``This product includes software developed by the University of California,
13b0453382SBill Fenner  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14b0453382SBill Fenner  * the University nor the names of its contributors may be used to endorse
15b0453382SBill Fenner  * or promote products derived from this software without specific prior
16b0453382SBill Fenner  * written permission.
17b0453382SBill Fenner  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18b0453382SBill Fenner  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19b0453382SBill Fenner  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20b0453382SBill Fenner  */
21b0453382SBill Fenner 
223340d773SGleb Smirnoff /* \summary: IPv6 printer */
233340d773SGleb Smirnoff 
24ee67461eSJoseph Mingrone #include <config.h>
25b0453382SBill Fenner 
26ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
27b0453382SBill Fenner 
28943ee2b1SBill Fenner #include <string.h>
29b0453382SBill Fenner 
303340d773SGleb Smirnoff #include "netdissect.h"
31b0453382SBill Fenner #include "addrtoname.h"
32cc391cceSBruce M Simpson #include "extract.h"
33b0453382SBill Fenner 
34943ee2b1SBill Fenner #include "ip6.h"
35cc391cceSBruce M Simpson #include "ipproto.h"
36b0453382SBill Fenner 
37b0453382SBill Fenner /*
383340d773SGleb Smirnoff  * If routing headers are presend and valid, set dst to the final destination.
393340d773SGleb Smirnoff  * Otherwise, set it to the IPv6 destination.
403340d773SGleb Smirnoff  *
413340d773SGleb Smirnoff  * This is used for UDP and TCP pseudo-header in the checksum
423340d773SGleb Smirnoff  * calculation.
433340d773SGleb Smirnoff  */
443340d773SGleb Smirnoff static void
ip6_finddst(netdissect_options * ndo,nd_ipv6 * dst,const struct ip6_hdr * ip6)45ee67461eSJoseph Mingrone ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst,
463340d773SGleb Smirnoff             const struct ip6_hdr *ip6)
473340d773SGleb Smirnoff {
483340d773SGleb Smirnoff 	const u_char *cp;
49ee67461eSJoseph Mingrone 	u_int advance;
503340d773SGleb Smirnoff 	u_int nh;
51ee67461eSJoseph Mingrone 	const void *dst_addr;
523340d773SGleb Smirnoff 	const struct ip6_rthdr *dp;
533340d773SGleb Smirnoff 	const struct ip6_rthdr0 *dp0;
54ee67461eSJoseph Mingrone 	const struct ip6_srh *srh;
55ee67461eSJoseph Mingrone 	const u_char *p;
563340d773SGleb Smirnoff 	int i, len;
573340d773SGleb Smirnoff 
583340d773SGleb Smirnoff 	cp = (const u_char *)ip6;
593340d773SGleb Smirnoff 	advance = sizeof(struct ip6_hdr);
60ee67461eSJoseph Mingrone 	nh = GET_U_1(ip6->ip6_nxt);
61ee67461eSJoseph Mingrone 	dst_addr = (const void *)ip6->ip6_dst;
623340d773SGleb Smirnoff 
633340d773SGleb Smirnoff 	while (cp < ndo->ndo_snapend) {
643340d773SGleb Smirnoff 		cp += advance;
653340d773SGleb Smirnoff 
663340d773SGleb Smirnoff 		switch (nh) {
673340d773SGleb Smirnoff 
683340d773SGleb Smirnoff 		case IPPROTO_HOPOPTS:
693340d773SGleb Smirnoff 		case IPPROTO_DSTOPTS:
703340d773SGleb Smirnoff 		case IPPROTO_MOBILITY_OLD:
713340d773SGleb Smirnoff 		case IPPROTO_MOBILITY:
723340d773SGleb Smirnoff 			/*
733340d773SGleb Smirnoff 			 * These have a header length byte, following
743340d773SGleb Smirnoff 			 * the next header byte, giving the length of
753340d773SGleb Smirnoff 			 * the header, in units of 8 octets, excluding
763340d773SGleb Smirnoff 			 * the first 8 octets.
773340d773SGleb Smirnoff 			 */
78ee67461eSJoseph Mingrone 			advance = (GET_U_1(cp + 1) + 1) << 3;
79ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
803340d773SGleb Smirnoff 			break;
813340d773SGleb Smirnoff 
823340d773SGleb Smirnoff 		case IPPROTO_FRAGMENT:
833340d773SGleb Smirnoff 			/*
843340d773SGleb Smirnoff 			 * The byte following the next header byte is
853340d773SGleb Smirnoff 			 * marked as reserved, and the header is always
863340d773SGleb Smirnoff 			 * the same size.
873340d773SGleb Smirnoff 			 */
883340d773SGleb Smirnoff 			advance = sizeof(struct ip6_frag);
89ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
903340d773SGleb Smirnoff 			break;
913340d773SGleb Smirnoff 
923340d773SGleb Smirnoff 		case IPPROTO_ROUTING:
933340d773SGleb Smirnoff 			/*
943340d773SGleb Smirnoff 			 * OK, we found it.
953340d773SGleb Smirnoff 			 */
963340d773SGleb Smirnoff 			dp = (const struct ip6_rthdr *)cp;
97ee67461eSJoseph Mingrone 			ND_TCHECK_SIZE(dp);
98ee67461eSJoseph Mingrone 			len = GET_U_1(dp->ip6r_len);
99ee67461eSJoseph Mingrone 			switch (GET_U_1(dp->ip6r_type)) {
1003340d773SGleb Smirnoff 
1013340d773SGleb Smirnoff 			case IPV6_RTHDR_TYPE_0:
1023340d773SGleb Smirnoff 			case IPV6_RTHDR_TYPE_2:		/* Mobile IPv6 ID-20 */
1033340d773SGleb Smirnoff 				dp0 = (const struct ip6_rthdr0 *)dp;
1043340d773SGleb Smirnoff 				if (len % 2 == 1)
1053340d773SGleb Smirnoff 					goto trunc;
1063340d773SGleb Smirnoff 				len >>= 1;
107ee67461eSJoseph Mingrone 				p = (const u_char *) dp0->ip6r0_addr;
1083340d773SGleb Smirnoff 				for (i = 0; i < len; i++) {
109ee67461eSJoseph Mingrone 					ND_TCHECK_16(p);
110ee67461eSJoseph Mingrone 					dst_addr = (const void *)p;
111ee67461eSJoseph Mingrone 					p += 16;
1123340d773SGleb Smirnoff 				}
1133340d773SGleb Smirnoff 				break;
114ee67461eSJoseph Mingrone 			case IPV6_RTHDR_TYPE_4:
115ee67461eSJoseph Mingrone 				/* IPv6 Segment Routing Header (SRH) */
116ee67461eSJoseph Mingrone 				srh = (const struct ip6_srh *)dp;
117ee67461eSJoseph Mingrone 				if (len % 2 == 1)
118ee67461eSJoseph Mingrone 					goto trunc;
119ee67461eSJoseph Mingrone 				p = (const u_char *) srh->srh_segments;
120ee67461eSJoseph Mingrone 				/*
121ee67461eSJoseph Mingrone 				 * The list of segments are encoded in the reverse order.
122ee67461eSJoseph Mingrone 				 * Accordingly, the final DA is encoded in srh_segments[0]
123ee67461eSJoseph Mingrone 				 */
124ee67461eSJoseph Mingrone 				ND_TCHECK_16(p);
125ee67461eSJoseph Mingrone 				dst_addr = (const void *)p;
126ee67461eSJoseph Mingrone 				break;
1273340d773SGleb Smirnoff 
1283340d773SGleb Smirnoff 			default:
1293340d773SGleb Smirnoff 				break;
1303340d773SGleb Smirnoff 			}
1313340d773SGleb Smirnoff 
1323340d773SGleb Smirnoff 			/*
1333340d773SGleb Smirnoff 			 * Only one routing header to a customer.
1343340d773SGleb Smirnoff 			 */
1353340d773SGleb Smirnoff 			goto done;
1363340d773SGleb Smirnoff 
1373340d773SGleb Smirnoff 		case IPPROTO_AH:
1383340d773SGleb Smirnoff 		case IPPROTO_ESP:
1393340d773SGleb Smirnoff 		case IPPROTO_IPCOMP:
1403340d773SGleb Smirnoff 		default:
1413340d773SGleb Smirnoff 			/*
1423340d773SGleb Smirnoff 			 * AH and ESP are, in the RFCs that describe them,
1433340d773SGleb Smirnoff 			 * described as being "viewed as an end-to-end
1443340d773SGleb Smirnoff 			 * payload" "in the IPv6 context, so that they
1453340d773SGleb Smirnoff 			 * "should appear after hop-by-hop, routing, and
1463340d773SGleb Smirnoff 			 * fragmentation extension headers".  We assume
1473340d773SGleb Smirnoff 			 * that's the case, and stop as soon as we see
1483340d773SGleb Smirnoff 			 * one.  (We can't handle an ESP header in
1493340d773SGleb Smirnoff 			 * the general case anyway, as its length depends
1503340d773SGleb Smirnoff 			 * on the encryption algorithm.)
1513340d773SGleb Smirnoff 			 *
1523340d773SGleb Smirnoff 			 * IPComp is also "viewed as an end-to-end
1533340d773SGleb Smirnoff 			 * payload" "in the IPv6 context".
1543340d773SGleb Smirnoff 			 *
1553340d773SGleb Smirnoff 			 * All other protocols are assumed to be the final
1563340d773SGleb Smirnoff 			 * protocol.
1573340d773SGleb Smirnoff 			 */
1583340d773SGleb Smirnoff 			goto done;
1593340d773SGleb Smirnoff 		}
1603340d773SGleb Smirnoff 	}
1613340d773SGleb Smirnoff 
1623340d773SGleb Smirnoff done:
1633340d773SGleb Smirnoff trunc:
164ee67461eSJoseph Mingrone 	GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6));
1653340d773SGleb Smirnoff }
1663340d773SGleb Smirnoff 
1673340d773SGleb Smirnoff /*
16827df3f5dSRui Paulo  * Compute a V6-style checksum by building a pseudoheader.
16927df3f5dSRui Paulo  */
170ee67461eSJoseph Mingrone uint16_t
nextproto6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const uint8_t * data,u_int len,u_int covlen,uint8_t next_proto)1713340d773SGleb Smirnoff nextproto6_cksum(netdissect_options *ndo,
1723340d773SGleb Smirnoff                  const struct ip6_hdr *ip6, const uint8_t *data,
173ee67461eSJoseph Mingrone 		 u_int len, u_int covlen, uint8_t next_proto)
17427df3f5dSRui Paulo {
175cac3dcd5SXin LI         struct {
176ee67461eSJoseph Mingrone                 nd_ipv6 ph_src;
177ee67461eSJoseph Mingrone                 nd_ipv6 ph_dst;
1783c602fabSXin LI                 uint32_t       ph_len;
1793c602fabSXin LI                 uint8_t        ph_zero[3];
1803c602fabSXin LI                 uint8_t        ph_nxt;
181cac3dcd5SXin LI         } ph;
182cac3dcd5SXin LI         struct cksum_vec vec[2];
183ee67461eSJoseph Mingrone         u_int nh;
18427df3f5dSRui Paulo 
18527df3f5dSRui Paulo         /* pseudo-header */
186cac3dcd5SXin LI         memset(&ph, 0, sizeof(ph));
187ee67461eSJoseph Mingrone         GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6));
188ee67461eSJoseph Mingrone         nh = GET_U_1(ip6->ip6_nxt);
189ee67461eSJoseph Mingrone         switch (nh) {
1903340d773SGleb Smirnoff 
1913340d773SGleb Smirnoff         case IPPROTO_HOPOPTS:
1923340d773SGleb Smirnoff         case IPPROTO_DSTOPTS:
1933340d773SGleb Smirnoff         case IPPROTO_MOBILITY_OLD:
1943340d773SGleb Smirnoff         case IPPROTO_MOBILITY:
1953340d773SGleb Smirnoff         case IPPROTO_FRAGMENT:
1963340d773SGleb Smirnoff         case IPPROTO_ROUTING:
1973340d773SGleb Smirnoff                 /*
1983340d773SGleb Smirnoff                  * The next header is either a routing header or a header
1993340d773SGleb Smirnoff                  * after which there might be a routing header, so scan
2003340d773SGleb Smirnoff                  * for a routing header.
2013340d773SGleb Smirnoff                  */
2023340d773SGleb Smirnoff                 ip6_finddst(ndo, &ph.ph_dst, ip6);
2033340d773SGleb Smirnoff                 break;
2043340d773SGleb Smirnoff 
2053340d773SGleb Smirnoff         default:
206ee67461eSJoseph Mingrone                 GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6));
2073340d773SGleb Smirnoff                 break;
2083340d773SGleb Smirnoff         }
209cac3dcd5SXin LI         ph.ph_len = htonl(len);
210cac3dcd5SXin LI         ph.ph_nxt = next_proto;
21127df3f5dSRui Paulo 
2123c602fabSXin LI         vec[0].ptr = (const uint8_t *)(void *)&ph;
213cac3dcd5SXin LI         vec[0].len = sizeof(ph);
214cac3dcd5SXin LI         vec[1].ptr = data;
2153c602fabSXin LI         vec[1].len = covlen;
21627df3f5dSRui Paulo 
217cac3dcd5SXin LI         return in_cksum(vec, 2);
21827df3f5dSRui Paulo }
21927df3f5dSRui Paulo 
22027df3f5dSRui Paulo /*
221b0453382SBill Fenner  * print an IP6 datagram.
222b0453382SBill Fenner  */
223b0453382SBill Fenner void
ip6_print(netdissect_options * ndo,const u_char * bp,u_int length)224cac3dcd5SXin LI ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
225b0453382SBill Fenner {
226ee67461eSJoseph Mingrone 	const struct ip6_hdr *ip6;
227ee67461eSJoseph Mingrone 	int advance;
228cc391cceSBruce M Simpson 	u_int len;
229ee67461eSJoseph Mingrone 	u_int total_advance;
230ee67461eSJoseph Mingrone 	const u_char *cp;
231ee67461eSJoseph Mingrone 	uint32_t payload_len;
232ee67461eSJoseph Mingrone 	uint8_t ph, nh;
233943ee2b1SBill Fenner 	int fragmented = 0;
234b0453382SBill Fenner 	u_int flow;
235ee67461eSJoseph Mingrone 	int found_extension_header;
236ee67461eSJoseph Mingrone 	int found_jumbo;
237ee67461eSJoseph Mingrone 	int found_hbh;
238b0453382SBill Fenner 
239ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "ip6";
240b0453382SBill Fenner 	ip6 = (const struct ip6_hdr *)bp;
241b0453382SBill Fenner 
242*0a7e5f1fSJoseph Mingrone 	if (!ndo->ndo_eflag) {
243*0a7e5f1fSJoseph Mingrone 		nd_print_protocol_caps(ndo);
244*0a7e5f1fSJoseph Mingrone 		ND_PRINT(" ");
245b0453382SBill Fenner 	}
246b0453382SBill Fenner 
247*0a7e5f1fSJoseph Mingrone 	ND_ICHECK_ZU(length, <, sizeof (struct ip6_hdr));
248*0a7e5f1fSJoseph Mingrone 	ND_ICHECKMSG_U("version", IP6_VERSION(ip6), !=, 6);
2493c602fabSXin LI 
250ee67461eSJoseph Mingrone 	payload_len = GET_BE_U_2(ip6->ip6_plen);
251ee67461eSJoseph Mingrone 	/*
252ee67461eSJoseph Mingrone 	 * RFC 1883 says:
253ee67461eSJoseph Mingrone 	 *
254ee67461eSJoseph Mingrone 	 * The Payload Length field in the IPv6 header must be set to zero
255ee67461eSJoseph Mingrone 	 * in every packet that carries the Jumbo Payload option.  If a
256ee67461eSJoseph Mingrone 	 * packet is received with a valid Jumbo Payload option present and
257ee67461eSJoseph Mingrone 	 * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem
258ee67461eSJoseph Mingrone 	 * message, Code 0, should be sent to the packet's source, pointing
259ee67461eSJoseph Mingrone 	 * to the Option Type field of the Jumbo Payload option.
260ee67461eSJoseph Mingrone 	 *
261ee67461eSJoseph Mingrone 	 * Later versions of the IPv6 spec don't discuss the Jumbo Payload
262ee67461eSJoseph Mingrone 	 * option.
263ee67461eSJoseph Mingrone 	 *
264ee67461eSJoseph Mingrone 	 * If the payload length is 0, we temporarily just set the total
265ee67461eSJoseph Mingrone 	 * length to the remaining data in the packet (which, for Ethernet,
266ee67461eSJoseph Mingrone 	 * could include frame padding, but if it's a Jumbo Payload frame,
267ee67461eSJoseph Mingrone 	 * it shouldn't even be sendable over Ethernet, so we don't worry
268ee67461eSJoseph Mingrone 	 * about that), so we can process the extension headers in order
269ee67461eSJoseph Mingrone 	 * to *find* a Jumbo Payload hop-by-hop option and, when we've
270ee67461eSJoseph Mingrone 	 * processed all the extension headers, check whether we found
271ee67461eSJoseph Mingrone 	 * a Jumbo Payload option, and fail if we haven't.
272ee67461eSJoseph Mingrone 	 */
273ee67461eSJoseph Mingrone 	if (payload_len != 0) {
274cc391cceSBruce M Simpson 		len = payload_len + sizeof(struct ip6_hdr);
275*0a7e5f1fSJoseph Mingrone 		if (len > length) {
276*0a7e5f1fSJoseph Mingrone 			ND_PRINT("[header+payload length %u > length %u]",
277*0a7e5f1fSJoseph Mingrone 				 len, length);
278*0a7e5f1fSJoseph Mingrone 			nd_print_invalid(ndo);
279*0a7e5f1fSJoseph Mingrone 			ND_PRINT(" ");
280*0a7e5f1fSJoseph Mingrone 		}
281ee67461eSJoseph Mingrone 	} else
282ee67461eSJoseph Mingrone 		len = length + sizeof(struct ip6_hdr);
283cc391cceSBruce M Simpson 
284ee67461eSJoseph Mingrone 	ph = 255;
285ee67461eSJoseph Mingrone 	nh = GET_U_1(ip6->ip6_nxt);
286cac3dcd5SXin LI 	if (ndo->ndo_vflag) {
287ee67461eSJoseph Mingrone 	    flow = GET_BE_U_4(ip6->ip6_flow);
288ee67461eSJoseph Mingrone 	    ND_PRINT("(");
289c1ad1296SSam Leffler 	    /* RFC 2460 */
290c1ad1296SSam Leffler 	    if (flow & 0x0ff00000)
291ee67461eSJoseph Mingrone 	        ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
292c1ad1296SSam Leffler 	    if (flow & 0x000fffff)
293ee67461eSJoseph Mingrone 	        ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff);
294c1ad1296SSam Leffler 
295ee67461eSJoseph Mingrone 	    ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ",
296ee67461eSJoseph Mingrone 	                 GET_U_1(ip6->ip6_hlim),
297ee67461eSJoseph Mingrone 	                 tok2str(ipproto_values,"unknown",nh),
298ee67461eSJoseph Mingrone 	                 nh,
299ee67461eSJoseph Mingrone 	                 payload_len);
300c1ad1296SSam Leffler 	}
301*0a7e5f1fSJoseph Mingrone 	ND_TCHECK_SIZE(ip6);
302c1ad1296SSam Leffler 
303cc391cceSBruce M Simpson 	/*
304cc391cceSBruce M Simpson 	 * Cut off the snapshot length to the end of the IP payload.
305cc391cceSBruce M Simpson 	 */
306ee67461eSJoseph Mingrone 	if (!nd_push_snaplen(ndo, bp, len)) {
307ee67461eSJoseph Mingrone 		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
308ee67461eSJoseph Mingrone 			"%s: can't push snaplen on buffer stack", __func__);
309ee67461eSJoseph Mingrone 	}
310b0453382SBill Fenner 
311b0453382SBill Fenner 	cp = (const u_char *)ip6;
312cc391cceSBruce M Simpson 	advance = sizeof(struct ip6_hdr);
313ee67461eSJoseph Mingrone 	total_advance = 0;
314ee67461eSJoseph Mingrone 	/* Process extension headers */
315ee67461eSJoseph Mingrone 	found_extension_header = 0;
316ee67461eSJoseph Mingrone 	found_jumbo = 0;
317ee67461eSJoseph Mingrone 	found_hbh = 0;
318cac3dcd5SXin LI 	while (cp < ndo->ndo_snapend && advance > 0) {
3190bff6a5aSEd Maste 		if (len < (u_int)advance)
3200bff6a5aSEd Maste 			goto trunc;
321943ee2b1SBill Fenner 		cp += advance;
322cc391cceSBruce M Simpson 		len -= advance;
323ee67461eSJoseph Mingrone 		total_advance += advance;
324b0453382SBill Fenner 
325cc391cceSBruce M Simpson 		if (cp == (const u_char *)(ip6 + 1) &&
326cc391cceSBruce M Simpson 		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
32717cb103cSSam Leffler 		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
328ee67461eSJoseph Mingrone 			ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
329ee67461eSJoseph Mingrone 				 GET_IP6ADDR_STRING(ip6->ip6_dst));
330b0453382SBill Fenner 		}
331b0453382SBill Fenner 
332b0453382SBill Fenner 		switch (nh) {
333ee67461eSJoseph Mingrone 
334b0453382SBill Fenner 		case IPPROTO_HOPOPTS:
335ee67461eSJoseph Mingrone 			/*
336ee67461eSJoseph Mingrone 			 * The Hop-by-Hop Options header, when present,
337ee67461eSJoseph Mingrone 			 * must immediately follow the IPv6 header (RFC 8200)
338ee67461eSJoseph Mingrone 			 */
339ee67461eSJoseph Mingrone 			if (found_hbh == 1) {
340ee67461eSJoseph Mingrone 				ND_PRINT("[The Hop-by-Hop Options header was already found]");
341ee67461eSJoseph Mingrone 				nd_print_invalid(ndo);
3423340d773SGleb Smirnoff 				return;
343ee67461eSJoseph Mingrone 			}
344ee67461eSJoseph Mingrone 			if (ph != 255) {
345ee67461eSJoseph Mingrone 				ND_PRINT("[The Hop-by-Hop Options header don't follow the IPv6 header]");
346ee67461eSJoseph Mingrone 				nd_print_invalid(ndo);
347ee67461eSJoseph Mingrone 				return;
348ee67461eSJoseph Mingrone 			}
349ee67461eSJoseph Mingrone 			advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
350ee67461eSJoseph Mingrone 			if (payload_len == 0 && found_jumbo == 0) {
351ee67461eSJoseph Mingrone 				ND_PRINT("[No valid Jumbo Payload Hop-by-Hop option found]");
352ee67461eSJoseph Mingrone 				nd_print_invalid(ndo);
353ee67461eSJoseph Mingrone 				return;
354ee67461eSJoseph Mingrone 			}
355ee67461eSJoseph Mingrone 			if (advance < 0) {
356ee67461eSJoseph Mingrone 				nd_pop_packet_info(ndo);
357ee67461eSJoseph Mingrone 				return;
358ee67461eSJoseph Mingrone 			}
359ee67461eSJoseph Mingrone 			found_extension_header = 1;
360ee67461eSJoseph Mingrone 			found_hbh = 1;
361ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
362b0453382SBill Fenner 			break;
363ee67461eSJoseph Mingrone 
364b0453382SBill Fenner 		case IPPROTO_DSTOPTS:
365ee67461eSJoseph Mingrone 			advance = dstopt_process(ndo, cp);
366ee67461eSJoseph Mingrone 			if (advance < 0) {
367ee67461eSJoseph Mingrone 				nd_pop_packet_info(ndo);
3683340d773SGleb Smirnoff 				return;
369ee67461eSJoseph Mingrone 			}
370ee67461eSJoseph Mingrone 			found_extension_header = 1;
371ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
372b0453382SBill Fenner 			break;
373ee67461eSJoseph Mingrone 
374b0453382SBill Fenner 		case IPPROTO_FRAGMENT:
3753c602fabSXin LI 			advance = frag6_print(ndo, cp, (const u_char *)ip6);
376ee67461eSJoseph Mingrone 			if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
377ee67461eSJoseph Mingrone 				nd_pop_packet_info(ndo);
378c1ad1296SSam Leffler 				return;
379ee67461eSJoseph Mingrone 			}
380ee67461eSJoseph Mingrone 			found_extension_header = 1;
381ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
382943ee2b1SBill Fenner 			fragmented = 1;
383b0453382SBill Fenner 			break;
384cc391cceSBruce M Simpson 
385cc391cceSBruce M Simpson 		case IPPROTO_MOBILITY_OLD:
386cc391cceSBruce M Simpson 		case IPPROTO_MOBILITY:
387cc391cceSBruce M Simpson 			/*
388*0a7e5f1fSJoseph Mingrone 			 * RFC 3775 says that
389cc391cceSBruce M Simpson 			 * the next header field in a mobility header
390cc391cceSBruce M Simpson 			 * should be IPPROTO_NONE, but speaks of
391ee67461eSJoseph Mingrone 			 * the possibility of a future extension in
392cc391cceSBruce M Simpson 			 * which payload can be piggybacked atop a
393cc391cceSBruce M Simpson 			 * mobility header.
394cc391cceSBruce M Simpson 			 */
3953c602fabSXin LI 			advance = mobility_print(ndo, cp, (const u_char *)ip6);
396ee67461eSJoseph Mingrone 			if (advance < 0) {
397ee67461eSJoseph Mingrone 				nd_pop_packet_info(ndo);
3980bff6a5aSEd Maste 				return;
399ee67461eSJoseph Mingrone 			}
400ee67461eSJoseph Mingrone 			found_extension_header = 1;
401ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
402ee67461eSJoseph Mingrone 			nd_pop_packet_info(ndo);
403c1ad1296SSam Leffler 			return;
404ee67461eSJoseph Mingrone 
405b0453382SBill Fenner 		case IPPROTO_ROUTING:
406ee67461eSJoseph Mingrone 			ND_TCHECK_1(cp);
4073c602fabSXin LI 			advance = rt6_print(ndo, cp, (const u_char *)ip6);
408ee67461eSJoseph Mingrone 			if (advance < 0) {
409ee67461eSJoseph Mingrone 				nd_pop_packet_info(ndo);
4100bff6a5aSEd Maste 				return;
411b0453382SBill Fenner 			}
412ee67461eSJoseph Mingrone 			found_extension_header = 1;
413ee67461eSJoseph Mingrone 			nh = GET_U_1(cp);
414b0453382SBill Fenner 			break;
415b0453382SBill Fenner 
416b0453382SBill Fenner 		default:
417ee67461eSJoseph Mingrone 			/*
418ee67461eSJoseph Mingrone 			 * Not an extension header; hand off to the
419ee67461eSJoseph Mingrone 			 * IP protocol demuxer.
420ee67461eSJoseph Mingrone 			 */
421ee67461eSJoseph Mingrone 			if (found_jumbo) {
422ee67461eSJoseph Mingrone 				/*
423ee67461eSJoseph Mingrone 				 * We saw a Jumbo Payload option.
424ee67461eSJoseph Mingrone 				 * Set the length to the payload length
425ee67461eSJoseph Mingrone 				 * plus the IPv6 header length, and
426ee67461eSJoseph Mingrone 				 * change the snapshot length accordingly.
427ee67461eSJoseph Mingrone 				 *
428ee67461eSJoseph Mingrone 				 * But make sure it's not shorter than
429ee67461eSJoseph Mingrone 				 * the total number of bytes we've
430ee67461eSJoseph Mingrone 				 * processed so far.
431ee67461eSJoseph Mingrone 				 */
432ee67461eSJoseph Mingrone 				len = payload_len + sizeof(struct ip6_hdr);
433ee67461eSJoseph Mingrone 				if (len < total_advance)
434ee67461eSJoseph Mingrone 					goto trunc;
435*0a7e5f1fSJoseph Mingrone 				if (len > length) {
436*0a7e5f1fSJoseph Mingrone 					ND_PRINT("[header+payload length %u > length %u]",
437*0a7e5f1fSJoseph Mingrone 						 len, length);
438*0a7e5f1fSJoseph Mingrone 					nd_print_invalid(ndo);
439*0a7e5f1fSJoseph Mingrone 					ND_PRINT(" ");
440*0a7e5f1fSJoseph Mingrone 				}
441ee67461eSJoseph Mingrone 				nd_change_snaplen(ndo, bp, len);
442ee67461eSJoseph Mingrone 
443ee67461eSJoseph Mingrone 				/*
444ee67461eSJoseph Mingrone 				 * Now subtract the length of the IPv6
445ee67461eSJoseph Mingrone 				 * header plus extension headers to get
446ee67461eSJoseph Mingrone 				 * the payload length.
447ee67461eSJoseph Mingrone 				 */
448ee67461eSJoseph Mingrone 				len -= total_advance;
449ee67461eSJoseph Mingrone 			} else {
450ee67461eSJoseph Mingrone 				/*
451ee67461eSJoseph Mingrone 				 * We didn't see a Jumbo Payload option;
452ee67461eSJoseph Mingrone 				 * was the payload length zero?
453ee67461eSJoseph Mingrone 				 */
454ee67461eSJoseph Mingrone 				if (payload_len == 0) {
455ee67461eSJoseph Mingrone 					/*
456ee67461eSJoseph Mingrone 					 * Yes.  If we found an extension
457ee67461eSJoseph Mingrone 					 * header, treat that as a truncated
458ee67461eSJoseph Mingrone 					 * packet header, as there was
459ee67461eSJoseph Mingrone 					 * no payload to contain an
460ee67461eSJoseph Mingrone 					 * extension header.
461ee67461eSJoseph Mingrone 					 */
462ee67461eSJoseph Mingrone 					if (found_extension_header)
463ee67461eSJoseph Mingrone 						goto trunc;
464ee67461eSJoseph Mingrone 
465ee67461eSJoseph Mingrone 					/*
466ee67461eSJoseph Mingrone 					 * OK, we didn't see any extension
467ee67461eSJoseph Mingrone 					 * header, but that means we have
468ee67461eSJoseph Mingrone 					 * no payload, so set the length
469ee67461eSJoseph Mingrone 					 * to the IPv6 header length,
470ee67461eSJoseph Mingrone 					 * and change the snapshot length
471ee67461eSJoseph Mingrone 					 * accordingly.
472ee67461eSJoseph Mingrone 					 */
473ee67461eSJoseph Mingrone 					len = sizeof(struct ip6_hdr);
474ee67461eSJoseph Mingrone 					nd_change_snaplen(ndo, bp, len);
475ee67461eSJoseph Mingrone 
476ee67461eSJoseph Mingrone 					/*
477ee67461eSJoseph Mingrone 					 * Now subtract the length of
478ee67461eSJoseph Mingrone 					 * the IPv6 header plus extension
479ee67461eSJoseph Mingrone 					 * headers (there weren't any, so
480ee67461eSJoseph Mingrone 					 * that's just the IPv6 header
481ee67461eSJoseph Mingrone 					 * length) to get the payload length.
482ee67461eSJoseph Mingrone 					 */
483ee67461eSJoseph Mingrone 					len -= total_advance;
484ee67461eSJoseph Mingrone 				}
485ee67461eSJoseph Mingrone 			}
486ee67461eSJoseph Mingrone 			ip_demux_print(ndo, cp, len, 6, fragmented,
487ee67461eSJoseph Mingrone 				       GET_U_1(ip6->ip6_hlim), nh, bp);
488ee67461eSJoseph Mingrone 			nd_pop_packet_info(ndo);
489c1ad1296SSam Leffler 			return;
490b0453382SBill Fenner 		}
491ee67461eSJoseph Mingrone 		ph = nh;
492ee67461eSJoseph Mingrone 
493ee67461eSJoseph Mingrone 		/* ndo_protocol reassignment after xxx_print() calls */
494ee67461eSJoseph Mingrone 		ndo->ndo_protocol = "ip6";
495b0453382SBill Fenner 	}
496b0453382SBill Fenner 
497ee67461eSJoseph Mingrone 	nd_pop_packet_info(ndo);
498a1c2090eSBill Fenner 	return;
499a1c2090eSBill Fenner trunc:
500ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
501*0a7e5f1fSJoseph Mingrone 	return;
502*0a7e5f1fSJoseph Mingrone 
503*0a7e5f1fSJoseph Mingrone invalid:
504*0a7e5f1fSJoseph Mingrone 	nd_print_invalid(ndo);
505b0453382SBill Fenner }
506