LCOV - code coverage report
Current view: top level - vnet/ip - ip6_packet.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 196 212 92.5 %
Date: 2023-10-26 01:39:38 Functions: 34 37 91.9 %

          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             :  */

Generated by: LCOV version 1.14