Skip site navigation (1)Skip section navigation (2)


| raw e-mail | index | archive | help
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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?>