xref: /dflybsd-src/contrib/tcpdump/print-ip6.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
141c99275SPeter Avalos /*
241c99275SPeter Avalos  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
341c99275SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
441c99275SPeter Avalos  *
541c99275SPeter Avalos  * Redistribution and use in source and binary forms, with or without
641c99275SPeter Avalos  * modification, are permitted provided that: (1) source code distributions
741c99275SPeter Avalos  * retain the above copyright notice and this paragraph in its entirety, (2)
841c99275SPeter Avalos  * distributions including binary code include the above copyright notice and
941c99275SPeter Avalos  * this paragraph in its entirety in the documentation or other materials
1041c99275SPeter Avalos  * provided with the distribution, and (3) all advertising materials mentioning
1141c99275SPeter Avalos  * features or use of this software display the following acknowledgement:
1241c99275SPeter Avalos  * ``This product includes software developed by the University of California,
1341c99275SPeter Avalos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1441c99275SPeter Avalos  * the University nor the names of its contributors may be used to endorse
1541c99275SPeter Avalos  * or promote products derived from this software without specific prior
1641c99275SPeter Avalos  * written permission.
1741c99275SPeter Avalos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1841c99275SPeter Avalos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1941c99275SPeter Avalos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2041c99275SPeter Avalos  */
2141c99275SPeter Avalos 
22411677aeSAaron LI /* \summary: IPv6 printer */
2341c99275SPeter Avalos 
2441c99275SPeter Avalos #ifdef HAVE_CONFIG_H
25*ed775ee7SAntonio Huete Jimenez #include <config.h>
2641c99275SPeter Avalos #endif
2741c99275SPeter Avalos 
28*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
2941c99275SPeter Avalos 
3041c99275SPeter Avalos #include <string.h>
3141c99275SPeter Avalos 
3227bfbee1SPeter Avalos #include "netdissect.h"
3341c99275SPeter Avalos #include "addrtoname.h"
3441c99275SPeter Avalos #include "extract.h"
3541c99275SPeter Avalos 
3641c99275SPeter Avalos #include "ip6.h"
3741c99275SPeter Avalos #include "ipproto.h"
3841c99275SPeter Avalos 
3941c99275SPeter Avalos /*
40411677aeSAaron LI  * If routing headers are presend and valid, set dst to the final destination.
41411677aeSAaron LI  * Otherwise, set it to the IPv6 destination.
42411677aeSAaron LI  *
43411677aeSAaron LI  * This is used for UDP and TCP pseudo-header in the checksum
44411677aeSAaron LI  * calculation.
45411677aeSAaron LI  */
46411677aeSAaron LI static void
ip6_finddst(netdissect_options * ndo,nd_ipv6 * dst,const struct ip6_hdr * ip6)47*ed775ee7SAntonio Huete Jimenez ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst,
48411677aeSAaron LI             const struct ip6_hdr *ip6)
49411677aeSAaron LI {
50411677aeSAaron LI 	const u_char *cp;
51*ed775ee7SAntonio Huete Jimenez 	u_int advance;
52411677aeSAaron LI 	u_int nh;
53*ed775ee7SAntonio Huete Jimenez 	const void *dst_addr;
54411677aeSAaron LI 	const struct ip6_rthdr *dp;
55411677aeSAaron LI 	const struct ip6_rthdr0 *dp0;
56*ed775ee7SAntonio Huete Jimenez 	const struct ip6_srh *srh;
57*ed775ee7SAntonio Huete Jimenez 	const u_char *p;
58411677aeSAaron LI 	int i, len;
59411677aeSAaron LI 
60411677aeSAaron LI 	cp = (const u_char *)ip6;
61411677aeSAaron LI 	advance = sizeof(struct ip6_hdr);
62*ed775ee7SAntonio Huete Jimenez 	nh = GET_U_1(ip6->ip6_nxt);
63*ed775ee7SAntonio Huete Jimenez 	dst_addr = (const void *)ip6->ip6_dst;
64411677aeSAaron LI 
65411677aeSAaron LI 	while (cp < ndo->ndo_snapend) {
66411677aeSAaron LI 		cp += advance;
67411677aeSAaron LI 
68411677aeSAaron LI 		switch (nh) {
69411677aeSAaron LI 
70411677aeSAaron LI 		case IPPROTO_HOPOPTS:
71411677aeSAaron LI 		case IPPROTO_DSTOPTS:
72411677aeSAaron LI 		case IPPROTO_MOBILITY_OLD:
73411677aeSAaron LI 		case IPPROTO_MOBILITY:
74411677aeSAaron LI 			/*
75411677aeSAaron LI 			 * These have a header length byte, following
76411677aeSAaron LI 			 * the next header byte, giving the length of
77411677aeSAaron LI 			 * the header, in units of 8 octets, excluding
78411677aeSAaron LI 			 * the first 8 octets.
79411677aeSAaron LI 			 */
80*ed775ee7SAntonio Huete Jimenez 			advance = (GET_U_1(cp + 1) + 1) << 3;
81*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
82411677aeSAaron LI 			break;
83411677aeSAaron LI 
84411677aeSAaron LI 		case IPPROTO_FRAGMENT:
85411677aeSAaron LI 			/*
86411677aeSAaron LI 			 * The byte following the next header byte is
87411677aeSAaron LI 			 * marked as reserved, and the header is always
88411677aeSAaron LI 			 * the same size.
89411677aeSAaron LI 			 */
90411677aeSAaron LI 			advance = sizeof(struct ip6_frag);
91*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
92411677aeSAaron LI 			break;
93411677aeSAaron LI 
94411677aeSAaron LI 		case IPPROTO_ROUTING:
95411677aeSAaron LI 			/*
96411677aeSAaron LI 			 * OK, we found it.
97411677aeSAaron LI 			 */
98411677aeSAaron LI 			dp = (const struct ip6_rthdr *)cp;
99*ed775ee7SAntonio Huete Jimenez 			ND_TCHECK_SIZE(dp);
100*ed775ee7SAntonio Huete Jimenez 			len = GET_U_1(dp->ip6r_len);
101*ed775ee7SAntonio Huete Jimenez 			switch (GET_U_1(dp->ip6r_type)) {
102411677aeSAaron LI 
103411677aeSAaron LI 			case IPV6_RTHDR_TYPE_0:
104411677aeSAaron LI 			case IPV6_RTHDR_TYPE_2:		/* Mobile IPv6 ID-20 */
105411677aeSAaron LI 				dp0 = (const struct ip6_rthdr0 *)dp;
106411677aeSAaron LI 				if (len % 2 == 1)
107411677aeSAaron LI 					goto trunc;
108411677aeSAaron LI 				len >>= 1;
109*ed775ee7SAntonio Huete Jimenez 				p = (const u_char *) dp0->ip6r0_addr;
110411677aeSAaron LI 				for (i = 0; i < len; i++) {
111*ed775ee7SAntonio Huete Jimenez 					ND_TCHECK_16(p);
112*ed775ee7SAntonio Huete Jimenez 					dst_addr = (const void *)p;
113*ed775ee7SAntonio Huete Jimenez 					p += 16;
114411677aeSAaron LI 				}
115411677aeSAaron LI 				break;
116*ed775ee7SAntonio Huete Jimenez 			case IPV6_RTHDR_TYPE_4:
117*ed775ee7SAntonio Huete Jimenez 				/* IPv6 Segment Routing Header (SRH) */
118*ed775ee7SAntonio Huete Jimenez 				srh = (const struct ip6_srh *)dp;
119*ed775ee7SAntonio Huete Jimenez 				if (len % 2 == 1)
120*ed775ee7SAntonio Huete Jimenez 					goto trunc;
121*ed775ee7SAntonio Huete Jimenez 				p = (const u_char *) srh->srh_segments;
122*ed775ee7SAntonio Huete Jimenez 				/*
123*ed775ee7SAntonio Huete Jimenez 				 * The list of segments are encoded in the reverse order.
124*ed775ee7SAntonio Huete Jimenez 				 * Accordingly, the final DA is encoded in srh_segments[0]
125*ed775ee7SAntonio Huete Jimenez 				 */
126*ed775ee7SAntonio Huete Jimenez 				ND_TCHECK_16(p);
127*ed775ee7SAntonio Huete Jimenez 				dst_addr = (const void *)p;
128*ed775ee7SAntonio Huete Jimenez 				break;
129411677aeSAaron LI 
130411677aeSAaron LI 			default:
131411677aeSAaron LI 				break;
132411677aeSAaron LI 			}
133411677aeSAaron LI 
134411677aeSAaron LI 			/*
135411677aeSAaron LI 			 * Only one routing header to a customer.
136411677aeSAaron LI 			 */
137411677aeSAaron LI 			goto done;
138411677aeSAaron LI 
139411677aeSAaron LI 		case IPPROTO_AH:
140411677aeSAaron LI 		case IPPROTO_ESP:
141411677aeSAaron LI 		case IPPROTO_IPCOMP:
142411677aeSAaron LI 		default:
143411677aeSAaron LI 			/*
144411677aeSAaron LI 			 * AH and ESP are, in the RFCs that describe them,
145411677aeSAaron LI 			 * described as being "viewed as an end-to-end
146411677aeSAaron LI 			 * payload" "in the IPv6 context, so that they
147411677aeSAaron LI 			 * "should appear after hop-by-hop, routing, and
148411677aeSAaron LI 			 * fragmentation extension headers".  We assume
149411677aeSAaron LI 			 * that's the case, and stop as soon as we see
150411677aeSAaron LI 			 * one.  (We can't handle an ESP header in
151411677aeSAaron LI 			 * the general case anyway, as its length depends
152411677aeSAaron LI 			 * on the encryption algorithm.)
153411677aeSAaron LI 			 *
154411677aeSAaron LI 			 * IPComp is also "viewed as an end-to-end
155411677aeSAaron LI 			 * payload" "in the IPv6 context".
156411677aeSAaron LI 			 *
157411677aeSAaron LI 			 * All other protocols are assumed to be the final
158411677aeSAaron LI 			 * protocol.
159411677aeSAaron LI 			 */
160411677aeSAaron LI 			goto done;
161411677aeSAaron LI 		}
162411677aeSAaron LI 	}
163411677aeSAaron LI 
164411677aeSAaron LI done:
165411677aeSAaron LI trunc:
166*ed775ee7SAntonio Huete Jimenez 	GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6));
167411677aeSAaron LI }
168411677aeSAaron LI 
169411677aeSAaron LI /*
17027bfbee1SPeter Avalos  * Compute a V6-style checksum by building a pseudoheader.
17127bfbee1SPeter Avalos  */
172*ed775ee7SAntonio Huete Jimenez 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)173411677aeSAaron LI nextproto6_cksum(netdissect_options *ndo,
174411677aeSAaron LI                  const struct ip6_hdr *ip6, const uint8_t *data,
175*ed775ee7SAntonio Huete Jimenez 		 u_int len, u_int covlen, uint8_t next_proto)
17627bfbee1SPeter Avalos {
17727bfbee1SPeter Avalos         struct {
178*ed775ee7SAntonio Huete Jimenez                 nd_ipv6 ph_src;
179*ed775ee7SAntonio Huete Jimenez                 nd_ipv6 ph_dst;
180411677aeSAaron LI                 uint32_t       ph_len;
181411677aeSAaron LI                 uint8_t        ph_zero[3];
182411677aeSAaron LI                 uint8_t        ph_nxt;
18327bfbee1SPeter Avalos         } ph;
18427bfbee1SPeter Avalos         struct cksum_vec vec[2];
185*ed775ee7SAntonio Huete Jimenez         u_int nh;
18627bfbee1SPeter Avalos 
18727bfbee1SPeter Avalos         /* pseudo-header */
18827bfbee1SPeter Avalos         memset(&ph, 0, sizeof(ph));
189*ed775ee7SAntonio Huete Jimenez         GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6));
190*ed775ee7SAntonio Huete Jimenez         nh = GET_U_1(ip6->ip6_nxt);
191*ed775ee7SAntonio Huete Jimenez         switch (nh) {
192411677aeSAaron LI 
193411677aeSAaron LI         case IPPROTO_HOPOPTS:
194411677aeSAaron LI         case IPPROTO_DSTOPTS:
195411677aeSAaron LI         case IPPROTO_MOBILITY_OLD:
196411677aeSAaron LI         case IPPROTO_MOBILITY:
197411677aeSAaron LI         case IPPROTO_FRAGMENT:
198411677aeSAaron LI         case IPPROTO_ROUTING:
199411677aeSAaron LI                 /*
200411677aeSAaron LI                  * The next header is either a routing header or a header
201411677aeSAaron LI                  * after which there might be a routing header, so scan
202411677aeSAaron LI                  * for a routing header.
203411677aeSAaron LI                  */
204411677aeSAaron LI                 ip6_finddst(ndo, &ph.ph_dst, ip6);
205411677aeSAaron LI                 break;
206411677aeSAaron LI 
207411677aeSAaron LI         default:
208*ed775ee7SAntonio Huete Jimenez                 GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6));
209411677aeSAaron LI                 break;
210411677aeSAaron LI         }
21127bfbee1SPeter Avalos         ph.ph_len = htonl(len);
21227bfbee1SPeter Avalos         ph.ph_nxt = next_proto;
21327bfbee1SPeter Avalos 
214411677aeSAaron LI         vec[0].ptr = (const uint8_t *)(void *)&ph;
21527bfbee1SPeter Avalos         vec[0].len = sizeof(ph);
21627bfbee1SPeter Avalos         vec[1].ptr = data;
217411677aeSAaron LI         vec[1].len = covlen;
21827bfbee1SPeter Avalos 
21927bfbee1SPeter Avalos         return in_cksum(vec, 2);
22027bfbee1SPeter Avalos }
22127bfbee1SPeter Avalos 
22227bfbee1SPeter Avalos /*
22341c99275SPeter Avalos  * print an IP6 datagram.
22441c99275SPeter Avalos  */
22541c99275SPeter Avalos void
ip6_print(netdissect_options * ndo,const u_char * bp,u_int length)22627bfbee1SPeter Avalos ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
22741c99275SPeter Avalos {
228*ed775ee7SAntonio Huete Jimenez 	const struct ip6_hdr *ip6;
229*ed775ee7SAntonio Huete Jimenez 	int advance;
23041c99275SPeter Avalos 	u_int len;
231*ed775ee7SAntonio Huete Jimenez 	u_int total_advance;
232*ed775ee7SAntonio Huete Jimenez 	const u_char *cp;
233*ed775ee7SAntonio Huete Jimenez 	uint32_t payload_len;
234*ed775ee7SAntonio Huete Jimenez 	uint8_t nh;
23541c99275SPeter Avalos 	int fragmented = 0;
23641c99275SPeter Avalos 	u_int flow;
237*ed775ee7SAntonio Huete Jimenez 	int found_extension_header;
238*ed775ee7SAntonio Huete Jimenez 	int found_jumbo;
23941c99275SPeter Avalos 
240*ed775ee7SAntonio Huete Jimenez 	ndo->ndo_protocol = "ip6";
24141c99275SPeter Avalos 	ip6 = (const struct ip6_hdr *)bp;
24241c99275SPeter Avalos 
243*ed775ee7SAntonio Huete Jimenez 	ND_TCHECK_SIZE(ip6);
24441c99275SPeter Avalos 	if (length < sizeof (struct ip6_hdr)) {
245*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("truncated-ip6 %u", length);
24641c99275SPeter Avalos 		return;
24741c99275SPeter Avalos 	}
24841c99275SPeter Avalos 
24927bfbee1SPeter Avalos         if (!ndo->ndo_eflag)
250*ed775ee7SAntonio Huete Jimenez             ND_PRINT("IP6 ");
25141c99275SPeter Avalos 
252411677aeSAaron LI 	if (IP6_VERSION(ip6) != 6) {
253*ed775ee7SAntonio Huete Jimenez           ND_PRINT("version error: %u != 6", IP6_VERSION(ip6));
254411677aeSAaron LI           return;
255411677aeSAaron LI 	}
256411677aeSAaron LI 
257*ed775ee7SAntonio Huete Jimenez 	payload_len = GET_BE_U_2(ip6->ip6_plen);
258*ed775ee7SAntonio Huete Jimenez 	/*
259*ed775ee7SAntonio Huete Jimenez 	 * RFC 1883 says:
260*ed775ee7SAntonio Huete Jimenez 	 *
261*ed775ee7SAntonio Huete Jimenez 	 * The Payload Length field in the IPv6 header must be set to zero
262*ed775ee7SAntonio Huete Jimenez 	 * in every packet that carries the Jumbo Payload option.  If a
263*ed775ee7SAntonio Huete Jimenez 	 * packet is received with a valid Jumbo Payload option present and
264*ed775ee7SAntonio Huete Jimenez 	 * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem
265*ed775ee7SAntonio Huete Jimenez 	 * message, Code 0, should be sent to the packet's source, pointing
266*ed775ee7SAntonio Huete Jimenez 	 * to the Option Type field of the Jumbo Payload option.
267*ed775ee7SAntonio Huete Jimenez 	 *
268*ed775ee7SAntonio Huete Jimenez 	 * Later versions of the IPv6 spec don't discuss the Jumbo Payload
269*ed775ee7SAntonio Huete Jimenez 	 * option.
270*ed775ee7SAntonio Huete Jimenez 	 *
271*ed775ee7SAntonio Huete Jimenez 	 * If the payload length is 0, we temporarily just set the total
272*ed775ee7SAntonio Huete Jimenez 	 * length to the remaining data in the packet (which, for Ethernet,
273*ed775ee7SAntonio Huete Jimenez 	 * could include frame padding, but if it's a Jumbo Payload frame,
274*ed775ee7SAntonio Huete Jimenez 	 * it shouldn't even be sendable over Ethernet, so we don't worry
275*ed775ee7SAntonio Huete Jimenez 	 * about that), so we can process the extension headers in order
276*ed775ee7SAntonio Huete Jimenez 	 * to *find* a Jumbo Payload hop-by-hop option and, when we've
277*ed775ee7SAntonio Huete Jimenez 	 * processed all the extension headers, check whether we found
278*ed775ee7SAntonio Huete Jimenez 	 * a Jumbo Payload option, and fail if we haven't.
279*ed775ee7SAntonio Huete Jimenez 	 */
280*ed775ee7SAntonio Huete Jimenez 	if (payload_len != 0) {
28141c99275SPeter Avalos 		len = payload_len + sizeof(struct ip6_hdr);
28241c99275SPeter Avalos 		if (length < len)
283*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("truncated-ip6 - %u bytes missing!",
284*ed775ee7SAntonio Huete Jimenez 				len - length);
285*ed775ee7SAntonio Huete Jimenez 	} else
286*ed775ee7SAntonio Huete Jimenez 		len = length + sizeof(struct ip6_hdr);
28741c99275SPeter Avalos 
288*ed775ee7SAntonio Huete Jimenez         nh = GET_U_1(ip6->ip6_nxt);
28927bfbee1SPeter Avalos         if (ndo->ndo_vflag) {
290*ed775ee7SAntonio Huete Jimenez             flow = GET_BE_U_4(ip6->ip6_flow);
291*ed775ee7SAntonio Huete Jimenez             ND_PRINT("(");
29241c99275SPeter Avalos #if 0
29341c99275SPeter Avalos             /* rfc1883 */
29441c99275SPeter Avalos             if (flow & 0x0f000000)
295*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("pri 0x%02x, ", (flow & 0x0f000000) >> 24);
29641c99275SPeter Avalos             if (flow & 0x00ffffff)
297*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("flowlabel 0x%06x, ", flow & 0x00ffffff);
29841c99275SPeter Avalos #else
29941c99275SPeter Avalos             /* RFC 2460 */
30041c99275SPeter Avalos             if (flow & 0x0ff00000)
301*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
30241c99275SPeter Avalos             if (flow & 0x000fffff)
303*ed775ee7SAntonio Huete Jimenez 		ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff);
30441c99275SPeter Avalos #endif
30541c99275SPeter Avalos 
306*ed775ee7SAntonio Huete Jimenez             ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ",
307*ed775ee7SAntonio Huete Jimenez                          GET_U_1(ip6->ip6_hlim),
308*ed775ee7SAntonio Huete Jimenez                          tok2str(ipproto_values,"unknown",nh),
309*ed775ee7SAntonio Huete Jimenez                          nh,
310*ed775ee7SAntonio Huete Jimenez                          payload_len);
31141c99275SPeter Avalos         }
31241c99275SPeter Avalos 
31341c99275SPeter Avalos 	/*
31441c99275SPeter Avalos 	 * Cut off the snapshot length to the end of the IP payload.
31541c99275SPeter Avalos 	 */
316*ed775ee7SAntonio Huete Jimenez 	nd_push_snapend(ndo, bp + len);
31741c99275SPeter Avalos 
31841c99275SPeter Avalos 	cp = (const u_char *)ip6;
31941c99275SPeter Avalos 	advance = sizeof(struct ip6_hdr);
320*ed775ee7SAntonio Huete Jimenez 	total_advance = 0;
321*ed775ee7SAntonio Huete Jimenez 	/* Process extension headers */
322*ed775ee7SAntonio Huete Jimenez 	found_extension_header = 0;
323*ed775ee7SAntonio Huete Jimenez 	found_jumbo = 0;
32427bfbee1SPeter Avalos 	while (cp < ndo->ndo_snapend && advance > 0) {
325411677aeSAaron LI 		if (len < (u_int)advance)
326411677aeSAaron LI 			goto trunc;
32741c99275SPeter Avalos 		cp += advance;
32841c99275SPeter Avalos 		len -= advance;
329*ed775ee7SAntonio Huete Jimenez 		total_advance += advance;
33041c99275SPeter Avalos 
33141c99275SPeter Avalos 		if (cp == (const u_char *)(ip6 + 1) &&
33241c99275SPeter Avalos 		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
33341c99275SPeter Avalos 		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
334*ed775ee7SAntonio Huete Jimenez 			ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
335*ed775ee7SAntonio Huete Jimenez 				     GET_IP6ADDR_STRING(ip6->ip6_dst));
33641c99275SPeter Avalos 		}
33741c99275SPeter Avalos 
33841c99275SPeter Avalos 		switch (nh) {
339*ed775ee7SAntonio Huete Jimenez 
34041c99275SPeter Avalos 		case IPPROTO_HOPOPTS:
341*ed775ee7SAntonio Huete Jimenez 			advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
342*ed775ee7SAntonio Huete Jimenez 			if (advance < 0) {
343*ed775ee7SAntonio Huete Jimenez 				nd_pop_packet_info(ndo);
344411677aeSAaron LI 				return;
345*ed775ee7SAntonio Huete Jimenez 			}
346*ed775ee7SAntonio Huete Jimenez 			found_extension_header = 1;
347*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
34841c99275SPeter Avalos 			break;
349*ed775ee7SAntonio Huete Jimenez 
35041c99275SPeter Avalos 		case IPPROTO_DSTOPTS:
351*ed775ee7SAntonio Huete Jimenez 			advance = dstopt_process(ndo, cp);
352*ed775ee7SAntonio Huete Jimenez 			if (advance < 0) {
353*ed775ee7SAntonio Huete Jimenez 				nd_pop_packet_info(ndo);
354411677aeSAaron LI 				return;
355*ed775ee7SAntonio Huete Jimenez 			}
356*ed775ee7SAntonio Huete Jimenez 			found_extension_header = 1;
357*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
35841c99275SPeter Avalos 			break;
359*ed775ee7SAntonio Huete Jimenez 
36041c99275SPeter Avalos 		case IPPROTO_FRAGMENT:
361411677aeSAaron LI 			advance = frag6_print(ndo, cp, (const u_char *)ip6);
362*ed775ee7SAntonio Huete Jimenez 			if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
363*ed775ee7SAntonio Huete Jimenez 				nd_pop_packet_info(ndo);
36441c99275SPeter Avalos 				return;
365*ed775ee7SAntonio Huete Jimenez 			}
366*ed775ee7SAntonio Huete Jimenez 			found_extension_header = 1;
367*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
36841c99275SPeter Avalos 			fragmented = 1;
36941c99275SPeter Avalos 			break;
37041c99275SPeter Avalos 
37141c99275SPeter Avalos 		case IPPROTO_MOBILITY_OLD:
37241c99275SPeter Avalos 		case IPPROTO_MOBILITY:
37341c99275SPeter Avalos 			/*
374411677aeSAaron LI 			 * XXX - we don't use "advance"; RFC 3775 says that
37541c99275SPeter Avalos 			 * the next header field in a mobility header
37641c99275SPeter Avalos 			 * should be IPPROTO_NONE, but speaks of
377*ed775ee7SAntonio Huete Jimenez 			 * the possibility of a future extension in
37841c99275SPeter Avalos 			 * which payload can be piggybacked atop a
37941c99275SPeter Avalos 			 * mobility header.
38041c99275SPeter Avalos 			 */
381411677aeSAaron LI 			advance = mobility_print(ndo, cp, (const u_char *)ip6);
382*ed775ee7SAntonio Huete Jimenez 			if (advance < 0) {
383*ed775ee7SAntonio Huete Jimenez 				nd_pop_packet_info(ndo);
384411677aeSAaron LI 				return;
385*ed775ee7SAntonio Huete Jimenez 			}
386*ed775ee7SAntonio Huete Jimenez 			found_extension_header = 1;
387*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
388*ed775ee7SAntonio Huete Jimenez 			nd_pop_packet_info(ndo);
38941c99275SPeter Avalos 			return;
390*ed775ee7SAntonio Huete Jimenez 
39141c99275SPeter Avalos 		case IPPROTO_ROUTING:
392*ed775ee7SAntonio Huete Jimenez 			ND_TCHECK_1(cp);
393411677aeSAaron LI 			advance = rt6_print(ndo, cp, (const u_char *)ip6);
394*ed775ee7SAntonio Huete Jimenez 			if (advance < 0) {
395*ed775ee7SAntonio Huete Jimenez 				nd_pop_packet_info(ndo);
396411677aeSAaron LI 				return;
39741c99275SPeter Avalos 			}
398*ed775ee7SAntonio Huete Jimenez 			found_extension_header = 1;
399*ed775ee7SAntonio Huete Jimenez 			nh = GET_U_1(cp);
40041c99275SPeter Avalos 			break;
40141c99275SPeter Avalos 
40241c99275SPeter Avalos 		default:
403*ed775ee7SAntonio Huete Jimenez 			/*
404*ed775ee7SAntonio Huete Jimenez 			 * Not an extension header; hand off to the
405*ed775ee7SAntonio Huete Jimenez 			 * IP protocol demuxer.
406*ed775ee7SAntonio Huete Jimenez 			 */
407*ed775ee7SAntonio Huete Jimenez 			if (found_jumbo) {
408*ed775ee7SAntonio Huete Jimenez 				/*
409*ed775ee7SAntonio Huete Jimenez 				 * We saw a Jumbo Payload option.
410*ed775ee7SAntonio Huete Jimenez 				 * Set the length to the payload length
411*ed775ee7SAntonio Huete Jimenez 				 * plus the IPv6 header length, and
412*ed775ee7SAntonio Huete Jimenez 				 * change the snapshot length accordingly.
413*ed775ee7SAntonio Huete Jimenez 				 *
414*ed775ee7SAntonio Huete Jimenez 				 * But make sure it's not shorter than
415*ed775ee7SAntonio Huete Jimenez 				 * the total number of bytes we've
416*ed775ee7SAntonio Huete Jimenez 				 * processed so far.
417*ed775ee7SAntonio Huete Jimenez 				 */
418*ed775ee7SAntonio Huete Jimenez 				len = payload_len + sizeof(struct ip6_hdr);
419*ed775ee7SAntonio Huete Jimenez 				if (len < total_advance)
420*ed775ee7SAntonio Huete Jimenez 					goto trunc;
421*ed775ee7SAntonio Huete Jimenez 				if (length < len)
422*ed775ee7SAntonio Huete Jimenez 					ND_PRINT("truncated-ip6 - %u bytes missing!",
423*ed775ee7SAntonio Huete Jimenez 						len - length);
424*ed775ee7SAntonio Huete Jimenez 				nd_change_snapend(ndo, bp + len);
425*ed775ee7SAntonio Huete Jimenez 
426*ed775ee7SAntonio Huete Jimenez 				/*
427*ed775ee7SAntonio Huete Jimenez 				 * Now subtract the length of the IPv6
428*ed775ee7SAntonio Huete Jimenez 				 * header plus extension headers to get
429*ed775ee7SAntonio Huete Jimenez 				 * the payload length.
430*ed775ee7SAntonio Huete Jimenez 				 */
431*ed775ee7SAntonio Huete Jimenez 				len -= total_advance;
432*ed775ee7SAntonio Huete Jimenez 			} else {
433*ed775ee7SAntonio Huete Jimenez 				/*
434*ed775ee7SAntonio Huete Jimenez 				 * We didn't see a Jumbo Payload option;
435*ed775ee7SAntonio Huete Jimenez 				 * was the payload length zero?
436*ed775ee7SAntonio Huete Jimenez 				 */
437*ed775ee7SAntonio Huete Jimenez 				if (payload_len == 0) {
438*ed775ee7SAntonio Huete Jimenez 					/*
439*ed775ee7SAntonio Huete Jimenez 					 * Yes.  If we found an extension
440*ed775ee7SAntonio Huete Jimenez 					 * header, treat that as a truncated
441*ed775ee7SAntonio Huete Jimenez 					 * packet header, as there was
442*ed775ee7SAntonio Huete Jimenez 					 * no payload to contain an
443*ed775ee7SAntonio Huete Jimenez 					 * extension header.
444*ed775ee7SAntonio Huete Jimenez 					 */
445*ed775ee7SAntonio Huete Jimenez 					if (found_extension_header)
446*ed775ee7SAntonio Huete Jimenez 						goto trunc;
447*ed775ee7SAntonio Huete Jimenez 
448*ed775ee7SAntonio Huete Jimenez 					/*
449*ed775ee7SAntonio Huete Jimenez 					 * OK, we didn't see any extnesion
450*ed775ee7SAntonio Huete Jimenez 					 * header, but that means we have
451*ed775ee7SAntonio Huete Jimenez 					 * no payload, so set the length
452*ed775ee7SAntonio Huete Jimenez 					 * to the IPv6 header length,
453*ed775ee7SAntonio Huete Jimenez 					 * and change the snapshot length
454*ed775ee7SAntonio Huete Jimenez 					 * accordingly.
455*ed775ee7SAntonio Huete Jimenez 					 */
456*ed775ee7SAntonio Huete Jimenez 					len = sizeof(struct ip6_hdr);
457*ed775ee7SAntonio Huete Jimenez 					nd_change_snapend(ndo, bp + len);
458*ed775ee7SAntonio Huete Jimenez 
459*ed775ee7SAntonio Huete Jimenez 					/*
460*ed775ee7SAntonio Huete Jimenez 					 * Now subtract the length of
461*ed775ee7SAntonio Huete Jimenez 					 * the IPv6 header plus extension
462*ed775ee7SAntonio Huete Jimenez 					 * headers (there weren't any, so
463*ed775ee7SAntonio Huete Jimenez 					 * that's just the IPv6 header
464*ed775ee7SAntonio Huete Jimenez 					 * length) to get the payload length.
465*ed775ee7SAntonio Huete Jimenez 					 */
466*ed775ee7SAntonio Huete Jimenez 					len -= total_advance;
46741c99275SPeter Avalos 				}
46841c99275SPeter Avalos 			}
469*ed775ee7SAntonio Huete Jimenez 			ip_demux_print(ndo, cp, len, 6, fragmented,
470*ed775ee7SAntonio Huete Jimenez 				       GET_U_1(ip6->ip6_hlim), nh, bp);
471*ed775ee7SAntonio Huete Jimenez 			nd_pop_packet_info(ndo);
472*ed775ee7SAntonio Huete Jimenez 			return;
473*ed775ee7SAntonio Huete Jimenez 		}
47441c99275SPeter Avalos 
475*ed775ee7SAntonio Huete Jimenez 		/* ndo_protocol reassignment after xxx_print() calls */
476*ed775ee7SAntonio Huete Jimenez 		ndo->ndo_protocol = "ip6";
477*ed775ee7SAntonio Huete Jimenez 	}
478*ed775ee7SAntonio Huete Jimenez 
479*ed775ee7SAntonio Huete Jimenez 	nd_pop_packet_info(ndo);
48041c99275SPeter Avalos 	return;
48141c99275SPeter Avalos trunc:
482*ed775ee7SAntonio Huete Jimenez 	nd_print_trunc(ndo);
48341c99275SPeter Avalos }
484