diff options
Diffstat (limited to 'platform/linux-generic/odp_ipsec_sad.c')
-rw-r--r-- | platform/linux-generic/odp_ipsec_sad.c | 68 |
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 = ¶m->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); |