git: 4b9ae864fc46 - main - LinuxKPI: 802.11: make TKIP start to work

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Wed, 23 Apr 2025 16:25:24 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=4b9ae864fc46f75d87d04b1b9c343f317a9d0bed

commit 4b9ae864fc46f75d87d04b1b9c343f317a9d0bed
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-16 08:22:20 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-23 16:24:21 +0000

    LinuxKPI: 802.11: make TKIP start to work
    
    In lkpi_iv_key_set() change the order to check if the cipher suite
    is supported. This for one avoids a possible kc memory leak, for the
    other allows us to extend the keylen we use for allocating memory.
    TKIP does need extra space as in addition to the key the RX/TX MIC
    are appended.  Copy those now as well.
    
    In lkpi_hw_crypto_prepare_tkip() do the "enmic" (making space) part
    first before doing the "encap" part (making space).  While this is
    technically not fully correct as the "enmic" would be done once for
    the entire MSDU and the "encap" would be done for each fragment, we
    are currently not setup to do per-vap or per-ic callbacks for this
    at the right moment from net80211.  It will require a bit of thought.
    On the other hand we expect the firmware to do all this so it should
    be fine for as long as we no longer skip one part.
    We can likely start being more creative here in the compat code if
    needed.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/src/linux_80211.c | 90 +++++++++++++++++++---------
 1 file changed, 61 insertions(+), 29 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index b9d8cc7263ae..eef8024c5e84 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -1353,6 +1353,7 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
 	struct ieee80211_key_conf *kc;
 	uint32_t lcipher;
 	uint16_t exp_flags;
+	uint8_t keylen;
 	int error;
 
 	ic = vap->iv_ic;
@@ -1377,21 +1378,14 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
 	}
 	sta = LSTA_TO_STA(lsta);
 
-	if (lsta->kc[k->wk_keyix] != NULL) {
-		IMPROVE("Still in firmware? Del first. Can we assert this cannot happen?");
-		ic_printf(ic, "%s: sta %6D found with key information\n",
-		    __func__, sta->addr, ":");
-		kc = lsta->kc[k->wk_keyix];
-		lsta->kc[k->wk_keyix] = NULL;
-		free(kc, M_LKPI80211);
-		kc = NULL;	/* safeguard */
-	}
-
+	keylen = k->wk_keylen;
 	lcipher = lkpi_net80211_to_l80211_cipher_suite(
 	    k->wk_cipher->ic_cipher, k->wk_keylen);
 	switch (lcipher) {
 	case WLAN_CIPHER_SUITE_CCMP:
+		break;
 	case WLAN_CIPHER_SUITE_TKIP:
+		keylen += 2 * k->wk_cipher->ic_miclen;
 		break;
 	default:
 		ic_printf(ic, "%s: CIPHER SUITE %#x (%s) not supported\n",
@@ -1401,9 +1395,18 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
 		return (0);
 	}
 
-	kc = malloc(sizeof(*kc) + k->wk_keylen, M_LKPI80211, M_WAITOK | M_ZERO);
+	if (lsta->kc[k->wk_keyix] != NULL) {
+		IMPROVE("Still in firmware? Del first. Can we assert this cannot happen?");
+		ic_printf(ic, "%s: sta %6D found with key information\n",
+		    __func__, sta->addr, ":");
+		kc = lsta->kc[k->wk_keyix];
+		lsta->kc[k->wk_keyix] = NULL;
+		free(kc, M_LKPI80211);
+		kc = NULL;	/* safeguard */
+	}
+
+	kc = malloc(sizeof(*kc) + keylen, M_LKPI80211, M_WAITOK | M_ZERO);
 	kc->_k = k;		/* Save the pointer to net80211. */
-	atomic64_set(&kc->tx_pn, k->wk_keytsc);
 	kc->cipher = lcipher;
 	kc->keyidx = k->wk_keyix;
 #if 0
@@ -1424,6 +1427,8 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
 		kc->icv_len = k->wk_cipher->ic_trailer;
 		break;
 	case WLAN_CIPHER_SUITE_TKIP:
+		memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, k->wk_txmic, k->wk_cipher->ic_miclen);
+		memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, k->wk_rxmic, k->wk_cipher->ic_miclen);
 		kc->iv_len = k->wk_cipher->ic_header;
 		kc->icv_len = k->wk_cipher->ic_trailer;
 		break;
@@ -1437,9 +1442,9 @@ lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
 #ifdef LINUXKPI_DEBUG_80211
 	if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)
 		ic_printf(ic, "%s: running set_key cmd %d(%s) for sta %6D: "
-		    "kc %p keyidx %u hw_key_idx %u flags %b\n", __func__,
-		    SET_KEY, "SET", sta->addr, ":",
-		    kc, kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);
+		    "kc %p keyidx %u hw_key_idx %u keylen %u flags %b\n", __func__,
+		    SET_KEY, "SET", sta->addr, ":", kc, kc->keyidx, kc->hw_key_idx,
+		    kc->keylen, kc->flags, IEEE80211_KEY_FLAG_BITS);
 #endif
 
 	lhw = ic->ic_softc;
@@ -4679,16 +4684,51 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
 }
 
 #ifdef LKPI_80211_HW_CRYPTO
+/*
+ * This is a bit of a hack given we know we are operating on a
+ * single frame and we know that hardware will deal with it.
+ * But otherwise the enmic bit and the encrypt bit need to be
+ * decoupled.
+ */
 static int
 lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,
     struct ieee80211_key_conf *kc, struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr;
 	uint32_t hlen, hdrlen;
-	uint8_t *p, *m;
+	uint8_t *p;
 
 	/*
-	 * Check if we have anythig to do as requested by driver
+	 * TKIP only happens on data.
+	 */
+	hdr = (void *)skb->data;
+	if (!ieee80211_is_data_present(hdr->frame_control))
+		return (0);
+
+	/*
+	 * "enmic" (though we do not do that).
+	 */
+	/* any conditions to not apply this? */
+	if (skb_tailroom(skb) < k->wk_cipher->ic_miclen)
+		return (ENOBUFS);
+
+	p = skb_put(skb, k->wk_cipher->ic_miclen);
+	if ((kc->flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) != 0)
+		goto encrypt;
+
+	/*
+	 * (*enmic) which we hopefully do not have to do with hw accel.
+	 * That means if we make it here we have a problem.
+	 */
+	TODO("(*enmic)");
+	return (ENXIO);
+
+encrypt:
+	/*
+	 * "encrypt" (though we do not do that).
+	 */
+	/*
+	 * Check if we have anything to do as requested by driver
 	 * or if we are done?
 	 */
 	if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&
@@ -4697,23 +4737,13 @@ lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,
 
 	hlen = k->wk_cipher->ic_header;
 	if (skb_headroom(skb) < hlen)
-		return (ENOSPC);
+		return (ENOBUFS);
 
 	hdr = (void *)skb->data;
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	p = skb_push(skb, hlen);
 	memmove(p, p + hlen, hdrlen);
 
-	/*
-	 * Put in zeroed space for the MMIC if requested.
-	 * XXX-BZ in theory this is not the right place but given we
-	 * are here we know we do hw_crypto so not much missing.
-	 */
-	if ((kc->flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) != 0) {
-		m = skb_put(skb, 8);
-		memset(m, 0, 8);
-	}
-
 	/* If driver request space only we are done. */
 	if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) != 0)
 		return (0);
@@ -4721,6 +4751,8 @@ lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,
 	p += hdrlen;
 	k->wk_cipher->ic_setiv(k, p);
 
+	/* If we make it hear we do sw encryption. */
+	TODO("sw encrypt");
 	return (ENXIO);
 }
 static int
@@ -4746,7 +4778,7 @@ lkpi_hw_crypto_prepare_ccmp(struct ieee80211_key *k,
 
 	hlen = k->wk_cipher->ic_header;
 	if (skb_headroom(skb) < hlen)
-		return (ENOSPC);
+		return (ENOBUFS);
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	p = skb_push(skb, hlen);