ip6: fix ip6-michain trace function
[vpp.git] / src / plugins / ikev2 / ikev2.c
index f0eaa7a..9bea2c9 100644 (file)
@@ -211,6 +211,8 @@ ikev2_select_proposal (ikev2_sa_proposal_t * proposals,
        rv->proposal_num = proposal->proposal_num;
        rv->protocol_id = proposal->protocol_id;
        RAND_bytes ((u8 *) & rv->spi, sizeof (rv->spi));
+       if (rv->protocol_id != IKEV2_PROTOCOL_IKE)
+         rv->spi &= 0xffffffff;
        goto done;
       }
     else
@@ -480,11 +482,10 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai)
 }
 
 static void
-ikev2_calc_keys (ikev2_sa_t * sa)
+ikev2_calc_keys_internal (ikev2_sa_t *sa, u8 *skeyseed)
 {
   u8 *tmp;
   /* calculate SKEYSEED = prf(Ni | Nr, g^ir) */
-  u8 *skeyseed = 0;
   u8 *s = 0;
   u16 integ_key_len = 0, salt_len = 0;
   ikev2_sa_transform_t *tr_encr, *tr_prf, *tr_integ;
@@ -502,7 +503,6 @@ ikev2_calc_keys (ikev2_sa_t * sa)
 
   vec_append (s, sa->i_nonce);
   vec_append (s, sa->r_nonce);
-  skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key);
 
   /* Calculate S = Ni | Nr | SPIi | SPIr */
   u64 *spi;
@@ -520,7 +520,6 @@ ikev2_calc_keys (ikev2_sa_t * sa)
     salt_len * 2;
 
   keymat = ikev2_calc_prfplus (tr_prf, skeyseed, s, len);
-  vec_free (skeyseed);
   vec_free (s);
 
   int pos = 0;
@@ -567,6 +566,41 @@ ikev2_calc_keys (ikev2_sa_t * sa)
   sa->keys_generated = 1;
 }
 
+static void
+ikev2_calc_keys_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old)
+{
+  u8 *s = 0, *skeyseed = 0;
+  ikev2_sa_transform_t *tr_prf =
+    ikev2_sa_get_td_for_type (sa_old->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
+
+  vec_append (s, sa_new->dh_shared_key);
+  vec_append (s, sa_new->i_nonce);
+  vec_append (s, sa_new->r_nonce);
+  skeyseed = ikev2_calc_prf (tr_prf, sa_old->sk_d, s);
+
+  ikev2_calc_keys_internal (sa_new, skeyseed);
+
+  vec_free (skeyseed);
+  vec_free (s);
+}
+
+static void
+ikev2_calc_keys (ikev2_sa_t *sa)
+{
+  u8 *s = 0, *skeyseed = 0;
+  ikev2_sa_transform_t *tr_prf =
+    ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
+
+  vec_append (s, sa->i_nonce);
+  vec_append (s, sa->r_nonce);
+  skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key);
+
+  ikev2_calc_keys_internal (sa, skeyseed);
+
+  vec_free (skeyseed);
+  vec_free (s);
+}
+
 static void
 ikev2_calc_child_keys (ikev2_sa_t *sa, ikev2_child_sa_t *child, u8 kex)
 {
@@ -1076,7 +1110,6 @@ ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd,
   ikev2_child_sa_t *c;
 
   /* find old IKE SAs with the same authenticated identity */
-  /* *INDENT-OFF* */
   pool_foreach (tmp, ptd->sas)  {
     if (!ikev2_is_id_equal (&tmp->i_id, &sa->i_id)
         || !ikev2_is_id_equal(&tmp->r_id, &sa->r_id))
@@ -1085,7 +1118,6 @@ ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd,
     if (sa->rspi != tmp->rspi)
       vec_add1(delete, tmp - ptd->sas);
   }
-  /* *INDENT-ON* */
 
   for (i = 0; i < vec_len (delete); i++)
     {
@@ -1410,6 +1442,110 @@ ikev2_process_create_child_sa_rekey (ikev2_sa_t *sa, ikev2_sa_t *sar,
   return 1;
 }
 
+static void
+ikev2_complete_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old,
+                        ikev2_sa_rekey_t *sa_rekey)
+{
+  sa_new->del = 0;
+  sa_new->rekey = 0;
+  sa_new->new_child = 0;
+  sa_new->sa_rekey = 0;
+  sa_new->last_sa_init_req_packet_data = 0;
+  sa_new->last_sa_init_res_packet_data = 0;
+  sa_new->last_msg_id = ~0;
+  sa_new->last_res_packet_data = 0;
+  sa_new->last_init_msg_id = 0;
+  clib_memset (&sa_new->stats, 0, sizeof (sa_new->stats));
+
+  sa_new->ispi = sa_rekey->ispi;
+  sa_new->rspi = sa_rekey->rspi;
+  sa_new->i_nonce = sa_rekey->i_nonce;
+  sa_new->r_nonce = sa_rekey->r_nonce;
+  sa_new->dh_group = sa_rekey->dh_group;
+  sa_new->dh_shared_key = sa_rekey->dh_shared_key;
+  sa_new->dh_private_key = sa_rekey->dh_private_key;
+  sa_new->i_dh_data = sa_rekey->i_dh_data;
+  sa_new->r_dh_data = sa_rekey->r_dh_data;
+  sa_new->i_proposals = sa_rekey->i_proposals;
+  sa_new->r_proposals = sa_rekey->r_proposals;
+
+  sa_new->sk_d = 0;
+  sa_new->sk_ai = 0;
+  sa_new->sk_ar = 0;
+  sa_new->sk_ei = 0;
+  sa_new->sk_er = 0;
+  sa_new->sk_pi = 0;
+  sa_new->sk_pr = 0;
+  ikev2_calc_keys_rekey (sa_new, sa_old);
+
+  sa_new->i_auth.data = vec_dup (sa_old->i_auth.data);
+  sa_new->i_auth.key = sa_old->i_auth.key;
+  if (sa_new->i_auth.key)
+    EVP_PKEY_up_ref (sa_new->i_auth.key);
+
+  sa_new->r_auth.data = vec_dup (sa_old->r_auth.data);
+  sa_new->r_auth.key = sa_old->r_auth.key;
+  if (sa_new->r_auth.key)
+    EVP_PKEY_up_ref (sa_new->r_auth.key);
+
+  sa_new->i_id.data = vec_dup (sa_old->i_id.data);
+  sa_new->r_id.data = vec_dup (sa_old->r_id.data);
+
+  sa_old->is_tun_itf_set = 0;
+  sa_old->tun_itf = ~0;
+  sa_old->old_id_expiration = 0;
+  sa_old->current_remote_id_mask = 0;
+  sa_old->old_remote_id = 0;
+  sa_old->old_remote_id_present = 0;
+  sa_old->childs = 0;
+  sa_old->sw_if_index = ~0;
+}
+
+static void
+ikev2_process_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old,
+                       ikev2_sa_rekey_t *sa_rekey)
+{
+  ikev2_sa_transform_t *tr;
+
+  if (ikev2_generate_sa_init_data (sa_new) != IKEV2_GENERATE_SA_INIT_OK)
+    {
+      sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD;
+      return;
+    }
+
+  sa_new->r_proposals =
+    ikev2_select_proposal (sa_new->i_proposals, IKEV2_PROTOCOL_IKE);
+
+  tr = ikev2_sa_get_td_for_type (sa_new->r_proposals, IKEV2_TRANSFORM_TYPE_DH);
+  if (!tr || tr->dh_type != sa_new->dh_group)
+    {
+      sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD;
+      return;
+    }
+
+  sa_rekey->notify_type = 0;
+  sa_rekey->ispi = sa_new->i_proposals[0].spi;
+  sa_rekey->rspi = sa_new->r_proposals[0].spi;
+  sa_rekey->i_nonce = sa_new->i_nonce;
+  sa_rekey->r_nonce = sa_new->r_nonce;
+  sa_rekey->dh_group = sa_new->dh_group;
+  sa_rekey->dh_shared_key = sa_new->dh_shared_key;
+  sa_rekey->dh_private_key = sa_new->dh_private_key;
+  sa_rekey->i_dh_data = sa_new->i_dh_data;
+  sa_rekey->r_dh_data = sa_new->r_dh_data;
+  sa_rekey->i_proposals = sa_new->i_proposals;
+  sa_rekey->r_proposals = sa_new->r_proposals;
+
+  sa_new->i_nonce = 0;
+  sa_new->r_nonce = 0;
+  sa_new->dh_shared_key = 0;
+  sa_new->dh_private_key = 0;
+  sa_new->i_dh_data = 0;
+  sa_new->r_dh_data = 0;
+  sa_new->i_proposals = 0;
+  sa_new->r_proposals = 0;
+}
+
 static int
 ikev2_process_create_child_sa_req (vlib_main_t * vm,
                                   ikev2_sa_t * sa, ike_header_t * ike,
@@ -1515,7 +1651,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm,
       p += plen;
     }
 
-  if (!proposal || proposal->protocol_id != IKEV2_PROTOCOL_ESP || !nonce)
+  if (!proposal || !nonce ||
+      (proposal->protocol_id != IKEV2_PROTOCOL_ESP &&
+       proposal->protocol_id != IKEV2_PROTOCOL_IKE))
     goto cleanup_and_exit;
 
   if (sa->is_initiator)
@@ -1571,6 +1709,16 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm,
              vec_free (tsi);
            }
        }
+      else if (proposal[0].protocol_id == IKEV2_PROTOCOL_IKE)
+       {
+         ikev2_sa_rekey_t *sa_rekey;
+         if (tsi || tsr)
+           goto cleanup_and_exit;
+         sar.i_proposals = proposal;
+         vec_add (sar.i_nonce, nonce, nonce_len);
+         vec_add2 (sa->sa_rekey, sa_rekey, 1);
+         ikev2_process_sa_rekey (&sar, sa, sa_rekey);
+       }
       else
        {
          /* create new child SA */
@@ -1681,7 +1829,6 @@ ikev2_sa_match_ts (ikev2_sa_t * sa)
   ikev2_ts_t *ts, *p_tsi, *p_tsr, *tsi = 0, *tsr = 0;
   ikev2_id_t *id_rem, *id_loc;
 
-  /* *INDENT-OFF* */
   pool_foreach (p, km->profiles)  {
 
     if (sa->is_initiator)
@@ -1724,7 +1871,6 @@ ikev2_sa_match_ts (ikev2_sa_t * sa)
 
     break;
   }
-  /* *INDENT-ON* */
 
   if (tsi && tsr)
     {
@@ -1742,7 +1888,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa)
 }
 
 static ikev2_profile_t *
-ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa,
+ikev2_select_profile (vlib_main_t *vm, ikev2_main_t *km, ikev2_sa_t *sa,
                      ikev2_sa_transform_t *tr_prf, u8 *key_pad)
 {
   ikev2_profile_t *ret = 0, *p;
@@ -1782,6 +1928,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa,
          if (!clib_memcmp (auth, sa_auth->data, vec_len (sa_auth->data)))
            {
              ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED);
+             sa->auth_timestamp = vlib_time_now (vm);
              vec_free (auth);
              ret = p;
              break;
@@ -1800,6 +1947,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa,
          if (ikev2_verify_sign (p->auth.key, sa_auth->data, authmsg) == 1)
            {
              ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED);
+             sa->auth_timestamp = vlib_time_now (vm);
              ret = p;
              break;
            }
@@ -1815,7 +1963,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa,
 }
 
 static void
-ikev2_sa_auth (ikev2_sa_t *sa)
+ikev2_sa_auth (ikev2_sa_t *sa, vlib_main_t *vm)
 {
   ikev2_main_t *km = &ikev2_main;
   ikev2_profile_t *sel_p = 0;
@@ -1836,7 +1984,7 @@ ikev2_sa_auth (ikev2_sa_t *sa)
     }
 
   key_pad = format (0, "%s", IKEV2_KEY_PAD);
-  sel_p = ikev2_select_profile (km, sa, tr_prf, key_pad);
+  sel_p = ikev2_select_profile (vm, km, sa, tr_prf, key_pad);
 
   if (sel_p)
     {
@@ -2041,7 +2189,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a)
   rv = ipsec_sa_add_and_lock (a->local_sa_id, a->local_spi, IPSEC_PROTOCOL_ESP,
                              a->encr_type, &a->loc_ckey, a->integ_type,
                              &a->loc_ikey, a->flags, a->salt_local,
-                             a->src_port, a->dst_port, &tun_out, NULL);
+                             a->src_port, a->dst_port, 0, &tun_out, NULL);
   if (rv)
     goto err0;
 
@@ -2049,7 +2197,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a)
     a->remote_sa_id, a->remote_spi, IPSEC_PROTOCOL_ESP, a->encr_type,
     &a->rem_ckey, a->integ_type, &a->rem_ikey,
     (a->flags | IPSEC_SA_FLAG_IS_INBOUND), a->salt_remote,
-    a->ipsec_over_udp_port, a->ipsec_over_udp_port, &tun_in, NULL);
+    a->ipsec_over_udp_port, a->ipsec_over_udp_port, 0, &tun_in, NULL);
   if (rv)
     goto err1;
 
@@ -2084,6 +2232,8 @@ ikev2_create_tunnel_interface (vlib_main_t *vm, ikev2_sa_t *sa,
 
   clib_memset (&a, 0, sizeof (a));
 
+  child->timestamp = vlib_time_now (vm);
+
   if (!child->r_proposals)
     {
       ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
@@ -2336,14 +2486,12 @@ ikev2_del_tunnel_from_main (ikev2_del_ipsec_tunnel_args_t * a)
 
   if (~0 == a->sw_if_index)
     {
-    /* *INDENT-OFF* */
     ipip_tunnel_key_t key = {
       .src = a->local_ip,
       .dst = a->remote_ip,
       .transport = IPIP_TRANSPORT_IP4,
       .fib_index = 0,
     };
-    /* *INDENT-ON* */
 
       ipip = ipip_tunnel_db_find (&key);
 
@@ -2413,20 +2561,27 @@ ikev2_add_invalid_ke_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain)
   vec_free (data);
 }
 
+static void
+ikev2_add_notify_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain,
+                         u16 notify_type)
+{
+  if (notify_type == IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD)
+    ikev2_add_invalid_ke_payload (sa, chain);
+  else
+    ikev2_payload_add_notify (chain, notify_type, 0);
+}
+
 static void
 ikev2_add_create_child_resp (ikev2_sa_t *sa, ikev2_rekey_t *rekey,
                             ikev2_payload_chain_t *chain)
 {
   if (rekey->notify_type)
     {
-      if (rekey->notify_type == IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD)
-       ikev2_add_invalid_ke_payload (sa, chain);
-      else
-       ikev2_payload_add_notify (chain, rekey->notify_type, 0);
+      ikev2_add_notify_payload (sa, chain, rekey->notify_type);
       return;
     }
 
-  ikev2_payload_add_sa (chain, rekey->r_proposal);
+  ikev2_payload_add_sa (chain, rekey->r_proposal, 0);
   ikev2_payload_add_nonce (chain, sa->r_nonce);
   if (rekey->kex)
     ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data);
@@ -2482,7 +2637,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
          ASSERT (udp);
 
          ike->rspi = clib_host_to_net_u64 (sa->rspi);
-         ikev2_payload_add_sa (chain, sa->r_proposals);
+         ikev2_payload_add_sa (chain, sa->r_proposals, 0);
          ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data);
          ikev2_payload_add_nonce (chain, sa->r_nonce);
 
@@ -2510,7 +2665,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
        {
          ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR);
          ikev2_payload_add_auth (chain, &sa->r_auth);
-         ikev2_payload_add_sa (chain, sa->childs[0].r_proposals);
+         ikev2_payload_add_sa (chain, sa->childs[0].r_proposals, 0);
          ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
          ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
        }
@@ -2555,7 +2710,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
          if (sa->r_id.type != 0)
            ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR);
          ikev2_payload_add_auth (chain, &sa->i_auth);
-         ikev2_payload_add_sa (chain, sa->childs[0].i_proposals);
+         ikev2_payload_add_sa (chain, sa->childs[0].i_proposals, 0);
          ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
          ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
          ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_INITIAL_CONTACT,
@@ -2632,7 +2787,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
          notify.spi = sa->childs[0].i_proposals->spi;
          *(u32 *) data = clib_host_to_net_u32 (notify.spi);
 
-         ikev2_payload_add_sa (chain, proposals);
+         ikev2_payload_add_sa (chain, proposals, 0);
          ikev2_payload_add_nonce (chain, sa->i_nonce);
          ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
          ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
@@ -2651,6 +2806,19 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
          ikev2_add_create_child_resp (sa, &sa->new_child[0], chain);
          vec_del1 (sa->new_child, 0);
        }
+      else if (vec_len (sa->sa_rekey) > 0)
+       {
+         if (sa->sa_rekey[0].notify_type)
+           ikev2_add_notify_payload (sa, chain, sa->sa_rekey[0].notify_type);
+         else
+           {
+             ikev2_payload_add_sa (chain, sa->sa_rekey[0].r_proposals, 1);
+             ikev2_payload_add_nonce (chain, sa->sa_rekey[0].r_nonce);
+             ikev2_payload_add_ke (chain, sa->sa_rekey[0].dh_group,
+                                   sa->sa_rekey[0].r_dh_data);
+           }
+         vec_del1 (sa->sa_rekey, 0);
+       }
       else if (sa->unsupported_cp)
        {
          u8 *data = vec_new (u8, 1);
@@ -2843,13 +3011,11 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr,
   u32 res;
   ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data ();
 
-  /* *INDENT-OFF* */
   pool_foreach (sa, ptd->sas)  {
     res = ikev2_retransmit_sa_init_one (sa, ike, iaddr, raddr, rlen);
     if (res)
       return res;
   }
-  /* *INDENT-ON* */
 
   /* req is not retransmit */
   return 0;
@@ -3262,13 +3428,15 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
              sa0->dst_port = clib_net_to_host_u16 (udp0->src_port);
              res = ikev2_process_auth_req (vm, sa0, ike0, rlen);
              if (res)
-               ikev2_sa_auth (sa0);
+               ikev2_sa_auth (sa0, vm);
              else
                vlib_node_increment_counter (vm, node->node_index,
                                             IKEV2_ERROR_MALFORMED_PACKET, 1);
              if (sa0->state == IKEV2_STATE_AUTHENTICATED)
                {
                  ikev2_initial_contact_cleanup (ptd, sa0);
+                 p = hash_get (ptd->sa_by_rspi,
+                               clib_net_to_host_u64 (ike0->rspi));
                  ikev2_sa_match_ts (sa0);
                  if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
                    ikev2_create_tunnel_interface (vm, sa0, &sa0->childs[0],
@@ -3454,6 +3622,38 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
                          vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1);
                    }
                }
+             else if (vec_len (sa0->sa_rekey) > 0)
+               {
+                 if (!sa0->sa_rekey[0].notify_type)
+                   {
+                     ikev2_sa_t *sar, *tmp = 0;
+                     pool_get (ptd->sas, tmp);
+                     sa0 = pool_elt_at_index (ptd->sas, p[0]);
+                     /* swap old/new SAs to keep index and inherit IPsec SA */
+                     clib_memcpy_fast (tmp, sa0, sizeof (*tmp));
+                     sar = sa0;
+                     sa0 = tmp;
+                     hash_set (ptd->sa_by_rspi, sa0->rspi, sa0 - ptd->sas);
+                     p = hash_get (ptd->sa_by_rspi, sa0->rspi);
+                     ikev2_complete_sa_rekey (sar, sa0, &sa0->sa_rekey[0]);
+                     hash_set (ptd->sa_by_rspi, sar->rspi, sar - ptd->sas);
+                   }
+                 if (ike_hdr_is_response (ike0))
+                   {
+                     vec_free (sa0->sa_rekey);
+                   }
+                 else
+                   {
+                     stats->n_rekey_req++;
+                     sa0->stats.n_rekey_req++;
+                     ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
+                     slen =
+                       ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats);
+                     if (~0 == slen)
+                       vlib_node_increment_counter (
+                         vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1);
+                   }
+               }
            }
        }
       else
@@ -3562,7 +3762,6 @@ ikev2_ip6 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
   return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */, 0);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ikev2_node_ip4,static) = {
   .function = ikev2_ip4,
   .name = "ikev2-ip4",
@@ -3613,7 +3812,6 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = {
     [IKEV2_NEXT_IP6_ERROR_DROP] = "error-drop",
   },
 };
-/* *INDENT-ON* */
 
 // set ikev2 proposals when vpp is used as initiator
 static clib_error_t *
@@ -3955,12 +4153,10 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p)
   u32 *sai;
   u32 *del_sai = 0;
 
-  /* *INDENT-OFF* */
   pool_foreach (sa, km->sais)  {
     if (pi == sa->profile_index)
       vec_add1 (del_sai, sa - km->sais);
   }
-  /* *INDENT-ON* */
 
   vec_foreach (sai, del_sai)
   {
@@ -3973,12 +4169,10 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p)
 
   vec_foreach (tkm, km->per_thread_data)
   {
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       if (sa->profile_index != ~0 && pi == sa->profile_index)
         vec_add1 (del_sai, sa - tkm->sas);
     }
-    /* *INDENT-ON* */
 
     vec_foreach (sai, del_sai)
     {
@@ -4524,7 +4718,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
   proposals[0].protocol_id = IKEV2_PROTOCOL_IKE;
 
   /* Add and then cleanup proposal data */
-  ikev2_payload_add_sa (chain, proposals);
+  ikev2_payload_add_sa (chain, proposals, 0);
   ikev2_sa_free_proposal_vector (&proposals);
 
   sa.is_initiator = 1;
@@ -4558,6 +4752,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
   sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP;
   RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi,
              sizeof (sa.childs[0].i_proposals[0].spi));
+  sa.childs[0].i_proposals[0].spi &= 0xffffffff;
 
   /* Add NAT detection notification messages (mandatory) */
   u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 (
@@ -4709,7 +4904,6 @@ ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi)
     ikev2_sa_t *sa;
     if (fchild)
       break;
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1);
       if (fchild)
@@ -4718,7 +4912,6 @@ ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi)
           break;
         }
     }
-    /* *INDENT-ON* */
   }
 
   if (!fchild || !fsa)
@@ -4749,7 +4942,6 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi)
     ikev2_sa_t *sa;
     if (fsa)
       break;
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       if (sa->ispi == ispi)
         {
@@ -4758,7 +4950,6 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi)
           break;
         }
     }
-    /* *INDENT-ON* */
   }
 
   if (!fsa)
@@ -4805,6 +4996,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
 
   /*need new ispi */
   RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi));
+  proposals[0].spi &= 0xffffffff;
   rekey->spi = proposals[0].spi;
   rekey->ispi = csa->i_proposals->spi;
   len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0);
@@ -4833,7 +5025,6 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi)
     ikev2_sa_t *sa;
     if (fchild)
       break;
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1);
       if (fchild)
@@ -4842,7 +5033,6 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi)
           break;
         }
     }
-    /* *INDENT-ON* */
   }
 
   if (!fchild || !fsa)
@@ -4875,12 +5065,10 @@ ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index)
 
   vec_foreach (tkm, km->per_thread_data)
   {
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       if (ikev2_sa_sw_if_match (sa, sw_if_index))
         vec_add1 (sa_vec, sa);
     }
-    /* *INDENT-ON* */
 
     vec_foreach (sap, sa_vec)
     {
@@ -4890,12 +5078,10 @@ ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index)
   }
   vec_free (sa_vec);
 
-  /* *INDENT-OFF* */
   pool_foreach (sa, km->sais)  {
     if (ikev2_sa_sw_if_match (sa, sw_if_index))
       vec_add1 (ispi_vec, sa->ispi);
   }
-  /* *INDENT-ON* */
 
   vec_foreach (ispi, ispi_vec)
   {
@@ -4914,12 +5100,10 @@ ikev2_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
   if (is_add)
     return 0;
 
-  /* *INDENT-OFF* */
   pool_foreach (p, km->profiles)  {
     if (p->responder.sw_if_index == sw_if_index)
       ikev2_sa_del (p, sw_if_index);
   }
-  /* *INDENT-ON* */
 
   return 0;
 }
@@ -4945,11 +5129,9 @@ ikev2_init (vlib_main_t * vm)
   return 0;
 }
 
-/* *INDENT-OFF* */
 VLIB_INIT_FUNCTION (ikev2_init) = {
   .runs_after = VLIB_INITS ("ipsec_init", "ipsec_punt_init"),
 };
-/* *INDENT-ON* */
 
 static u8
 ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa,
@@ -5020,14 +5202,12 @@ ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa,
                                   ip_addr_bytes (&sa->iaddr));
            }
 
-       /* *INDENT-OFF* */
        ipip_tunnel_key_t key = {
          .src = local_ip,
          .dst = remote_ip,
          .transport = IPIP_TRANSPORT_IP4,
          .fib_index = 0,
        };
-       /* *INDENT-ON* */
 
          ipip = ipip_tunnel_db_find (&key);
 
@@ -5108,7 +5288,6 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
     ikev2_sa_t *sa;
     if (fchild)
       break;
-    /* *INDENT-OFF* */
     pool_foreach (sa, tkm->sas)  {
       fchild = ikev2_sa_get_child(sa, ipsec_sa->spi, IKEV2_PROTOCOL_ESP, 1);
       if (fchild)
@@ -5117,7 +5296,6 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
           break;
         }
     }
-    /* *INDENT-ON* */
   }
   vlib_get_combined_counter (&ipsec_sa_counters,
                             ipsec_sa->stat_index, &counts);
@@ -5215,7 +5393,6 @@ ikev2_process_pending_sa_init (vlib_main_t *vm, ikev2_main_t *km)
   u64 ispi;
   ikev2_sa_t *sa;
 
-  /* *INDENT-OFF* */
   hash_foreach (ispi, sai, km->sa_by_ispi,
   ({
     sa = pool_elt_at_index (km->sais, sai);
@@ -5224,7 +5401,6 @@ ikev2_process_pending_sa_init (vlib_main_t *vm, ikev2_main_t *km)
 
     ikev2_process_pending_sa_init_one (vm, km, sa);
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -5329,29 +5505,32 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
        ikev2_sa_t *sa;
        u32 *to_be_deleted = 0;
 
-        /* *INDENT-OFF* */
         pool_foreach (sa, tkm->sas)  {
           ikev2_child_sa_t *c;
           u8 del_old_ids = 0;
 
-          if (sa->state != IKEV2_STATE_AUTHENTICATED)
-            continue;
+         if (sa->state == IKEV2_STATE_SA_INIT)
+           {
+             if (vec_len (sa->childs) > 0)
+               vec_add1 (to_be_deleted, sa - tkm->sas);
+           }
+         else if (sa->state != IKEV2_STATE_AUTHENTICATED)
+           continue;
 
-          if (sa->old_remote_id_present && 0 > sa->old_id_expiration)
-            {
-              sa->old_remote_id_present = 0;
-              del_old_ids = 1;
-            }
-          else
-            sa->old_id_expiration -= 1;
+         if (sa->old_remote_id_present && 0 > sa->old_id_expiration)
+           {
+             sa->old_remote_id_present = 0;
+             del_old_ids = 1;
+           }
+         else
+           sa->old_id_expiration -= 1;
 
-          vec_foreach (c, sa->childs)
-            ikev2_mngr_process_child_sa(sa, c, del_old_ids);
+         vec_foreach (c, sa->childs)
+           ikev2_mngr_process_child_sa (sa, c, del_old_ids);
 
-          if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa))
-            vec_add1 (to_be_deleted, sa - tkm->sas);
-        }
-        /* *INDENT-ON* */
+         if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa))
+           vec_add1 (to_be_deleted, sa - tkm->sas);
+         }
 
        vec_foreach (sai, to_be_deleted)
        {
@@ -5386,19 +5565,16 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
 
       /* process ipsec sas */
       ipsec_sa_t *sa;
-      /* *INDENT-OFF* */
       pool_foreach (sa, ipsec_sa_pool)
        {
          ikev2_mngr_process_ipsec_sa (sa);
        }
-      /* *INDENT-ON* */
 
       ikev2_process_pending_sa_init (vm, km);
     }
   return 0;
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (ikev2_mngr_process_node, static) = {
     .function = ikev2_mngr_process_fn,
     .type = VLIB_NODE_TYPE_PROCESS,
@@ -5460,7 +5636,6 @@ VLIB_PLUGIN_REGISTER () = {
     .version = VPP_BUILD_VER,
     .description = "Internet Key Exchange (IKEv2) Protocol",
 };
-/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON