git: 1751bf9e58dd - main - net80211: fail setting a key if the cipher isn't HW/SW supported

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Tue, 08 Apr 2025 01:35:29 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=1751bf9e58ddc41f3cde013ebe7cc6bcfc17eb56

commit 1751bf9e58ddc41f3cde013ebe7cc6bcfc17eb56
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2025-03-17 03:16:06 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2025-04-08 01:35:22 +0000

    net80211: fail setting a key if the cipher isn't HW/SW supported
    
    The key alloc path was checking if the key was supported in hardware
    but treated /all/ keys as supported in software.  As I discovered
    during my ath10k port, not all NICs that support ciphers in hardware
    support enough of an 802.11 frame transmit/receive path to actually
    handle software encryption.
    
    So, do a second check after the hardware encryption check to see
    if it's in the software list and hard fail it if it isn't in there.
    
    Otherwise a fun failure mode occurs - the frames are marked as
    protected, but since there's no GCMP support setup/enabled, they
    just get marked as "protected" but they don't go through the
    encryption path, and the receiver dutifully tosses them as invalid.
    
    I've verified this by trying to use GCMP in wpa_supplicant with
    a NIC that doesn't announce GCMP HW/SW encryption, and now it actually
    fails.
    
    Differential Revision:  https://reviews.freebsd.org/D49393
    Reviewed by:    bz
---
 sys/net80211/ieee80211_crypto.c | 15 +++++++++++++++
 sys/net80211/ieee80211_ioctl.h  |  1 +
 2 files changed, 16 insertions(+)

diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c
index 84cf1d02e408..6b636da9fa2c 100644
--- a/sys/net80211/ieee80211_crypto.c
+++ b/sys/net80211/ieee80211_crypto.c
@@ -397,6 +397,21 @@ ieee80211_crypto_newkey(struct ieee80211vap *vap,
 		    __func__, cip->ic_name);
 		flags |= IEEE80211_KEY_SWCRYPT;
 	}
+	/*
+	 * Check if the software cipher is available; if not then
+	 * fail it early.
+	 *
+	 * Some devices do not support all ciphers in software
+	 * (for example they don't support a "raw" data path.)
+	 */
+	if ((flags & IEEE80211_KEY_SWCRYPT) &&
+	    (ic->ic_sw_cryptocaps & (1<<cipher)) == 0) {
+		IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
+		    "%s: no s/w support for cipher %s, rejecting\n",
+		    __func__, cip->ic_name);
+		vap->iv_stats.is_crypto_swcipherfail++;
+		return (0);
+	}
 	/*
 	 * Hardware TKIP with software MIC is an important
 	 * combination; we handle it by flagging each key,
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index 6064f586c923..d542d75312b9 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -259,6 +259,7 @@ struct ieee80211_stats {
 	uint32_t	is_rx_gcmpmic;		/* rx MIC check failed (GCMP) */
 	uint32_t	is_crypto_gcmp_nomem;	/* gcmp crypto failed; no mem */
 	uint32_t	is_crypto_gcmp_nospc;	/* gcmp crypto failed; no mbuf space */
+	uint32_t	is_crypto_swcipherfail;	/* no support for SW cipher */
 
 	uint32_t	is_spare[5];
 };