@@ -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,7 +676,24 @@ 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);
+
+ param.override_iv_ptr = iv;
+ } else if (ipsec_sa->esp_iv_len) {
uint32_t len;
len = odp_random_data(iv + ipsec_sa->salt_length,
@@ -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)
@@ -315,6 +316,7 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param)
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 +325,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) {