LCOV - code coverage report
Current view: top level - vnet/ip - ip6_to_ip4.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 161 217 74.2 %
Date: 2023-10-26 01:39:38 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 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             :  * @file
      17             :  * @brief IPv6 to IPv4 translation
      18             :  */
      19             : #ifndef __included_ip6_to_ip4_h__
      20             : #define __included_ip6_to_ip4_h__
      21             : 
      22             : #include <vnet/ip/ip.h>
      23             : 
      24             : /**
      25             :  * IPv6 to IPv4 set call back function type
      26             :  */
      27             : typedef int (*ip6_to_ip4_icmp_set_fn_t) (ip6_header_t * ip6,
      28             :                                          ip4_header_t * ip4, void *ctx);
      29             : 
      30             : typedef int (*ip6_to_ip4_tcp_udp_set_fn_t) (vlib_buffer_t * b,
      31             :                                             ip6_header_t * ip6,
      32             :                                             ip4_header_t * ip4, void *ctx);
      33             : 
      34             : /* *INDENT-OFF* */
      35             : static u8 icmp6_to_icmp_updater_pointer_table[] =
      36             :   { 0, 1, ~0, ~0,
      37             :     2, 2, 9, 8,
      38             :     12, 12, 12, 12,
      39             :     12, 12, 12, 12,
      40             :     12, 12, 12, 12,
      41             :     12, 12, 12, 12,
      42             :     24, 24, 24, 24,
      43             :     24, 24, 24, 24,
      44             :     24, 24, 24, 24,
      45             :     24, 24, 24, 24
      46             :   };
      47             : /* *INDENT-ON* */
      48             : 
      49             : #define frag_id_6to4(id) ((id) ^ ((id) >> 16))
      50             : 
      51             : /**
      52             :  * @brief Parse some useful information from IPv6 header.
      53             :  *
      54             :  * @param vm              vlib main
      55             :  * @param b               vlib buffer
      56             :  * @param ip6             IPv6 header.
      57             :  * @param buff_len        Buffer length.
      58             :  * @param l4_protocol     L4 protocol number.
      59             :  * @param l4_offset       L4 header offset.
      60             :  * @param frag_hdr_offset Fragment header offset if present, 0 otherwise.
      61             :  *
      62             :  * @returns 0 on success, non-zero value otherwise.
      63             :  */
      64             : static_always_inline int
      65         213 : ip6_parse (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6, u32 buff_len,
      66             :            u8 *l4_protocol, u16 *l4_offset, u16 *frag_hdr_offset)
      67             : {
      68             :   ip6_ext_hdr_chain_t hdr_chain;
      69             :   int res =
      70         213 :     ip6_ext_header_walk (b, ip6, IP_PROTOCOL_IPV6_FRAGMENTATION, &hdr_chain);
      71         213 :   if (res < 0)
      72             :     {
      73           1 :       return -1;
      74             :     }
      75         212 :   if (hdr_chain.eh[res].protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
      76          37 :     *frag_hdr_offset = hdr_chain.eh[res].offset;
      77             :   else
      78         175 :     *frag_hdr_offset = 0;
      79             : 
      80         212 :   *l4_protocol = hdr_chain.eh[hdr_chain.length - 1].protocol;
      81         212 :   *l4_offset = hdr_chain.eh[hdr_chain.length - 1].offset;
      82             : 
      83         212 :   return 0;
      84             : }
      85             : 
      86             : /**
      87             :  * @brief Get L4 information like port number or ICMP id from IPv6 packet.
      88             :  *
      89             :  * @param ip6        IPv6 header.
      90             :  * @param buffer_len Buffer length.
      91             :  * @param ip_protocol L4 protocol
      92             :  * @param src_port L4 src port or icmp id
      93             :  * @param dst_post L4 dst port or icmp id
      94             :  * @param icmp_type_or_tcp_flags ICMP type or TCP flags, if applicable
      95             :  * @param tcp_ack_number TCP ack number, if applicable
      96             :  * @param tcp_seq_number TCP seq number, if applicable
      97             :  *
      98             :  * @returns 1 on success, 0 otherwise.
      99             :  */
     100             : always_inline u16
     101         101 : ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6,
     102             :               u16 buffer_len, u8 * ip_protocol, u16 * src_port,
     103             :               u16 * dst_port, u8 * icmp_type_or_tcp_flags,
     104             :               u32 * tcp_ack_number, u32 * tcp_seq_number)
     105             : {
     106             :   u8 l4_protocol;
     107             :   u16 l4_offset;
     108             :   u16 frag_offset;
     109             :   u8 *l4;
     110             : 
     111         101 :   if (ip6_parse (vm, b, ip6, buffer_len, &l4_protocol, &l4_offset,
     112             :                  &frag_offset))
     113             :     {
     114           1 :       return 0;
     115             :     }
     116         121 :   if (frag_offset &&
     117          21 :       ip6_frag_hdr_offset (((ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_offset))))
     118           0 :     return 0;                   //Can't deal with non-first fragment for now
     119             : 
     120         100 :   if (ip_protocol)
     121             :     {
     122          96 :       *ip_protocol = l4_protocol;
     123             :     }
     124         100 :   l4 = u8_ptr_add (ip6, l4_offset);
     125         100 :   if (l4_protocol == IP_PROTOCOL_TCP || l4_protocol == IP_PROTOCOL_UDP)
     126             :     {
     127          63 :       if (src_port)
     128          63 :         *src_port = ((udp_header_t *) (l4))->src_port;
     129          63 :       if (dst_port)
     130          63 :         *dst_port = ((udp_header_t *) (l4))->dst_port;
     131          63 :       if (icmp_type_or_tcp_flags && l4_protocol == IP_PROTOCOL_TCP)
     132          28 :         *icmp_type_or_tcp_flags = ((tcp_header_t *) (l4))->flags;
     133          63 :       if (tcp_ack_number && l4_protocol == IP_PROTOCOL_TCP)
     134          28 :         *tcp_ack_number = ((tcp_header_t *) (l4))->ack_number;
     135          63 :       if (tcp_seq_number && l4_protocol == IP_PROTOCOL_TCP)
     136          28 :         *tcp_seq_number = ((tcp_header_t *) (l4))->seq_number;
     137             :     }
     138          37 :   else if (l4_protocol == IP_PROTOCOL_ICMP6)
     139             :     {
     140          32 :       icmp46_header_t *icmp = (icmp46_header_t *) (l4);
     141          32 :       if (icmp_type_or_tcp_flags)
     142          28 :         *icmp_type_or_tcp_flags = ((icmp46_header_t *) (l4))->type;
     143          32 :       if (icmp->type == ICMP6_echo_request)
     144             :         {
     145          18 :           if (src_port)
     146          18 :             *src_port = ((u16 *) (icmp))[2];
     147          18 :           if (dst_port)
     148          17 :             *dst_port = ((u16 *) (icmp))[2];
     149             :         }
     150          14 :       else if (icmp->type == ICMP6_echo_reply)
     151             :         {
     152           3 :           if (src_port)
     153           3 :             *src_port = ((u16 *) (icmp))[2];
     154           3 :           if (dst_port)
     155           2 :             *dst_port = ((u16 *) (icmp))[2];
     156             :         }
     157          11 :       else if (clib_net_to_host_u16 (ip6->payload_length) >= 64)
     158             :         {
     159             :           u16 ip6_pay_len;
     160             :           ip6_header_t *inner_ip6;
     161             :           u8 inner_l4_protocol;
     162             :           u16 inner_l4_offset;
     163             :           u16 inner_frag_offset;
     164             :           u8 *inner_l4;
     165             : 
     166           7 :           ip6_pay_len = clib_net_to_host_u16 (ip6->payload_length);
     167           7 :           inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     168             : 
     169           7 :           if (ip6_parse (vm, b, inner_ip6, ip6_pay_len - 8,
     170             :                          &inner_l4_protocol, &inner_l4_offset,
     171             :                          &inner_frag_offset))
     172           0 :             return 0;
     173             : 
     174           7 :           if (inner_frag_offset &&
     175           0 :               ip6_frag_hdr_offset (((ip6_frag_hdr_t *)
     176             :                                     u8_ptr_add (inner_ip6,
     177             :                                                 inner_frag_offset))))
     178           0 :             return 0;
     179             : 
     180           7 :           inner_l4 = u8_ptr_add (inner_ip6, inner_l4_offset);
     181           7 :           if (inner_l4_protocol == IP_PROTOCOL_TCP ||
     182           4 :               inner_l4_protocol == IP_PROTOCOL_UDP)
     183             :             {
     184           7 :               if (src_port)
     185           7 :                 *src_port = ((udp_header_t *) (inner_l4))->dst_port;
     186           7 :               if (dst_port)
     187           5 :                 *dst_port = ((udp_header_t *) (inner_l4))->src_port;
     188             :             }
     189           0 :           else if (inner_l4_protocol == IP_PROTOCOL_ICMP6)
     190             :             {
     191           0 :               icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_l4);
     192           0 :               if (inner_icmp->type == ICMP6_echo_request)
     193             :                 {
     194           0 :                   if (src_port)
     195           0 :                     *src_port = ((u16 *) (inner_icmp))[2];
     196           0 :                   if (dst_port)
     197           0 :                     *dst_port = ((u16 *) (inner_icmp))[2];
     198             :                 }
     199           0 :               else if (inner_icmp->type == ICMP6_echo_reply)
     200             :                 {
     201           0 :                   if (src_port)
     202           0 :                     *src_port = ((u16 *) (inner_icmp))[2];
     203           0 :                   if (dst_port)
     204           0 :                     *dst_port = ((u16 *) (inner_icmp))[2];
     205             :                 }
     206             :             }
     207             :         }
     208             :     }
     209         100 :   return 1;
     210             : }
     211             : 
     212             : /**
     213             :  * @brief Convert type and code value from ICMP6 to ICMP4.
     214             :  *
     215             :  * @param icmp      ICMP header.
     216             :  * @param inner_ip6 Inner IPv6 header if present, 0 otherwise.
     217             :  *
     218             :  * @returns 0 on success, non-zero value otherwise.
     219             :  */
     220             : static_always_inline int
     221          16 : icmp6_to_icmp_header (icmp46_header_t * icmp, ip6_header_t ** inner_ip6)
     222             : {
     223          16 :   *inner_ip6 = NULL;
     224          16 :   switch (icmp->type)
     225             :     {
     226           9 :     case ICMP6_echo_request:
     227           9 :       icmp->type = ICMP4_echo_request;
     228           9 :       break;
     229           1 :     case ICMP6_echo_reply:
     230           1 :       icmp->type = ICMP4_echo_reply;
     231           1 :       break;
     232           4 :     case ICMP6_destination_unreachable:
     233           4 :       *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     234             : 
     235           4 :       switch (icmp->code)
     236             :         {
     237           0 :         case ICMP6_destination_unreachable_no_route_to_destination:     //0
     238             :         case ICMP6_destination_unreachable_beyond_scope_of_source_address:      //2
     239             :         case ICMP6_destination_unreachable_address_unreachable: //3
     240           0 :           icmp->type = ICMP4_destination_unreachable;
     241           0 :           icmp->code =
     242             :             ICMP4_destination_unreachable_destination_unreachable_host;
     243           0 :           break;
     244           4 :         case ICMP6_destination_unreachable_destination_administratively_prohibited:     //1
     245           4 :           icmp->type =
     246             :             ICMP4_destination_unreachable;
     247           4 :           icmp->code =
     248             :             ICMP4_destination_unreachable_communication_administratively_prohibited;
     249           4 :           break;
     250           0 :         case ICMP6_destination_unreachable_port_unreachable:
     251           0 :           icmp->type = ICMP4_destination_unreachable;
     252           0 :           icmp->code = ICMP4_destination_unreachable_port_unreachable;
     253           0 :           break;
     254           0 :         default:
     255           0 :           return -1;
     256             :         }
     257           4 :       break;
     258           1 :     case ICMP6_packet_too_big:
     259           1 :       *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     260             : 
     261           1 :       icmp->type = ICMP4_destination_unreachable;
     262           1 :       icmp->code = 4;
     263             :       {
     264           1 :         u32 advertised_mtu = clib_net_to_host_u32 (*((u32 *) (icmp + 1)));
     265           1 :         advertised_mtu -= 20;
     266             :         //FIXME: = minimum(advertised MTU-20, MTU_of_IPv4_nexthop, (MTU_of_IPv6_nexthop)-20)
     267           1 :         ((u16 *) (icmp))[3] = clib_host_to_net_u16 (advertised_mtu);
     268             :       }
     269           1 :       break;
     270             : 
     271           1 :     case ICMP6_time_exceeded:
     272           1 :       *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     273             : 
     274           1 :       icmp->type = ICMP4_time_exceeded;
     275           1 :       break;
     276             : 
     277           0 :     case ICMP6_parameter_problem:
     278           0 :       *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     279             : 
     280           0 :       switch (icmp->code)
     281             :         {
     282           0 :         case ICMP6_parameter_problem_erroneous_header_field:
     283           0 :           icmp->type = ICMP4_parameter_problem;
     284           0 :           icmp->code = ICMP4_parameter_problem_pointer_indicates_error;
     285           0 :           u32 pointer = clib_net_to_host_u32 (*((u32 *) (icmp + 1)));
     286           0 :           if (pointer >= 40)
     287           0 :             return -1;
     288             : 
     289           0 :           ((u8 *) (icmp + 1))[0] =
     290           0 :             icmp6_to_icmp_updater_pointer_table[pointer];
     291           0 :           break;
     292           0 :         case ICMP6_parameter_problem_unrecognized_next_header:
     293           0 :           icmp->type = ICMP4_destination_unreachable;
     294           0 :           icmp->code = ICMP4_destination_unreachable_port_unreachable;
     295           0 :           break;
     296           0 :         case ICMP6_parameter_problem_unrecognized_option:
     297             :         default:
     298           0 :           return -1;
     299             :         }
     300           0 :       break;
     301           0 :     default:
     302           0 :       return -1;
     303             :       break;
     304             :     }
     305          16 :   return 0;
     306             : }
     307             : 
     308             : /**
     309             :  * @brief Translate TOS value from IPv6 to IPv4.
     310             :  *
     311             :  * @param ip_version_traffic_class_and_flow_label in network byte order
     312             :  *
     313             :  * @returns IPv4 TOS value.
     314             :  */
     315             : static_always_inline u8
     316          59 : ip6_translate_tos (u32 ip_version_traffic_class_and_flow_label)
     317             : {
     318          59 :   return (clib_net_to_host_u32 (ip_version_traffic_class_and_flow_label)
     319          59 :           & 0x0ff00000) >> 20;
     320             : }
     321             : 
     322             : /**
     323             :  * @brief Translate ICMP6 packet to ICMP4.
     324             :  *
     325             :  * @param p         Buffer to translate.
     326             :  * @param fn        The function to translate outer header.
     327             :  * @param ctx       A context passed in the outer header translate function.
     328             :  * @param inner_fn  The function to translate inner header.
     329             :  * @param inner_ctx A context passed in the inner header translate function.
     330             :  *
     331             :  * @returns 0 on success, non-zero value otherwise.
     332             :  */
     333             : always_inline int
     334          16 : icmp6_to_icmp (vlib_main_t * vm, vlib_buffer_t * p,
     335             :                ip6_to_ip4_icmp_set_fn_t fn, void *ctx,
     336             :                ip6_to_ip4_icmp_set_fn_t inner_fn, void *inner_ctx)
     337             : {
     338             :   ip6_header_t *ip6, *inner_ip6;
     339             :   ip4_header_t *ip4, *inner_ip4;
     340             :   u32 ip6_pay_len;
     341             :   icmp46_header_t *icmp;
     342             :   ip_csum_t csum;
     343             :   int rv;
     344             :   ip6_address_t old_src, old_dst;
     345             : 
     346          16 :   ip6 = vlib_buffer_get_current (p);
     347          16 :   ip6_pay_len = clib_net_to_host_u16 (ip6->payload_length);
     348          16 :   icmp = (icmp46_header_t *) (ip6 + 1);
     349          16 :   ASSERT (ip6_pay_len + sizeof (*ip6) <= p->current_length);
     350             : 
     351             :   //No extensions headers allowed here
     352          16 :   if (ip6->protocol != IP_PROTOCOL_ICMP6)
     353           0 :     return -1;
     354             : 
     355             :   //There are no fragmented ICMP messages, so no extension header for now
     356          16 :   if (icmp6_to_icmp_header (icmp, &inner_ip6))
     357           0 :     return -1;
     358             : 
     359          16 :   if (inner_ip6)
     360             :     {
     361             :       u16 *inner_L4_checksum, inner_l4_offset, inner_frag_offset,
     362             :         inner_frag_id;
     363             :       u8 *inner_l4, inner_protocol;
     364             : 
     365             :       //We have two headers to translate
     366             :       //   FROM
     367             :       //   [   IPv6   ]<- ext ->[IC][   IPv6   ]<- ext ->[L4 header ...
     368             :       // Handled cases:
     369             :       //                     [   IPv6   ][IC][   IPv6   ][L4 header ...
     370             :       //                 [   IPv6   ][IC][   IPv6   ][Fr][L4 header ...
     371             :       //    TO
     372             :       //                               [ IPv4][IC][ IPv4][L4 header ...
     373             : 
     374           6 :       if (ip6_parse (vm, p, inner_ip6, ip6_pay_len - 8,
     375             :                      &inner_protocol, &inner_l4_offset, &inner_frag_offset))
     376           0 :         return -1;
     377             : 
     378           6 :       inner_l4 = u8_ptr_add (inner_ip6, inner_l4_offset);
     379           6 :       inner_ip4 =
     380             :         (ip4_header_t *) u8_ptr_add (inner_l4, -sizeof (*inner_ip4));
     381           6 :       if (inner_frag_offset)
     382             :         {
     383           0 :           ip6_frag_hdr_t *inner_frag =
     384           0 :             (ip6_frag_hdr_t *) u8_ptr_add (inner_ip6, inner_frag_offset);
     385           0 :           inner_frag_id = frag_id_6to4 (inner_frag->identification);
     386             :         }
     387             :       else
     388             :         {
     389           6 :           inner_frag_id = 0;
     390             :         }
     391             : 
     392             :       //Do the translation of the inner packet
     393           6 :       if (inner_protocol == IP_PROTOCOL_TCP)
     394             :         {
     395           2 :           inner_L4_checksum = (u16 *) u8_ptr_add (inner_l4, 16);
     396             :         }
     397           4 :       else if (inner_protocol == IP_PROTOCOL_UDP)
     398             :         {
     399           3 :           inner_L4_checksum = (u16 *) u8_ptr_add (inner_l4, 6);
     400             :         }
     401           1 :       else if (inner_protocol == IP_PROTOCOL_ICMP6)
     402             :         {
     403           1 :           icmp46_header_t *inner_icmp = (icmp46_header_t *) inner_l4;
     404             :           //It cannot be of a different type as ip6_icmp_to_icmp6_in_place succeeded
     405           1 :           inner_icmp->type = (inner_icmp->type == ICMP6_echo_request) ?
     406             :             ICMP4_echo_request : ICMP4_echo_reply;
     407           1 :           inner_protocol = IP_PROTOCOL_ICMP;    //Will be copied to ip6 later
     408           1 :           inner_L4_checksum = &inner_icmp->checksum;
     409             :         }
     410             :       else
     411             :         {
     412           0 :           return -1;
     413             :         }
     414             : 
     415           6 :       old_src.as_u64[0] = inner_ip6->src_address.as_u64[0];
     416           6 :       old_src.as_u64[1] = inner_ip6->src_address.as_u64[1];
     417           6 :       old_dst.as_u64[0] = inner_ip6->dst_address.as_u64[0];
     418           6 :       old_dst.as_u64[1] = inner_ip6->dst_address.as_u64[1];
     419             : 
     420           6 :       if ((rv = inner_fn (inner_ip6, inner_ip4, inner_ctx)) != 0)
     421           0 :         return rv;
     422             : 
     423           6 :       inner_ip4->ip_version_and_header_length =
     424             :         IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
     425           6 :       inner_ip4->tos =
     426           6 :         ip6_translate_tos
     427           6 :         (inner_ip6->ip_version_traffic_class_and_flow_label);
     428           6 :       inner_ip4->length =
     429           6 :         u16_net_add (inner_ip6->payload_length,
     430             :                      sizeof (*ip4) + sizeof (*ip6) - inner_l4_offset);
     431           6 :       inner_ip4->fragment_id = inner_frag_id;
     432           6 :       inner_ip4->flags_and_fragment_offset =
     433           6 :         clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
     434           6 :       inner_ip4->ttl = inner_ip6->hop_limit;
     435           6 :       inner_ip4->protocol = inner_protocol;
     436           6 :       inner_ip4->checksum = ip4_header_checksum (inner_ip4);
     437             : 
     438           6 :       if (inner_ip4->protocol == IP_PROTOCOL_ICMP)
     439             :         {
     440             :           //Recompute ICMP checksum
     441           1 :           icmp46_header_t *inner_icmp = (icmp46_header_t *) inner_l4;
     442           1 :           inner_icmp->checksum = 0;
     443             :           csum =
     444           1 :             ip_incremental_checksum (0, inner_icmp,
     445           1 :                                      clib_net_to_host_u16 (inner_ip4->length)
     446             :                                      - sizeof (*inner_ip4));
     447           1 :           inner_icmp->checksum = ~ip_csum_fold (csum);
     448             :         }
     449             :       else
     450             :         {
     451             :           //Update to new pseudo-header
     452           5 :           csum = *inner_L4_checksum;
     453           5 :           csum = ip_csum_sub_even (csum, old_src.as_u64[0]);
     454           5 :           csum = ip_csum_sub_even (csum, old_src.as_u64[1]);
     455           5 :           csum = ip_csum_sub_even (csum, old_dst.as_u64[0]);
     456           5 :           csum = ip_csum_sub_even (csum, old_dst.as_u64[1]);
     457           5 :           csum = ip_csum_add_even (csum, inner_ip4->src_address.as_u32);
     458           5 :           csum = ip_csum_add_even (csum, inner_ip4->dst_address.as_u32);
     459           5 :           *inner_L4_checksum = ip_csum_fold (csum);
     460             :         }
     461             : 
     462             :       //Move up icmp header
     463           6 :       ip4 = (ip4_header_t *) u8_ptr_add (inner_l4, -2 * sizeof (*ip4) - 8);
     464           6 :       clib_memcpy_fast (u8_ptr_add (inner_l4, -sizeof (*ip4) - 8), icmp, 8);
     465           6 :       icmp = (icmp46_header_t *) u8_ptr_add (inner_l4, -sizeof (*ip4) - 8);
     466             :     }
     467             :   else
     468             :     {
     469             :       //Only one header to translate
     470          10 :       ip4 = (ip4_header_t *) u8_ptr_add (ip6, sizeof (*ip6) - sizeof (*ip4));
     471             :     }
     472             : 
     473          16 :   vlib_buffer_advance (p, (u32) (((u8 *) ip4) - ((u8 *) ip6)));
     474             : 
     475          16 :   if ((rv = fn (ip6, ip4, ctx)) != 0)
     476           0 :     return rv;
     477             : 
     478          16 :   ip4->ip_version_and_header_length =
     479             :     IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
     480          16 :   ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
     481          16 :   ip4->fragment_id = 0;
     482          16 :   ip4->flags_and_fragment_offset = 0;
     483          16 :   ip4->ttl = ip6->hop_limit;
     484          16 :   ip4->protocol = IP_PROTOCOL_ICMP;
     485             :   //TODO fix the length depending on offset length
     486          16 :   ip4->length = u16_net_add (ip6->payload_length,
     487             :                              (inner_ip6 ==
     488             :                               NULL) ? sizeof (*ip4) : (2 * sizeof (*ip4) -
     489             :                                                        sizeof (*ip6)));
     490          16 :   ip4->checksum = ip4_header_checksum (ip4);
     491             : 
     492             :   //Recompute ICMP checksum
     493          16 :   icmp->checksum = 0;
     494             :   csum =
     495          16 :     ip_incremental_checksum (0, icmp,
     496          16 :                              clib_net_to_host_u16 (ip4->length) -
     497             :                              sizeof (*ip4));
     498          16 :   icmp->checksum = ~ip_csum_fold (csum);
     499             : 
     500          16 :   return 0;
     501             : }
     502             : 
     503             : #endif /* __included_ip6_to_ip4_h__ */
     504             : 
     505             : /*
     506             :  * fd.io coding-style-patch-verification: ON
     507             :  *
     508             :  * Local Variables:
     509             :  * eval: (c-set-style "gnu")
     510             :  * End:
     511             :  */

Generated by: LCOV version 1.14