aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/odp_ipsec_sad.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/odp_ipsec_sad.c')
-rw-r--r--platform/linux-generic/odp_ipsec_sad.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/platform/linux-generic/odp_ipsec_sad.c b/platform/linux-generic/odp_ipsec_sad.c
index 0eea57a10..756370516 100644
--- a/platform/linux-generic/odp_ipsec_sad.c
+++ b/platform/linux-generic/odp_ipsec_sad.c
@@ -503,10 +503,8 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
}
ipsec_sa->mode = param->mode;
ipsec_sa->flags = 0;
- if (param->opt.esn) {
- ODP_ERR("ESN is not supported!\n");
- return ODP_IPSEC_SA_INVALID;
- }
+ ipsec_sa->esn = param->opt.esn;
+
if (ODP_IPSEC_DIR_INBOUND == param->dir) {
ipsec_sa->lookup_mode = param->inbound.lookup_mode;
if (ODP_IPSEC_LOOKUP_DSTADDR_SPI == ipsec_sa->lookup_mode) {
@@ -640,6 +638,11 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
goto error;
ipsec_sa->salt_length = 0;
+ /* ESN higher 32 bits flag.
+ * This flag is set for individual algo's.
+ * This flag is reset for combined mode algo's and ODP_AUTH_ALG_NULL.
+ */
+ ipsec_sa->insert_seq_hi = (ipsec_sa->esn) ? 1 : 0;
switch (crypto_param.cipher_alg) {
case ODP_CIPHER_ALG_NULL:
@@ -700,10 +703,17 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
case ODP_AUTH_ALG_AES128_GCM:
#endif
case ODP_AUTH_ALG_AES_GCM:
- crypto_param.auth_aad_len = sizeof(ipsec_aad_t);
+ case ODP_AUTH_ALG_AES_CCM:
+ if (ipsec_sa->esn) {
+ crypto_param.auth_aad_len = 12;
+ ipsec_sa->insert_seq_hi = 0;
+ } else {
+ crypto_param.auth_aad_len = 8;
+ }
break;
case ODP_AUTH_ALG_AES_GMAC:
- if (ODP_CIPHER_ALG_NULL != crypto_param.cipher_alg)
+ if ((ODP_CIPHER_ALG_NULL != crypto_param.cipher_alg) ||
+ ipsec_sa->esn)
goto error;
ipsec_sa->use_counter_iv = 1;
ipsec_sa->esp_iv_len = 8;
@@ -713,7 +723,12 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
salt_param = &param->crypto.auth_key_extra;
break;
case ODP_AUTH_ALG_CHACHA20_POLY1305:
- crypto_param.auth_aad_len = sizeof(ipsec_aad_t);
+ if (ipsec_sa->esn) {
+ crypto_param.auth_aad_len = 12;
+ ipsec_sa->insert_seq_hi = 0;
+ } else {
+ crypto_param.auth_aad_len = 8;
+ }
break;
default:
break;
@@ -721,6 +736,10 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
ipsec_sa->icv_len = crypto_param.auth_digest_len;
+ /* For ODP_AUTH_ALG_NULL */
+ if (!ipsec_sa->icv_len)
+ ipsec_sa->insert_seq_hi = 0;
+
if (ipsec_sa->salt_length) {
if (ipsec_sa->salt_length > IPSEC_MAX_SALT_LEN) {
ODP_ERR("IPSEC_MAX_SALT_LEN too small\n");
@@ -947,30 +966,37 @@ static uint64_t ipsec_sa_antireplay_max_seq(ipsec_sa_t *ipsec_sa)
{
uint64_t max_seq = 0;
- max_seq = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq) & 0xffffffff;
+ max_seq = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq);
+ if (!ipsec_sa->esn)
+ max_seq &= 0xffffffff;
return max_seq;
}
-int _odp_ipsec_sa_replay_precheck(ipsec_sa_t *ipsec_sa, uint32_t seq,
+int _odp_ipsec_sa_replay_precheck(ipsec_sa_t *ipsec_sa, uint64_t seq,
odp_ipsec_op_status_t *status)
{
/* Try to be as quick as possible, we will discard packets later */
- if (ipsec_sa->antireplay && ((seq + ipsec_sa->in.ar.win_size) <=
- (odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq) & 0xffffffff))) {
- status->error.antireplay = 1;
- return -1;
- }
+ if (ipsec_sa->antireplay) {
+ uint64_t wintop = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq);
+
+ if (!ipsec_sa->esn)
+ wintop &= 0xffffffff;
+ if ((seq + ipsec_sa->in.ar.win_size) <= wintop) {
+ status->error.antireplay = 1;
+ return -1;
+ }
+ }
return 0;
}
-static inline int ipsec_wslarge_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq,
+static inline int ipsec_wslarge_replay_update(ipsec_sa_t *ipsec_sa, uint64_t seq,
odp_ipsec_op_status_t *status)
{
- uint32_t bucket, wintop_bucket, new_bucket;
- uint32_t bkt_diff, bkt_cnt, top_seq;
- uint64_t bit = 0;
+ uint64_t bucket, wintop_bucket, new_bucket;
+ uint64_t bkt_diff, bkt_cnt;
+ uint64_t bit = 0, top_seq;
odp_spinlock_lock(&ipsec_sa->hot.in.lock);
@@ -1052,14 +1078,14 @@ static inline int ipsec_ws32_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq,
return 0;
}
-int _odp_ipsec_sa_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq,
+int _odp_ipsec_sa_replay_update(ipsec_sa_t *ipsec_sa, uint64_t seq,
odp_ipsec_op_status_t *status)
{
int ret;
/* Window update for ws equal to 32 */
- if (ipsec_sa->in.ar.win_size == IPSEC_AR_WIN_SIZE_MIN)
- ret = ipsec_ws32_replay_update(ipsec_sa, seq, status);
+ if ((!ipsec_sa->esn) && (ipsec_sa->in.ar.win_size == IPSEC_AR_WIN_SIZE_MIN))
+ ret = ipsec_ws32_replay_update(ipsec_sa, (seq & 0xffffffff), status);
else
ret = ipsec_wslarge_replay_update(ipsec_sa, seq, status);