1/* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 5#ifndef __CNXK_SECURITY_AR_H__ 6#define __CNXK_SECURITY_AR_H__ 7 8#include <rte_mbuf.h> 9 10#include "cnxk_security.h" 11 12#define CNXK_ON_AR_WIN_SIZE_MAX 1024 13 14/* u64 array size to fit anti replay window bits */ 15#define AR_WIN_ARR_SZ \ 16 (PLT_ALIGN_CEIL(CNXK_ON_AR_WIN_SIZE_MAX + 1, BITS_PER_LONG_LONG) / \ 17 BITS_PER_LONG_LONG) 18 19#define WORD_SHIFT 6 20#define WORD_SIZE (1 << WORD_SHIFT) 21#define WORD_MASK (WORD_SIZE - 1) 22 23#define IPSEC_ANTI_REPLAY_FAILED (-1) 24 25struct cnxk_on_ipsec_ar { 26 rte_spinlock_t lock; 27 uint32_t winb; 28 uint32_t wint; 29 uint64_t base; /**< base of the anti-replay window */ 30 uint64_t window[AR_WIN_ARR_SZ]; /**< anti-replay window */ 31}; 32 33static inline uint32_t 34cnxk_on_anti_replay_get_seqh(uint32_t winsz, uint32_t seql, uint32_t esn_hi, 35 uint32_t esn_low) 36{ 37 uint32_t win_low = esn_low - winsz + 1; 38 39 if (esn_low > winsz - 1) { 40 /* Window is in one sequence number subspace */ 41 if (seql > win_low) 42 return esn_hi; 43 else 44 return esn_hi + 1; 45 } else { 46 /* Window is split across two sequence number subspaces */ 47 if (seql > win_low) 48 return esn_hi - 1; 49 else 50 return esn_hi; 51 } 52} 53 54static inline int 55cnxk_on_anti_replay_check(uint64_t seq, struct cnxk_on_ipsec_ar *ar, 56 uint32_t winsz) 57{ 58 uint64_t ex_winsz = winsz + WORD_SIZE; 59 uint64_t *window = &ar->window[0]; 60 uint64_t seqword, shiftwords; 61 uint64_t base = ar->base; 62 uint32_t winb = ar->winb; 63 uint32_t wint = ar->wint; 64 uint64_t winwords; 65 uint64_t bit_pos; 66 uint64_t shift; 67 uint64_t *wptr; 68 uint64_t tmp; 69 70 winwords = ex_winsz >> WORD_SHIFT; 71 if (winsz > 64) 72 goto slow_shift; 73 /* Check if the seq is the biggest one yet */ 74 if (likely(seq > base)) { 75 shift = seq - base; 76 if (shift < winsz) { /* In window */ 77 /* 78 * If more than 64-bit anti-replay window, 79 * use slow shift routine 80 */ 81 wptr = window + (shift >> WORD_SHIFT); 82 *wptr <<= shift; 83 *wptr |= 1ull; 84 } else { 85 /* No special handling of window size > 64 */ 86 wptr = window + ((winsz - 1) >> WORD_SHIFT); 87 /* 88 * Zero out the whole window (especially for 89 * bigger than 64b window) till the last 64b word 90 * as the incoming sequence number minus 91 * base sequence is more than the window size. 92 */ 93 while (window != wptr) 94 *window++ = 0ull; 95 /* 96 * Set the last bit (of the window) to 1 97 * as that corresponds to the base sequence number. 98 * Now any incoming sequence number which is 99 * (base - window size - 1) will pass anti-replay check 100 */ 101 *wptr = 1ull; 102 } 103 /* 104 * Set the base to incoming sequence number as 105 * that is the biggest sequence number seen yet 106 */ 107 ar->base = seq; 108 return 0; 109 } 110 111 bit_pos = base - seq; 112 113 /* If seq falls behind the window, return failure */ 114 if (bit_pos >= winsz) 115 return IPSEC_ANTI_REPLAY_FAILED; 116 117 /* seq is within anti-replay window */ 118 wptr = window + ((winsz - bit_pos - 1) >> WORD_SHIFT); 119 bit_pos &= WORD_MASK; 120 121 /* Check if this is a replayed packet */ 122 if (*wptr & ((1ull) << bit_pos)) 123 return IPSEC_ANTI_REPLAY_FAILED; 124 125 /* mark as seen */ 126 *wptr |= ((1ull) << bit_pos); 127 return 0; 128 129slow_shift: 130 if (likely(seq > base)) { 131 uint32_t i; 132 133 shift = seq - base; 134 if (unlikely(shift >= winsz)) { 135 /* 136 * shift is bigger than the window, 137 * so just zero out everything 138 */ 139 for (i = 0; i < winwords; i++) 140 window[i] = 0; 141winupdate: 142 /* Find out the word */ 143 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT; 144 145 /* Find out the bit in the word */ 146 bit_pos = (seq - 1) & WORD_MASK; 147 148 /* 149 * Set the bit corresponding to sequence number 150 * in window to mark it as received 151 */ 152 window[seqword] |= (1ull << (63 - bit_pos)); 153 154 /* wint and winb range from 1 to ex_winsz */ 155 ar->wint = ((wint + shift - 1) % ex_winsz) + 1; 156 ar->winb = ((winb + shift - 1) % ex_winsz) + 1; 157 158 ar->base = seq; 159 return 0; 160 } 161 162 /* 163 * New sequence number is bigger than the base but 164 * it's not bigger than base + window size 165 */ 166 167 shiftwords = ((wint + shift - 1) >> WORD_SHIFT) - 168 ((wint - 1) >> WORD_SHIFT); 169 if (unlikely(shiftwords)) { 170 tmp = (wint + WORD_SIZE - 1) / WORD_SIZE; 171 for (i = 0; i < shiftwords; i++) { 172 tmp %= winwords; 173 window[tmp++] = 0; 174 } 175 } 176 177 goto winupdate; 178 } 179 180 /* Sequence number is before the window */ 181 if (unlikely((seq + winsz) <= base)) 182 return IPSEC_ANTI_REPLAY_FAILED; 183 184 /* Sequence number is within the window */ 185 186 /* Find out the word */ 187 seqword = ((seq - 1) % ex_winsz) >> WORD_SHIFT; 188 189 /* Find out the bit in the word */ 190 bit_pos = (seq - 1) & WORD_MASK; 191 192 /* Check if this is a replayed packet */ 193 if (window[seqword] & (1ull << (63 - bit_pos))) 194 return IPSEC_ANTI_REPLAY_FAILED; 195 196 /* 197 * Set the bit corresponding to sequence number 198 * in window to mark it as received 199 */ 200 window[seqword] |= (1ull << (63 - bit_pos)); 201 202 return 0; 203} 204 205#endif /* __CNXK_SECURITY_AR_H__ */ 206