diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2020-2024 The FreeBSD Foundation + * Copyright (c) 2020-2025 The FreeBSD Foundation * Copyright (c) 2020-2025 Bjoern A. Zeeb * * This software was developed by Björn Zeeb under sponsorship from @@ -5424,6 +5424,20 @@ rx_stats.c_freq = rx_status->freq; rx_stats.c_ieee = ieee80211_mhz2ieee(rx_stats.c_freq, rx_stats.c_band); + /* + * We only need these for LKPI_80211_HW_CRYPTO in theory but in + * case the hardware does something we do not expect always leave + * these enabled. Leaving this commant as documentation for the || 1. + */ +#if defined(LKPI_80211_HW_CRYPTO) || 1 + if (rx_status->flag & RX_FLAG_DECRYPTED) { + rx_stats.c_pktflags |= IEEE80211_RX_F_DECRYPTED; + /* Only valid if decrypted is set. */ + if (rx_status->flag & RX_FLAG_PN_VALIDATED) + rx_stats.c_pktflags |= IEEE80211_RX_F_PN_VALIDATED; + } +#endif + /* XXX (*sta_statistics)() to get to some of that? */ /* XXX-BZ dump the FreeBSD version of rx_stats as well! */ diff --git a/sys/net80211/_ieee80211.h b/sys/net80211/_ieee80211.h --- a/sys/net80211/_ieee80211.h +++ b/sys/net80211/_ieee80211.h @@ -594,6 +594,7 @@ #define IEEE80211_RX_F_OFDM 0x00002000 #define IEEE80211_RX_F_HT 0x00004000 #define IEEE80211_RX_F_VHT 0x00008000 +#define IEEE80211_RX_F_PN_VALIDATED 0x00010000 /* Decrypted; PN validated */ /* Channel width */ #define IEEE80211_RX_FW_20MHZ 1 diff --git a/sys/net80211/ieee80211_crypto_ccmp.c b/sys/net80211/ieee80211_crypto_ccmp.c --- a/sys/net80211/ieee80211_crypto_ccmp.c +++ b/sys/net80211/ieee80211_crypto_ccmp.c @@ -238,6 +238,7 @@ struct ieee80211_frame *wh; uint8_t *ivp, tid; uint64_t pn; + bool noreplaycheck; rxs = ieee80211_get_rx_params_ptr(m); @@ -261,8 +262,10 @@ } tid = ieee80211_gettid(wh); pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); - if (pn <= k->wk_keyrsc[tid] && - (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { + + noreplaycheck = (k->wk_flags & IEEE80211_KEY_NOREPLAY) != 0; + noreplaycheck |= (rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_PN_VALIDATED) != 0; + if (pn <= k->wk_keyrsc[tid] && !noreplaycheck) { /* * Replay violation. */ @@ -302,7 +305,14 @@ * Ok to update rsc now. */ if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { - k->wk_keyrsc[tid] = pn; + /* + * Do not go backwards in the IEEE80211_KEY_NOREPLAY cases + * or in case hardware has checked but frames are arriving + * reordered (e.g., LinuxKPI drivers doing RSS which we are + * not prepared for at all). + */ + if (pn > k->wk_keyrsc[tid]) + k->wk_keyrsc[tid] = pn; } return 1;