@@ -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;
@@ -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
+
/**
* @}
*/
@@ -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, ¶m, status);
} else if (_ODP_IPPROTO_AH == state.ip_next_hdr) {
rc = ipsec_in_ah(&pkt, &state, &ipsec_sa, sa, ¶m, 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);
@@ -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);