Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * ip6/packet.h: ip6 packet format
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #ifndef included_ip6_packet_h
41 : #define included_ip6_packet_h
42 :
43 : #include <vlib/vlib.h>
44 : #include <vnet/ip/ip4_packet.h>
45 : #include <stdbool.h>
46 :
47 : typedef union
48 : {
49 : u8 as_u8[16];
50 : u16 as_u16[8];
51 : u32 as_u32[4];
52 : u64 as_u64[2];
53 : u64x2 as_u128;
54 : uword as_uword[16 / sizeof (uword)];
55 : }
56 : __clib_packed ip6_address_t;
57 :
58 : STATIC_ASSERT_SIZEOF (ip6_address_t, 16);
59 :
60 : typedef struct
61 : {
62 : ip6_address_t addr, mask;
63 : } ip6_address_and_mask_t;
64 :
65 : /* Packed so that the mhash key doesn't include uninitialized pad bytes */
66 : typedef CLIB_PACKED (struct {
67 : /* IP address must be first for ip_interface_address_get_address() to work */
68 : ip6_address_t ip6_addr;
69 : u32 fib_index;
70 : }) ip6_address_fib_t;
71 :
72 : always_inline void
73 4122 : ip6_addr_fib_init (ip6_address_fib_t * addr_fib,
74 : const ip6_address_t * address, u32 fib_index)
75 : {
76 4122 : addr_fib->ip6_addr = *address;
77 4122 : addr_fib->fib_index = fib_index;
78 4122 : }
79 :
80 : /* Special addresses:
81 : unspecified ::/128
82 : loopback ::1/128
83 : global unicast 2000::/3
84 : unique local unicast fc00::/7
85 : link local unicast fe80::/10
86 : multicast ff00::/8
87 : ietf reserved everything else. */
88 :
89 : #define foreach_ip6_multicast_address_scope \
90 : _ (loopback, 0x1) \
91 : _ (link_local, 0x2) \
92 : _ (admin_local, 0x4) \
93 : _ (site_local, 0x5) \
94 : _ (organization_local, 0x8) \
95 : _ (global, 0xe)
96 :
97 : #define foreach_ip6_multicast_link_local_group_id \
98 : _ (all_hosts, 0x1) \
99 : _ (all_routers, 0x2) \
100 : _ (rip_routers, 0x9) \
101 : _ (eigrp_routers, 0xa) \
102 : _ (pim_routers, 0xd) \
103 : _ (mldv2_routers, 0x16)
104 :
105 : typedef enum
106 : {
107 : #define _(f,n) IP6_MULTICAST_SCOPE_##f = n,
108 : foreach_ip6_multicast_address_scope
109 : #undef _
110 : } ip6_multicast_address_scope_t;
111 :
112 : typedef enum
113 : {
114 : #define _(f,n) IP6_MULTICAST_GROUP_ID_##f = n,
115 : foreach_ip6_multicast_link_local_group_id
116 : #undef _
117 : } ip6_multicast_link_local_group_id_t;
118 :
119 : always_inline uword
120 10044987 : ip6_address_is_multicast (const ip6_address_t * a)
121 : {
122 10044987 : return a->as_u8[0] == 0xff;
123 : }
124 :
125 : always_inline void
126 16163 : ip6_address_copy (ip6_address_t * dst, const ip6_address_t * src)
127 : {
128 16163 : dst->as_u64[0] = src->as_u64[0];
129 16163 : dst->as_u64[1] = src->as_u64[1];
130 16163 : }
131 :
132 : always_inline void
133 35039 : ip6_set_reserved_multicast_address (ip6_address_t * a,
134 : ip6_multicast_address_scope_t scope,
135 : u16 id)
136 : {
137 35039 : a->as_u64[0] = a->as_u64[1] = 0;
138 35039 : a->as_u16[0] = clib_host_to_net_u16 (0xff00 | scope);
139 35039 : a->as_u16[7] = clib_host_to_net_u16 (id);
140 35039 : }
141 :
142 : always_inline void
143 13504 : ip6_set_solicited_node_multicast_address (ip6_address_t * a, u32 id)
144 : {
145 : /* 0xff02::1:ffXX:XXXX. */
146 13504 : a->as_u64[0] = a->as_u64[1] = 0;
147 13504 : a->as_u16[0] = clib_host_to_net_u16 (0xff02);
148 13504 : a->as_u8[11] = 1;
149 13504 : ASSERT ((id >> 24) == 0);
150 13504 : id |= 0xff << 24;
151 13504 : a->as_u32[3] = clib_host_to_net_u32 (id);
152 13504 : }
153 :
154 : always_inline void
155 13 : ip6_multicast_ethernet_address (u8 * ethernet_address, u32 group_id)
156 : {
157 13 : ethernet_address[0] = 0x33;
158 13 : ethernet_address[1] = 0x33;
159 13 : ethernet_address[2] = ((group_id >> 24) & 0xff);
160 13 : ethernet_address[3] = ((group_id >> 16) & 0xff);
161 13 : ethernet_address[4] = ((group_id >> 8) & 0xff);
162 13 : ethernet_address[5] = ((group_id >> 0) & 0xff);
163 13 : }
164 :
165 : always_inline uword
166 74237 : ip6_address_is_equal (const ip6_address_t * a, const ip6_address_t * b)
167 : {
168 : int i;
169 222562 : for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
170 148407 : if (a->as_uword[i] != b->as_uword[i])
171 82 : return 0;
172 74155 : return 1;
173 : }
174 :
175 : always_inline uword
176 0 : ip6_address_is_equal_masked (const ip6_address_t * a,
177 : const ip6_address_t * b,
178 : const ip6_address_t * mask)
179 : {
180 : int i;
181 0 : for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
182 : {
183 : uword a_masked, b_masked;
184 0 : a_masked = a->as_uword[i] & mask->as_uword[i];
185 0 : b_masked = b->as_uword[i] & mask->as_uword[i];
186 :
187 0 : if (a_masked != b_masked)
188 0 : return 0;
189 : }
190 0 : return 1;
191 : }
192 :
193 : always_inline void
194 2187 : ip6_address_mask (ip6_address_t * a, const ip6_address_t * mask)
195 : {
196 : int i;
197 6561 : for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
198 4374 : a->as_uword[i] &= mask->as_uword[i];
199 2187 : }
200 :
201 : always_inline void
202 1943 : ip6_address_set_zero (ip6_address_t * a)
203 : {
204 : int i;
205 5829 : for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
206 3886 : a->as_uword[i] = 0;
207 1943 : }
208 :
209 : always_inline void
210 16500 : ip6_address_mask_from_width (ip6_address_t * a, u32 width)
211 : {
212 : int i, byte, bit, bitnum;
213 16500 : ASSERT (width <= 128);
214 16500 : clib_memset (a, 0, sizeof (a[0]));
215 2114802 : for (i = 0; i < width; i++)
216 : {
217 2098308 : bitnum = (7 - (i & 7));
218 2098308 : byte = i / 8;
219 2098308 : bit = 1 << bitnum;
220 2098308 : a->as_u8[byte] |= bit;
221 : }
222 16500 : }
223 :
224 : always_inline uword
225 37942 : ip6_address_is_zero (const ip6_address_t * a)
226 : {
227 : int i;
228 46468 : for (i = 0; i < ARRAY_LEN (a->as_uword); i++)
229 42205 : if (a->as_uword[i] != 0)
230 33679 : return 0;
231 4263 : return 1;
232 : }
233 :
234 : /* Check for unspecified address ::0 */
235 : always_inline uword
236 4057 : ip6_address_is_unspecified (const ip6_address_t * a)
237 : {
238 4057 : return ip6_address_is_zero (a);
239 : }
240 :
241 : /* Check for loopback address ::1 */
242 : always_inline uword
243 : ip6_address_is_loopback (const ip6_address_t * a)
244 : {
245 : return (a->as_u64[0] == 0 &&
246 : a->as_u32[2] == 0 &&
247 : a->as_u16[6] == 0 && a->as_u8[14] == 0 && a->as_u8[15] == 1);
248 : }
249 :
250 : /* Check for link local unicast fe80::/10. */
251 : always_inline uword
252 95455 : ip6_address_is_link_local_unicast (const ip6_address_t * a)
253 : {
254 95455 : return a->as_u8[0] == 0xfe && (a->as_u8[1] & 0xc0) == 0x80;
255 : }
256 :
257 : /* Check for unique local unicast fc00::/7. */
258 : always_inline uword
259 0 : ip6_address_is_local_unicast (const ip6_address_t * a)
260 : {
261 0 : return (a->as_u8[0] & 0xfe) == 0xfc;
262 : }
263 :
264 : /* Check for unique global unicast 2000::/3. */
265 : always_inline uword
266 0 : ip6_address_is_global_unicast (const ip6_address_t * a)
267 : {
268 0 : return (a->as_u8[0] & 0xe0) == 0x20;
269 : }
270 :
271 : /* Check for solicited node multicast 0xff02::1:ff00:0/104 */
272 : always_inline uword
273 : ip6_is_solicited_node_multicast_address (const ip6_address_t * a)
274 : {
275 : return (a->as_u32[0] == clib_host_to_net_u32 (0xff020000)
276 : && a->as_u32[1] == 0
277 : && a->as_u32[2] == clib_host_to_net_u32 (1)
278 : && a->as_u8[12] == 0xff);
279 : }
280 :
281 : always_inline u32
282 : ip6_address_hash_to_u32 (const ip6_address_t * a)
283 : {
284 : return (a->as_u32[0] ^ a->as_u32[1] ^ a->as_u32[2] ^ a->as_u32[3]);
285 : }
286 :
287 : always_inline u64
288 2668 : ip6_address_hash_to_u64 (const ip6_address_t * a)
289 : {
290 2668 : return (a->as_u64[0] ^ a->as_u64[1]);
291 : }
292 :
293 : typedef struct
294 : {
295 : /* 4 bit version, 8 bit traffic class and 20 bit flow label. */
296 : u32 ip_version_traffic_class_and_flow_label;
297 :
298 : /* Total packet length not including this header (but including
299 : any extension headers if present). */
300 : u16 payload_length;
301 :
302 : /* Protocol for next header. */
303 : u8 protocol;
304 :
305 : /* Hop limit decremented by router at each hop. */
306 : u8 hop_limit;
307 :
308 : /* Source and destination address. */
309 : ip6_address_t src_address, dst_address;
310 : } ip6_header_t;
311 :
312 : #define IP6_PACKET_TC_MASK 0x0FF00000
313 : #define IP6_PACKET_DSCP_MASK 0x0FC00000
314 : #define IP6_PACKET_ECN_MASK 0x00300000
315 : #define IP6_PACKET_FL_MASK 0x000FFFFF
316 :
317 : always_inline ip_dscp_t
318 : ip6_traffic_class (const ip6_header_t * i)
319 : {
320 : return (i->ip_version_traffic_class_and_flow_label & IP6_PACKET_TC_MASK) >>
321 : 20;
322 : }
323 :
324 : static_always_inline ip_dscp_t
325 592 : ip6_traffic_class_network_order (const ip6_header_t * ip6)
326 : {
327 592 : return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
328 592 : & IP6_PACKET_TC_MASK) >> 20;
329 : }
330 :
331 : static_always_inline ip_dscp_t
332 6152 : ip6_dscp_network_order (const ip6_header_t * ip6)
333 : {
334 6152 : return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
335 6152 : & IP6_PACKET_DSCP_MASK) >> 22;
336 : }
337 :
338 : static_always_inline ip_ecn_t
339 2030 : ip6_ecn_network_order (const ip6_header_t * ip6)
340 : {
341 2030 : return (clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label)
342 2030 : & IP6_PACKET_ECN_MASK) >> 20;
343 : }
344 :
345 : static_always_inline void
346 592 : ip6_set_traffic_class_network_order (ip6_header_t * ip6, ip_dscp_t dscp)
347 : {
348 : u32 tmp =
349 592 : clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
350 592 : tmp &= 0xf00fffff;
351 592 : tmp |= (dscp << 20);
352 592 : ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
353 592 : }
354 :
355 : static_always_inline void
356 9143 : ip6_set_dscp_network_order (ip6_header_t * ip6, ip_dscp_t dscp)
357 : {
358 : u32 tmp =
359 9143 : clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
360 9143 : tmp &= 0xf03fffff;
361 9143 : tmp |= (dscp << 22);
362 9143 : ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
363 9143 : }
364 :
365 : static_always_inline void
366 2030 : ip6_set_ecn_network_order (ip6_header_t * ip6, ip_ecn_t ecn)
367 : {
368 : u32 tmp =
369 2030 : clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
370 2030 : tmp &= 0xffcfffff;
371 2030 : tmp |= ((0x3 & ecn) << 20);
372 2030 : ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
373 2030 : }
374 :
375 : static_always_inline u32
376 3271 : ip6_flow_label_network_order (const ip6_header_t *ip6)
377 : {
378 : u32 tmp =
379 3271 : clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
380 3271 : return (tmp & 0xfffff);
381 : }
382 :
383 : static_always_inline void
384 1787 : ip6_set_flow_label_network_order (ip6_header_t *ip6, u32 flow_label)
385 : {
386 : u32 tmp =
387 1787 : clib_net_to_host_u32 (ip6->ip_version_traffic_class_and_flow_label);
388 1787 : tmp &= 0xfff00000;
389 1787 : tmp |= flow_label & 0x000fffff;
390 1787 : ip6->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (tmp);
391 1787 : }
392 :
393 : static_always_inline u32
394 508 : ip6_hop_limit_network_order (const ip6_header_t *ip6)
395 : {
396 508 : return (ip6->hop_limit);
397 : }
398 :
399 : static_always_inline void
400 635 : ip6_set_hop_limit_network_order (ip6_header_t *ip6, u8 hop_limit)
401 : {
402 635 : ip6->hop_limit = hop_limit;
403 635 : }
404 :
405 : always_inline void *
406 248204 : ip6_next_header (ip6_header_t * i)
407 : {
408 248204 : return (void *) (i + 1);
409 : }
410 :
411 : always_inline void
412 : ip6_copy_header (ip6_header_t * dst, const ip6_header_t * src)
413 : {
414 : dst->ip_version_traffic_class_and_flow_label =
415 : src->ip_version_traffic_class_and_flow_label;
416 : dst->payload_length = src->payload_length;
417 : dst->protocol = src->protocol;
418 : dst->hop_limit = src->hop_limit;
419 :
420 : dst->src_address.as_uword[0] = src->src_address.as_uword[0];
421 : dst->src_address.as_uword[1] = src->src_address.as_uword[1];
422 : dst->dst_address.as_uword[0] = src->dst_address.as_uword[0];
423 : dst->dst_address.as_uword[1] = src->dst_address.as_uword[1];
424 : }
425 :
426 : typedef CLIB_PACKED (struct {
427 : u8 data;
428 : }) ip6_pad1_option_t;
429 :
430 : typedef CLIB_PACKED (struct {
431 : u8 type;
432 : u8 len;
433 : u8 data[0];
434 : }) ip6_padN_option_t;
435 :
436 : typedef CLIB_PACKED (struct {
437 : #define IP6_MLDP_ALERT_TYPE 0x5
438 : u8 type;
439 : u8 len;
440 : u16 value;
441 : }) ip6_router_alert_option_t;
442 :
443 : typedef CLIB_PACKED (struct {
444 : u8 next_hdr;
445 : /* Length of this header plus option data in 8 byte units. */
446 : u8 n_data_u64s;
447 : }) ip6_ext_header_t;
448 :
449 : #define foreach_ext_hdr_type \
450 : _(IP6_HOP_BY_HOP_OPTIONS) \
451 : _(IPV6_ROUTE) \
452 : _(IP6_DESTINATION_OPTIONS) \
453 : _(MOBILITY) \
454 : _(HIP) \
455 : _(SHIM6)
456 :
457 : always_inline u8
458 1118263 : ip6_ext_hdr (u8 nexthdr)
459 : {
460 : #ifdef CLIB_HAVE_VEC128
461 : static const u8x16 ext_hdr_types = {
462 : #define _(x) IP_PROTOCOL_##x,
463 : foreach_ext_hdr_type
464 : #undef _
465 : };
466 :
467 1118263 : return !u8x16_is_all_zero (ext_hdr_types == u8x16_splat (nexthdr));
468 : #else
469 : /*
470 : * find out if nexthdr is an extension header or a protocol
471 : */
472 : return 0
473 : #define _(x) || (nexthdr == IP_PROTOCOL_##x)
474 : foreach_ext_hdr_type;
475 : #undef _
476 : #endif
477 : }
478 :
479 : typedef CLIB_PACKED (struct {
480 : u8 next_hdr;
481 : /* Length of this header plus option data in 8 byte units. */
482 : u8 n_data_u64s;
483 : u8 data[0];
484 : }) ip6_hop_by_hop_ext_t;
485 :
486 : typedef CLIB_PACKED (struct {
487 : u8 next_hdr;
488 : u8 rsv;
489 : u16 fragment_offset_and_more;
490 : u32 identification;
491 : }) ip6_frag_hdr_t;
492 :
493 : #define ip6_frag_hdr_offset(hdr) \
494 : (clib_net_to_host_u16 ((hdr)->fragment_offset_and_more) >> 3)
495 :
496 : #define ip6_frag_hdr_offset_bytes(hdr) (8 * ip6_frag_hdr_offset (hdr))
497 :
498 : #define ip6_frag_hdr_more(hdr) \
499 : (clib_net_to_host_u16 ((hdr)->fragment_offset_and_more) & 0x1)
500 :
501 : #define ip6_frag_hdr_offset_and_more(offset, more) \
502 : clib_host_to_net_u16 (((offset) << 3) + !!(more))
503 :
504 : #define ip6_ext_header_len(p) ((((ip6_ext_header_t *)(p))->n_data_u64s+1) << 3)
505 : #define ip6_ext_authhdr_len(p) ((((ip6_ext_header_t *)(p))->n_data_u64s+2) << 2)
506 :
507 : static inline int
508 77168 : ip6_ext_header_len_s (ip_protocol_t nh, void *p)
509 : {
510 77168 : if (ip6_ext_hdr (nh))
511 292 : return ip6_ext_header_len (p);
512 76883 : switch (nh)
513 : {
514 1911 : case IP_PROTOCOL_IPSEC_AH:
515 1911 : return ip6_ext_authhdr_len (p);
516 12873 : case IP_PROTOCOL_IPV6_FRAGMENTATION:
517 12873 : return sizeof (ip6_frag_hdr_t);
518 34747 : case IP_PROTOCOL_ICMP6:
519 34747 : return 4;
520 8211 : case IP_PROTOCOL_UDP:
521 8211 : return 8;
522 5628 : case IP_PROTOCOL_TCP:
523 5628 : return 20;
524 13513 : default: /* Caller is responsible for validating the length of terminating
525 : protocols */
526 : ;
527 : }
528 13513 : return 0;
529 : }
530 :
531 : always_inline void *
532 53 : ip6_ext_next_header (ip6_ext_header_t * ext_hdr)
533 : {
534 53 : return (void *) ((u8 *) ext_hdr + ip6_ext_header_len (ext_hdr));
535 : }
536 :
537 : always_inline void *
538 14765 : ip6_ext_next_header_offset (void *hdr, u16 offset)
539 : {
540 14765 : return (hdr + offset);
541 : }
542 :
543 : always_inline int
544 8158 : vlib_object_within_buffer_data (vlib_main_t * vm, vlib_buffer_t * b,
545 : void *obj, size_t len)
546 : {
547 8158 : u8 *o = obj;
548 8158 : if (o < b->data ||
549 8158 : o + len > b->data + vlib_buffer_get_default_data_size (vm))
550 0 : return 0;
551 8158 : return 1;
552 : }
553 :
554 : /* Returns the number of bytes left in buffer from p. */
555 : static inline u32
556 77165 : vlib_bytes_left_in_buffer (vlib_buffer_t *b, void *obj)
557 : {
558 77165 : return b->current_length - (((u8 *) obj - b->data) - b->current_data);
559 : }
560 :
561 : always_inline void *
562 82943 : ip6_ext_next_header_s (ip_protocol_t cur_nh, void *hdr, u32 max_offset,
563 : u32 *offset, int *res_nh, bool *last)
564 : {
565 82943 : u16 hdrlen = 0;
566 82943 : int new_nh = -1;
567 82943 : void *res = 0;
568 82943 : if (ip6_ext_hdr (cur_nh))
569 : {
570 293 : hdrlen = ip6_ext_header_len (hdr);
571 293 : new_nh = ((ip6_ext_header_t *) hdr)->next_hdr;
572 293 : res = hdr + hdrlen;
573 : }
574 82651 : else if (cur_nh == IP_PROTOCOL_IPV6_FRAGMENTATION)
575 : {
576 12864 : ip6_frag_hdr_t *frag_hdr = (ip6_frag_hdr_t *) hdr;
577 12864 : if (ip6_frag_hdr_offset (frag_hdr) > 0)
578 9291 : *last = true;
579 12863 : new_nh = frag_hdr->next_hdr;
580 12863 : hdrlen = sizeof (ip6_frag_hdr_t);
581 12863 : res = hdr + hdrlen;
582 : }
583 69787 : else if (cur_nh == IP_PROTOCOL_IPSEC_AH)
584 : {
585 1917 : new_nh = ((ip6_ext_header_t *) hdr)->next_hdr;
586 1917 : hdrlen = ip6_ext_authhdr_len (hdr);
587 1917 : res = hdr + hdrlen;
588 : }
589 : else
590 : {
591 : ;
592 : }
593 :
594 82943 : if (res && (*offset + hdrlen) >= max_offset)
595 : {
596 5 : return 0;
597 : }
598 82938 : *res_nh = new_nh;
599 82938 : *offset += hdrlen;
600 82938 : return res;
601 : }
602 :
603 : #define IP6_EXT_HDR_MAX (4) /* Maximum number of headers */
604 : #define IP6_EXT_HDR_MAX_DEPTH (256) /* Maximum header depth */
605 : typedef struct
606 : {
607 : int length;
608 : struct
609 : {
610 : u16 protocol;
611 : u16 offset;
612 : } eh[IP6_EXT_HDR_MAX];
613 : } ip6_ext_hdr_chain_t;
614 :
615 : /*
616 : * Find ipv6 extension header within ipv6 header within
617 : * whichever is smallest of buffer or IP6_EXT_HDR_MAX_DEPTH.
618 : * The complete header chain must be in first buffer.
619 : *
620 : * The complete header chain (up to the terminating header) is
621 : * returned in res.
622 : * Returns the index of the find_hdr_type if > 0. Otherwise
623 : * it returns the index of the last header.
624 : */
625 : always_inline int
626 77166 : ip6_ext_header_walk (vlib_buffer_t *b, ip6_header_t *ip, int find_hdr_type,
627 : ip6_ext_hdr_chain_t *res)
628 : {
629 77166 : int i = 0;
630 77166 : int found = -1;
631 77166 : void *next_header = ip6_next_header (ip);
632 77165 : int next_proto = ip->protocol;
633 77165 : res->length = 0;
634 77165 : u32 n_bytes_this_buffer =
635 77165 : clib_min (vlib_bytes_left_in_buffer (b, ip), IP6_EXT_HDR_MAX_DEPTH);
636 77165 : u32 max_offset = clib_min (n_bytes_this_buffer,
637 : sizeof (ip6_header_t) +
638 : clib_net_to_host_u16 (ip->payload_length));
639 77169 : u32 offset = sizeof (ip6_header_t);
640 77169 : if ((ip6_ext_header_len_s (ip->protocol, next_header) + offset) > max_offset)
641 : {
642 7 : return -1;
643 : }
644 77168 : bool last = false;
645 160113 : while (next_header)
646 : {
647 : /* Move on to next header */
648 92237 : res->eh[i].offset = offset;
649 92237 : res->eh[i].protocol = next_proto;
650 92237 : if (next_proto == find_hdr_type)
651 14808 : found = i;
652 92237 : i++;
653 92237 : if (last)
654 9289 : break;
655 82948 : if (i >= IP6_EXT_HDR_MAX)
656 0 : break;
657 82948 : next_header = ip6_ext_next_header_s (next_proto, next_header, max_offset,
658 : &offset, &next_proto, &last);
659 : }
660 77165 : res->length = i;
661 77165 : if (find_hdr_type < 0)
662 60613 : return i - 1;
663 16552 : return found != -1 ? found : i - 1;
664 : }
665 :
666 : always_inline void *
667 1978 : ip6_ext_header_find (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip,
668 : int find_hdr_type, ip6_ext_header_t **prev_ext_header)
669 : {
670 : ip6_ext_hdr_chain_t hdr_chain;
671 1978 : int res = ip6_ext_header_walk (b, ip, find_hdr_type, &hdr_chain);
672 1978 : if (res < 0)
673 0 : return 0;
674 :
675 1978 : if (prev_ext_header)
676 : {
677 1942 : if (res > 0)
678 : {
679 0 : *prev_ext_header =
680 0 : ip6_ext_next_header_offset (ip, hdr_chain.eh[res - 1].offset);
681 : }
682 : else
683 : {
684 1942 : *prev_ext_header = 0;
685 : }
686 : }
687 1978 : if (find_hdr_type == hdr_chain.eh[res].protocol)
688 1955 : return ip6_ext_next_header_offset (ip, hdr_chain.eh[res].offset);
689 23 : return 0;
690 : }
691 :
692 : #endif /* included_ip6_packet_h */
693 :
694 : /*
695 : * fd.io coding-style-patch-verification: ON
696 : *
697 : * Local Variables:
698 : * eval: (c-set-style "gnu")
699 : * End:
700 : */
|