1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2020 Marvell International Ltd.
5 #ifndef __OTX2_IPSEC_ANTI_REPLAY_H__
6 #define __OTX2_IPSEC_ANTI_REPLAY_H__
10 #include "otx2_ipsec_fp.h"
13 #define WORD_SIZE (1 << WORD_SHIFT)
14 #define WORD_MASK (WORD_SIZE - 1)
16 #define IPSEC_ANTI_REPLAY_FAILED (-1)
19 anti_replay_check(struct otx2_ipsec_replay *replay, uint64_t seq,
22 uint64_t *window = &replay->window[0];
23 uint64_t ex_winsz = winsz + WORD_SIZE;
24 uint64_t winwords = ex_winsz >> WORD_SHIFT;
25 uint64_t base = replay->base;
26 uint32_t winb = replay->winb;
27 uint32_t wint = replay->wint;
28 uint64_t seqword, shiftwords;
36 /* Check if the seq is the biggest one yet */
37 if (likely(seq > base)) {
39 if (shift < winsz) { /* In window */
41 * If more than 64-bit anti-replay window,
42 * use slow shift routine
44 wptr = window + (shift >> WORD_SHIFT);
48 /* No special handling of window size > 64 */
49 wptr = window + ((winsz - 1) >> WORD_SHIFT);
51 * Zero out the whole window (especially for
52 * bigger than 64b window) till the last 64b word
53 * as the incoming sequence number minus
54 * base sequence is more than the window size.
56 while (window != wptr)
59 * Set the last bit (of the window) to 1
60 * as that corresponds to the base sequence number.
61 * Now any incoming sequence number which is
62 * (base - window size - 1) will pass anti-replay check
67 * Set the base to incoming sequence number as
68 * that is the biggest sequence number seen yet
76 /* If seq falls behind the window, return failure */
78 return IPSEC_ANTI_REPLAY_FAILED;
80 /* seq is within anti-replay window */
81 wptr = window + ((winsz - bit_pos - 1) >> WORD_SHIFT);
84 /* Check if this is a replayed packet */
85 if (*wptr & ((1ull) << bit_pos))
86 return IPSEC_ANTI_REPLAY_FAILED;
89 *wptr |= ((1ull) << bit_pos);
93 if (likely(seq > base)) {
97 if (unlikely(shift >= winsz)) {
99 * shift is bigger than the window,
100 * so just zero out everything
102 for (i = 0; i < winwords; i++)
105 /* Find out the word */
106 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
108 /* Find out the bit in the word */
109 bit_pos = (seq - 1) & WORD_MASK;
112 * Set the bit corresponding to sequence number
113 * in window to mark it as received
115 window[seqword] |= (1ull << (63 - bit_pos));
117 /* wint and winb range from 1 to ex_winsz */
118 replay->wint = ((wint + shift - 1) % ex_winsz) + 1;
119 replay->winb = ((winb + shift - 1) % ex_winsz) + 1;
126 * New sequence number is bigger than the base but
127 * it's not bigger than base + window size
130 shiftwords = ((wint + shift - 1) >> WORD_SHIFT) -
131 ((wint - 1) >> WORD_SHIFT);
132 if (unlikely(shiftwords)) {
133 tmp = (wint + WORD_SIZE - 1) / WORD_SIZE;
134 for (i = 0; i < shiftwords; i++) {
143 /* Sequence number is before the window */
144 if (unlikely((seq + winsz) <= base))
145 return IPSEC_ANTI_REPLAY_FAILED;
147 /* Sequence number is within the window */
149 /* Find out the word */
150 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
152 /* Find out the bit in the word */
153 bit_pos = (seq - 1) & WORD_MASK;
155 /* Check if this is a replayed packet */
156 if (window[seqword] & (1ull << (63 - bit_pos)))
157 return IPSEC_ANTI_REPLAY_FAILED;
160 * Set the bit corresponding to sequence number
161 * in window to mark it as received
163 window[seqword] |= (1ull << (63 - bit_pos));
169 cpt_ipsec_ip_antireplay_check(struct otx2_ipsec_fp_in_sa *sa, void *l3_ptr)
171 struct otx2_ipsec_fp_res_hdr *hdr = l3_ptr;
179 esn = sa->ctl.esn_en;
180 seql = rte_be_to_cpu_32(hdr->seq_no_lo);
183 seq = (uint64_t)seql;
185 seqh = rte_be_to_cpu_32(hdr->seq_no_hi);
186 seq = ((uint64_t)seqh << 32) | seql;
189 if (unlikely(seq == 0))
190 return IPSEC_ANTI_REPLAY_FAILED;
192 rte_spinlock_lock(&sa->replay->lock);
193 ret = anti_replay_check(sa->replay, seq, sa->replay_win_sz);
194 if (esn && (ret == 0)) {
195 seq_in_sa = ((uint64_t)rte_be_to_cpu_32(sa->esn_hi) << 32) |
196 rte_be_to_cpu_32(sa->esn_low);
197 if (seq > seq_in_sa) {
198 sa->esn_low = rte_cpu_to_be_32(seql);
199 sa->esn_hi = rte_cpu_to_be_32(seqh);
202 rte_spinlock_unlock(&sa->replay->lock);
207 static inline uint32_t
208 anti_replay_get_seqh(uint32_t winsz, uint32_t seql,
209 uint32_t esn_hi, uint32_t esn_low)
211 uint32_t win_low = esn_low - winsz + 1;
213 if (esn_low > winsz - 1) {
214 /* Window is in one sequence number subspace */
220 /* Window is split across two sequence number subspaces */
227 #endif /* __OTX2_IPSEC_ANTI_REPLAY_H__ */