ikev2: add support for custom ipsec-over-udp port
[vpp.git] / src / vnet / ipsec / ah_decrypt.c
index 741fa91..682f6cc 100644 (file)
 #include <vnet/ipsec/ah.h>
 #include <vnet/ipsec/ipsec_io.h>
 
-#define foreach_ah_decrypt_next \
-  _ (DROP, "error-drop")        \
-  _ (IP4_INPUT, "ip4-input")    \
-  _ (IP6_INPUT, "ip6-input")
+#define foreach_ah_decrypt_next                 \
+  _(DROP, "error-drop")                         \
+  _(IP4_INPUT, "ip4-input")                     \
+  _(IP6_INPUT, "ip6-input")                     \
+  _(HANDOFF, "handoff")
 
 #define _(v, s) AH_DECRYPT_NEXT_##v,
 typedef enum
@@ -175,6 +176,21 @@ ah_decrypt_inline (vlib_main_t * vm,
                                          thread_index, current_sa_index);
        }
 
+      if (PREDICT_FALSE (~0 == sa0->decrypt_thread_index))
+       {
+         /* this is the first packet to use this SA, claim the SA
+          * for this thread. this could happen simultaneously on
+          * another thread */
+         clib_atomic_cmp_and_swap (&sa0->decrypt_thread_index, ~0,
+                                   ipsec_sa_assign_thread (thread_index));
+       }
+
+      if (PREDICT_TRUE (thread_index != sa0->decrypt_thread_index))
+       {
+         next[0] = AH_DECRYPT_NEXT_HANDOFF;
+         goto next;
+       }
+
       pd->sa_index = current_sa_index;
 
       ih4 = vlib_buffer_get_current (b[0]);
@@ -184,7 +200,8 @@ ah_decrypt_inline (vlib_main_t * vm,
       if (is_ip6)
        {
          ip6_ext_header_t *prev = NULL;
-         ip6_ext_header_find_t (ih6, prev, ah0, IP_PROTOCOL_IPSEC_AH);
+         ah0 =
+           ip6_ext_header_find (vm, b[0], ih6, IP_PROTOCOL_IPSEC_AH, &prev);
          pd->ip_hdr_size = sizeof (ip6_header_t);
          ASSERT ((u8 *) ah0 - (u8 *) ih6 == pd->ip_hdr_size);
        }
@@ -203,7 +220,7 @@ ah_decrypt_inline (vlib_main_t * vm,
       pd->seq = clib_host_to_net_u32 (ah0->seq_no);
 
       /* anti-replay check */
-      if (ipsec_sa_anti_replay_check (sa0, &ah0->seq_no))
+      if (ipsec_sa_anti_replay_check (sa0, pd->seq))
        {
          b[0]->error = node->errors[AH_DECRYPT_ERROR_REPLAY];
          next[0] = AH_DECRYPT_NEXT_DROP;
@@ -303,7 +320,14 @@ ah_decrypt_inline (vlib_main_t * vm,
 
       if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
        {
-         ipsec_sa_anti_replay_advance (sa0, clib_host_to_net_u32 (pd->seq));
+         /* redo the anit-reply check. see esp_decrypt for details */
+         if (ipsec_sa_anti_replay_check (sa0, pd->seq))
+           {
+             b[0]->error = node->errors[AH_DECRYPT_ERROR_REPLAY];
+             next[0] = AH_DECRYPT_NEXT_DROP;
+             goto trace;
+           }
+         ipsec_sa_anti_replay_advance (sa0, pd->seq);
        }
 
       u16 ah_hdr_len = sizeof (ah_header_t) + pd->icv_size
@@ -413,9 +437,10 @@ VLIB_REGISTER_NODE (ah4_decrypt_node) = {
 
   .n_next_nodes = AH_DECRYPT_N_NEXT,
   .next_nodes = {
-#define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
-    foreach_ah_decrypt_next
-#undef _
+    [AH_DECRYPT_NEXT_DROP] = "ip4-drop",
+    [AH_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+    [AH_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [AH_DECRYPT_NEXT_HANDOFF] = "ah4-decrypt-handoff",
   },
 };
 /* *INDENT-ON* */
@@ -439,9 +464,10 @@ VLIB_REGISTER_NODE (ah6_decrypt_node) = {
 
   .n_next_nodes = AH_DECRYPT_N_NEXT,
   .next_nodes = {
-#define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
-    foreach_ah_decrypt_next
-#undef _
+    [AH_DECRYPT_NEXT_DROP] = "ip6-drop",
+    [AH_DECRYPT_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
+    [AH_DECRYPT_NEXT_IP6_INPUT] = "ip6-input",
+    [AH_DECRYPT_NEXT_HANDOFF] = "ah6-decrypt-handoff",
   },
 };
 /* *INDENT-ON* */