+ }
+
+ /* next */
+ next:
+ n_left -= 1;
+ next += 1;
+ pd += 1;
+ b += 1;
+ }
+
+ if (PREDICT_TRUE (~0 != current_sa_index))
+ vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
+ current_sa_index, current_sa_pkts,
+ current_sa_bytes);
+
+ esp_process_ops (vm, node, ptd->integ_ops, bufs, nexts,
+ ESP_DECRYPT_ERROR_INTEG_ERROR);
+ esp_process_chained_ops (vm, node, ptd->chained_integ_ops, bufs, nexts,
+ ptd->chunks, ESP_DECRYPT_ERROR_INTEG_ERROR);
+
+ esp_process_ops (vm, node, ptd->crypto_ops, bufs, nexts,
+ ESP_DECRYPT_ERROR_DECRYPTION_FAILED);
+ esp_process_chained_ops (vm, node, ptd->chained_crypto_ops, bufs, nexts,
+ ptd->chunks, ESP_DECRYPT_ERROR_DECRYPTION_FAILED);
+
+ /* Post decryption ronud - adjust packet data start and length and next
+ node */
+
+ n_left = from_frame->n_vectors;
+ next = nexts;
+ pd = pkt_data;
+ b = bufs;
+
+ while (n_left)
+ {
+ const u8 tun_flags = IPSEC_SA_FLAG_IS_TUNNEL |
+ IPSEC_SA_FLAG_IS_TUNNEL_V6;
+
+ if (n_left >= 2)
+ {
+ void *data = b[1]->data + pd[1].current_data;
+
+ /* buffer metadata */
+ vlib_prefetch_buffer_header (b[1], LOAD);
+
+ /* esp_footer_t */
+ CLIB_PREFETCH (data + pd[1].current_length - pd[1].icv_sz - 2,
+ CLIB_CACHE_LINE_BYTES, LOAD);
+
+ /* packet headers */
+ CLIB_PREFETCH (data - CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES * 2, LOAD);
+ }
+
+ if (next[0] < ESP_DECRYPT_N_NEXT)
+ goto trace;
+
+ sa0 = vec_elt_at_index (im->sad, pd->sa_index);
+
+ /*
+ * redo the anti-reply check
+ * in this frame say we have sequence numbers, s, s+1, s+1, s+1
+ * and s and s+1 are in the window. When we did the anti-replay
+ * check above we did so against the state of the window (W),
+ * after packet s-1. So each of the packets in the sequence will be
+ * accepted.
+ * This time s will be cheked against Ws-1, s+1 chceked against Ws
+ * (i.e. the window state is updated/advnaced)
+ * so this time the successive s+! packet will be dropped.
+ * This is a consequence of batching the decrypts. If the
+ * check-dcrypt-advance process was done for each packet it would
+ * be fine. But we batch the decrypts because it's much more efficient
+ * to do so in SW and if we offload to HW and the process is async.
+ *
+ * You're probably thinking, but this means an attacker can send the
+ * above sequence and cause VPP to perform decrpyts that will fail,
+ * and that's true. But if the attacker can determine s (a valid
+ * sequence number in the window) which is non-trivial, it can generate
+ * a sequence s, s+1, s+2, s+3, ... s+n and nothing will prevent any
+ * implementation, sequential or batching, from decrypting these.
+ */
+ if (ipsec_sa_anti_replay_check (sa0, pd->seq))
+ {
+ b[0]->error = node->errors[ESP_DECRYPT_ERROR_REPLAY];
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ goto trace;
+ }
+
+ ipsec_sa_anti_replay_advance (sa0, pd->seq);
+
+ u8 pad_length = 0, next_header = 0;
+ u16 icv_sz = pd->icv_removed ? 0 : pd->icv_sz;
+
+ if (pd->free_buffer_index)
+ vlib_buffer_free_one (vm, pd->free_buffer_index);
+
+ if (pd->lb->current_length < sizeof (esp_footer_t) + icv_sz)
+ {
+ /* esp footer is either splitted in two buffers or in the before
+ * last buffer */
+
+ vlib_buffer_t *before_last = b[0], *bp = b[0];
+ while (bp->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ before_last = bp;
+ bp = vlib_get_buffer (vm, bp->next_buffer);
+ }
+ u8 *bt = vlib_buffer_get_tail (before_last);