From: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>

Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
---
/** Email created from pull request 304 (lumag:ipsec-ipv6-2)
 ** https://github.com/Linaro/odp/pull/304
 ** Patch: https://github.com/Linaro/odp/pull/304.patch
 ** Base sha: 4cb02e1caccb9179575e95448fd46979e17d0905
 ** Merge commit sha: 58c25c5ed099e25c8738c9220274c3bcf3fb66d2
 **/
 .../linux-generic/include/odp_ipsec_internal.h     |  1 +
 platform/linux-generic/include/protocols/udp.h     |  2 +
 platform/linux-generic/odp_ipsec.c                 | 53 +++++++++++++++++++++-
 platform/linux-generic/odp_ipsec_sad.c             |  1 +
 4 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/platform/linux-generic/include/odp_ipsec_internal.h 
b/platform/linux-generic/include/odp_ipsec_internal.h
index b294e7c4a..822c9016b 100644
--- a/platform/linux-generic/include/odp_ipsec_internal.h
+++ b/platform/linux-generic/include/odp_ipsec_internal.h
@@ -131,6 +131,7 @@ struct ipsec_sa_s {
                        unsigned        copy_df : 1;
                        unsigned        copy_flabel : 1;
                        unsigned        aes_ctr_iv : 1;
+                       unsigned        udp_encap : 1;
 
                        /* Only for outbound */
                        unsigned        use_counter_iv : 1;
diff --git a/platform/linux-generic/include/protocols/udp.h 
b/platform/linux-generic/include/protocols/udp.h
index 535aba855..85984c992 100644
--- a/platform/linux-generic/include/protocols/udp.h
+++ b/platform/linux-generic/include/protocols/udp.h
@@ -38,6 +38,8 @@ typedef struct ODP_PACKED {
 ODP_STATIC_ASSERT(sizeof(_odp_udphdr_t) == _ODP_UDPHDR_LEN,
                  "_ODP_UDPHDR_T__SIZE_ERROR");
 
+#define _ODP_UDP_IPSEC_PORT 4500
+
 /**
  * @}
  */
diff --git a/platform/linux-generic/odp_ipsec.c 
b/platform/linux-generic/odp_ipsec.c
index a48312fe9..2f4c69924 100644
--- a/platform/linux-generic/odp_ipsec.c
+++ b/platform/linux-generic/odp_ipsec.c
@@ -18,6 +18,7 @@
 #include <protocols/eth.h>
 #include <protocols/ip.h>
 #include <protocols/ipsec.h>
+#include <protocols/udp.h>
 
 #include <string.h>
 
@@ -378,9 +379,29 @@ static int ipsec_in_esp(odp_packet_t *pkt,
        _odp_esphdr_t esp;
        uint16_t ipsec_offset;
        ipsec_sa_t *ipsec_sa;
+       odp_bool_t udp_encap = false;
 
        ipsec_offset = state->ip_offset + state->ip_hdr_len;
 
+       if (_ODP_IPPROTO_UDP == state->ip_next_hdr) {
+               _odp_udphdr_t udp;
+               uint16_t ip_data_len = state->ip_tot_len -
+                                      state->ip_hdr_len;
+
+               odp_packet_copy_to_mem(*pkt, ipsec_offset,
+                                      _ODP_UDPHDR_LEN, &udp);
+
+               if (udp.dst_port != odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT) ||
+                   udp.length != odp_cpu_to_be_16(ip_data_len)) {
+                       status->error.proto = 1;
+                       return -1;
+               }
+
+               ipsec_offset += _ODP_UDPHDR_LEN;
+               state->ip_hdr_len += _ODP_UDPHDR_LEN;
+               udp_encap = true;
+       }
+
        if (odp_packet_copy_to_mem(*pkt, ipsec_offset,
                                   sizeof(esp), &esp) < 0) {
                status->error.alg = 1;
@@ -396,6 +417,11 @@ static int ipsec_in_esp(odp_packet_t *pkt,
        if (status->error.all)
                return -1;
 
+       if (!!ipsec_sa->udp_encap != udp_encap) {
+               status->error.proto = 1;
+               return -1;
+       }
+
        if (ipsec_in_iv(*pkt, state, ipsec_sa,
                        ipsec_offset + _ODP_ESPHDR_LEN) < 0) {
                status->error.alg = 1;
@@ -446,6 +472,11 @@ static int ipsec_in_esp_post(odp_packet_t pkt,
                                 ipsec_padding, esptrl.pad_len) != 0)
                return -1;
 
+       if (udp_encap) {
+               state->ip_hdr_len -= _ODP_UDPHDR_LEN;
+               state->in.hdr_len += _ODP_UDPHDR_LEN;
+       }
+
        odp_packet_copy_from_mem(pkt, state->ip_next_hdr_offset,
                                 1, &esptrl.next_header);
        state->in.trl_len += esptrl.pad_len;
@@ -603,7 +634,8 @@ static ipsec_sa_t *ipsec_in_single(odp_packet_t pkt,
        }
 
        /* Check IP header for IPSec protocols and look it up */
-       if (_ODP_IPPROTO_ESP == state.ip_next_hdr) {
+       if (_ODP_IPPROTO_ESP == state.ip_next_hdr ||
+           _ODP_IPPROTO_UDP == state.ip_next_hdr) {
                rc = ipsec_in_esp(&pkt, &state, &ipsec_sa, sa, &param, status);
        } else if (_ODP_IPPROTO_AH == state.ip_next_hdr) {
                rc = ipsec_in_ah(&pkt, &state, &ipsec_sa, sa, &param, status);
@@ -962,6 +994,7 @@ static int ipsec_out_esp(odp_packet_t *pkt,
 {
        _odp_esphdr_t esp;
        _odp_esptrl_t esptrl;
+       _odp_udphdr_t udphdr;
        uint32_t encrypt_len;
        uint16_t ip_data_len = state->ip_tot_len -
                               state->ip_hdr_len;
@@ -983,6 +1016,16 @@ static int ipsec_out_esp(odp_packet_t *pkt,
                       ip_data_len +
                       ipsec_sa->icv_len;
 
+       if (ipsec_sa->udp_encap) {
+               hdr_len += _ODP_UDPHDR_LEN;
+               proto = _ODP_IPPROTO_UDP;
+               udphdr.src_port = odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT);
+               udphdr.dst_port = odp_cpu_to_be_16(_ODP_UDP_IPSEC_PORT);
+               udphdr.length = odp_cpu_to_be_16(ip_data_len +
+                                                hdr_len + trl_len);
+               udphdr.chksum = 0; /* should be 0 by RFC */
+       }
+
        if (ipsec_out_iv(state, ipsec_sa) < 0) {
                status->error.alg = 1;
                return -1;
@@ -1030,6 +1073,14 @@ static int ipsec_out_esp(odp_packet_t *pkt,
                                 encrypt_len -
                                 _ODP_ESPTRL_LEN;
 
+       if (ipsec_sa->udp_encap) {
+               odp_packet_copy_from_mem(*pkt, ipsec_offset, _ODP_UDPHDR_LEN,
+                                        &udphdr);
+               ipsec_offset += _ODP_UDPHDR_LEN;
+               hdr_len -= _ODP_UDPHDR_LEN;
+               state->ip_hdr_len += _ODP_UDPHDR_LEN;
+       }
+
        odp_packet_copy_from_mem(*pkt,
                                 ipsec_offset, _ODP_ESPHDR_LEN,
                                 &esp);
diff --git a/platform/linux-generic/odp_ipsec_sad.c 
b/platform/linux-generic/odp_ipsec_sad.c
index 812ad0c46..82b3c4522 100644
--- a/platform/linux-generic/odp_ipsec_sad.c
+++ b/platform/linux-generic/odp_ipsec_sad.c
@@ -235,6 +235,7 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const 
odp_ipsec_sa_param_t *param)
        ipsec_sa->copy_dscp = param->opt.copy_dscp;
        ipsec_sa->copy_df = param->opt.copy_df;
        ipsec_sa->copy_flabel = param->opt.copy_flabel;
+       ipsec_sa->udp_encap = param->opt.udp_encap;
 
        odp_atomic_store_u64(&ipsec_sa->bytes, 0);
        odp_atomic_store_u64(&ipsec_sa->packets, 0);

Reply via email to