@@ -118,9 +118,17 @@ struct ipsec_sa_s {
uint8_t salt[IPSEC_MAX_SALT_LEN];
uint32_t salt_length;
- unsigned dec_ttl : 1;
- unsigned copy_dscp : 1;
- unsigned copy_df : 1;
+ union {
+ unsigned flags;
+ struct {
+ unsigned dec_ttl : 1;
+ unsigned copy_dscp : 1;
+ unsigned copy_df : 1;
+
+ /* Only for outbound */
+ unsigned use_counter_iv : 1;
+ };
+ };
union {
struct {
@@ -136,6 +144,8 @@ struct ipsec_sa_s {
odp_atomic_u32_t tun_hdr_id;
odp_atomic_u32_t seq;
+ odp_atomic_u64_t counter; /* for CTR/GCM */
+
uint8_t tun_ttl;
uint8_t tun_dscp;
uint8_t tun_df;
@@ -676,23 +676,36 @@ static ipsec_sa_t *ipsec_out_single(odp_packet_t pkt,
ip_data_len +
ipsec_sa->icv_len;
- if (ipsec_sa->esp_iv_len) {
+ if (ipsec_sa->use_counter_iv) {
+ uint64_t ctr;
+
+ /* Both GCM and CTR use 8-bit counters */
+ ODP_ASSERT(sizeof(ctr) == ipsec_sa->esp_iv_len);
+
+ ctr = odp_atomic_fetch_add_u64(&ipsec_sa->out.counter,
+ 1);
+ /* Check for overrun */
+ if (ctr == 0)
+ goto out;
+
+ memcpy(iv, ipsec_sa->salt, ipsec_sa->salt_length);
+ memcpy(iv + ipsec_sa->salt_length, &ctr,
+ ipsec_sa->esp_iv_len);
+
+ } else if (ipsec_sa->esp_iv_len) {
uint32_t len;
- len = odp_random_data(iv + ipsec_sa->salt_length,
- ipsec_sa->esp_iv_len,
+ len = odp_random_data(iv, ipsec_sa->esp_iv_len,
ODP_RANDOM_CRYPTO);
if (len != ipsec_sa->esp_iv_len) {
status->error.alg = 1;
goto out;
}
-
- memcpy(iv, ipsec_sa->salt, ipsec_sa->salt_length);
-
- param.override_iv_ptr = iv;
}
+ param.override_iv_ptr = iv;
+
if (odp_packet_extend_tail(&pkt, trl_len, NULL, NULL) < 0) {
status->error.alg = 1;
goto out;
@@ -734,7 +747,6 @@ static ipsec_sa_t *ipsec_out_single(odp_packet_t pkt,
odp_packet_copy_from_mem(pkt,
ipsec_offset, _ODP_ESPHDR_LEN,
&esp);
- memcpy(iv, ipsec_sa->salt, ipsec_sa->salt_length);
odp_packet_copy_from_mem(pkt,
ipsec_offset + _ODP_ESPHDR_LEN,
ipsec_sa->esp_iv_len,
@@ -207,6 +207,7 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
ipsec_sa->context = param->context;
ipsec_sa->queue = param->dest_queue;
ipsec_sa->mode = param->mode;
+ ipsec_sa->flags = 0;
if (ODP_IPSEC_DIR_INBOUND == param->dir) {
ipsec_sa->in.lookup_mode = param->inbound.lookup_mode;
if (ODP_IPSEC_LOOKUP_DSTADDR_SPI == ipsec_sa->in.lookup_mode)
@@ -298,11 +299,13 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
case ODP_CIPHER_ALG_NULL:
ipsec_sa->esp_iv_len = 0;
ipsec_sa->esp_block_len = 1;
+ crypto_param.iv.length = 0;
break;
case ODP_CIPHER_ALG_DES:
case ODP_CIPHER_ALG_3DES_CBC:
ipsec_sa->esp_iv_len = 8;
ipsec_sa->esp_block_len = 8;
+ crypto_param.iv.length = 8;
break;
#if ODP_DEPRECATED_API
case ODP_CIPHER_ALG_AES128_CBC:
@@ -310,11 +313,13 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
case ODP_CIPHER_ALG_AES_CBC:
ipsec_sa->esp_iv_len = 16;
ipsec_sa->esp_block_len = 16;
+ crypto_param.iv.length = 16;
break;
#if ODP_DEPRECATED_API
case ODP_CIPHER_ALG_AES128_GCM:
#endif
case ODP_CIPHER_ALG_AES_GCM:
+ ipsec_sa->use_counter_iv = 1;
ipsec_sa->esp_iv_len = 8;
ipsec_sa->esp_block_len = 16;
crypto_param.iv.length = 12;
@@ -323,6 +328,10 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
return ODP_IPSEC_SA_INVALID;
}
+ if (1 == ipsec_sa->use_counter_iv &&
+ ODP_IPSEC_DIR_OUTBOUND == param->dir)
+ odp_atomic_init_u64(&ipsec_sa->out.counter, 1);
+
crypto_param.auth_digest_len = ipsec_sa->icv_len;
if (param->crypto.cipher_key_extra.length) {