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