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(uint64_t seq, struct otx2_ipsec_fp_in_sa *sa)
21 struct otx2_ipsec_replay *replay = sa->replay;
22 uint64_t *window = &replay->window[0];
23 uint64_t winsz = sa->replay_win_sz;
24 uint64_t ex_winsz = winsz + WORD_SIZE;
25 uint64_t winwords = ex_winsz >> WORD_SHIFT;
26 uint64_t base = replay->base;
27 uint32_t winb = replay->winb;
28 uint32_t wint = replay->wint;
29 uint64_t seqword, shiftwords;
37 /* Check if the seq is the biggest one yet */
38 if (likely(seq > base)) {
40 if (shift < winsz) { /* In window */
42 * If more than 64-bit anti-replay window,
43 * use slow shift routine
45 wptr = window + (shift >> WORD_SHIFT);
49 /* No special handling of window size > 64 */
50 wptr = window + ((winsz - 1) >> WORD_SHIFT);
52 * Zero out the whole window (especially for
53 * bigger than 64b window) till the last 64b word
54 * as the incoming sequence number minus
55 * base sequence is more than the window size.
57 while (window != wptr)
60 * Set the last bit (of the window) to 1
61 * as that corresponds to the base sequence number.
62 * Now any incoming sequence number which is
63 * (base - window size - 1) will pass anti-replay check
68 * Set the base to incoming sequence number as
69 * that is the biggest sequence number seen yet
77 /* If seq falls behind the window, return failure */
79 return IPSEC_ANTI_REPLAY_FAILED;
81 /* seq is within anti-replay window */
82 wptr = window + ((winsz - bit_pos - 1) >> WORD_SHIFT);
85 /* Check if this is a replayed packet */
86 if (*wptr & ((1ull) << bit_pos))
87 return IPSEC_ANTI_REPLAY_FAILED;
90 *wptr |= ((1ull) << bit_pos);
94 if (likely(seq > base)) {
98 if (unlikely(shift >= winsz)) {
100 * shift is bigger than the window,
101 * so just zero out everything
103 for (i = 0; i < winwords; i++)
106 /* Find out the word */
107 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
109 /* Find out the bit in the word */
110 bit_pos = (seq - 1) & WORD_MASK;
113 * Set the bit corresponding to sequence number
114 * in window to mark it as received
116 window[seqword] |= (1ull << (63 - bit_pos));
118 /* wint and winb range from 1 to ex_winsz */
119 replay->wint = ((wint + shift - 1) % ex_winsz) + 1;
120 replay->winb = ((winb + shift - 1) % ex_winsz) + 1;
127 * New sequence number is bigger than the base but
128 * it's not bigger than base + window size
131 shiftwords = ((wint + shift - 1) >> WORD_SHIFT) -
132 ((wint - 1) >> WORD_SHIFT);
133 if (unlikely(shiftwords)) {
134 tmp = (wint + WORD_SIZE - 1) / WORD_SIZE;
135 for (i = 0; i < shiftwords; i++) {
144 /* Sequence number is before the window */
145 if (unlikely((seq + winsz) <= base))
146 return IPSEC_ANTI_REPLAY_FAILED;
148 /* Sequence number is within the window */
150 /* Find out the word */
151 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT;
153 /* Find out the bit in the word */
154 bit_pos = (seq - 1) & WORD_MASK;
156 /* Check if this is a replayed packet */
157 if (window[seqword] & (1ull << (63 - bit_pos)))
158 return IPSEC_ANTI_REPLAY_FAILED;
161 * Set the bit corresponding to sequence number
162 * in window to mark it as received
164 window[seqword] |= (1ull << (63 - bit_pos));
170 cpt_ipsec_antireplay_check(struct otx2_ipsec_fp_in_sa *sa, char *data)
179 esn = sa->ctl.esn_en;
180 seql = rte_be_to_cpu_32(*((uint32_t *)(data +
181 OTX2_IPSEC_SEQNO_LO_INDEX)));
184 seq = (uint64_t)seql;
186 seqh = rte_be_to_cpu_32(*((uint32_t *)(data +
187 OTX2_IPSEC_SEQNO_HI_INDEX)));
188 seq = ((uint64_t)seqh << 32) | seql;
191 if (unlikely(seq == 0))
192 return IPSEC_ANTI_REPLAY_FAILED;
194 rte_spinlock_lock(&sa->replay->lock);
195 ret = anti_replay_check(seq, sa);
196 if (esn && (ret == 0)) {
197 seq_in_sa = ((uint64_t)rte_be_to_cpu_32(sa->esn_hi) << 32) |
198 rte_be_to_cpu_32(sa->esn_low);
199 if (seq > seq_in_sa) {
200 sa->esn_low = rte_cpu_to_be_32(seql);
201 sa->esn_hi = rte_cpu_to_be_32(seqh);
204 rte_spinlock_unlock(&sa->replay->lock);
208 #endif /* __OTX2_IPSEC_ANTI_REPLAY_H__ */