git: bdc94f09bd96 - stable/14 - net80211/crypto: LinuxKPI/802.11: introduce IEEE80211_RX_F_PN_VALIDATED
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 24 Feb 2025 20:27:10 UTC
The branch stable/14 has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=bdc94f09bd96b28dcb841afa31f44b0879130134
commit bdc94f09bd96b28dcb841afa31f44b0879130134
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-01-07 12:02:54 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-02-24 20:26:48 +0000
net80211/crypto: LinuxKPI/802.11: introduce IEEE80211_RX_F_PN_VALIDATED
There are cases when we see "rx seq# violation (CCMP)".
Historically these were AHDEMO/IBBS cases (IEEE80211_KEY_NOREPLAY,
see 5d766a09daab2).
With iwlwifi(4) doing RSS for newer chipsets and us not having any idea
about multiple rx-queues (passed all the way through) leads to the same
problem. An easy way to trigger this is doing an IPv6 all-nodes echo
request. With a sufficient amount of nodes answering the answers will
be hashed to different queues and re-ordering will likely take place
as queues get released individually.
However crypto validation is already done in fw/driver for these cases
and we need to carry the state forward. Add IEEE80211_RX_F_PN_VALIDATED
to indicate that the checks were done passing the information from driver
through LinuxKPI to net80211.
LinuxKPI enforces that a frame was indeed decrypted; otherwise the flag
would be invalid.
This also avoids returning an error and no key from
ieee80211_crypto_decap() and thus avoids dropping the frame.
Sponsored by: The FreeBSD Foundation
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D49029
(cherry picked from commit ec6185c52661d3af0dac6dcc8701fc49fae3e1d9)
---
sys/compat/linuxkpi/common/src/linux_80211.c | 16 +++++++++++++++-
sys/net80211/_ieee80211.h | 1 +
sys/net80211/ieee80211_crypto_ccmp.c | 16 +++++++++++++---
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 02cacc62a4c2..7b0ddc3cbf9a 100644
--- 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
@@ -5425,6 +5425,20 @@ no_trace_beacons:
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
index 929de475f4bf..8b86cd612168 100644
--- a/sys/net80211/_ieee80211.h
+++ b/sys/net80211/_ieee80211.h
@@ -573,6 +573,7 @@ struct ieee80211_mimo_info {
#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
index 45e795a8799b..8f7d5eed593c 100644
--- a/sys/net80211/ieee80211_crypto_ccmp.c
+++ b/sys/net80211/ieee80211_crypto_ccmp.c
@@ -238,6 +238,7 @@ ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
struct ieee80211_frame *wh;
uint8_t *ivp, tid;
uint64_t pn;
+ bool noreplaycheck;
rxs = ieee80211_get_rx_params_ptr(m);
@@ -261,8 +262,10 @@ ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
}
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 @@ finish:
* 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;