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