git: 98e55905ab8a - main - LinuxKPI: 802.11: lkpi_hw_crypto_prepare and lkpi_hw_crypto_tailroom

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

URL: https://cgit.FreeBSD.org/src/commit/?id=98e55905ab8ac34a0b88a1863c1b88e6fe3a8c13

commit 98e55905ab8ac34a0b88a1863c1b88e6fe3a8c13
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-15 20:59:45 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-23 16:24:20 +0000

    LinuxKPI: 802.11: lkpi_hw_crypto_prepare and lkpi_hw_crypto_tailroom
    
    Split lkpi_hw_crypto_prepare() up per cipher suite and in addition to
    the CCMP implementation start drafting the TKIP implementation.
    Also add lkpi_hw_crypto_tailroom() dealing with any possible tailroom
    we need to prepare for the driver to fill in details later.
    Add support for that to lkpi_80211_txq_tx_one().
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/src/linux_80211.c | 130 ++++++++++++++++++++++-----
 1 file changed, 110 insertions(+), 20 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 28c04c9b7a99..6fe41ddb1bb2 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -4609,34 +4609,56 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
 
 #ifdef LKPI_80211_HW_CRYPTO
 static int
-lkpi_hw_crypto_prepare(struct lkpi_sta *lsta, struct ieee80211_key *k,
-    struct sk_buff *skb)
+lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,
+    struct ieee80211_key_conf *kc, struct sk_buff *skb)
 {
-	struct ieee80211_tx_info *info;
-	struct ieee80211_key_conf *kc;
 	struct ieee80211_hdr *hdr;
 	uint32_t hlen, hdrlen;
-	uint8_t *p;
+	uint8_t *p, *m;
 
-	KASSERT(lsta != NULL, ("%s: lsta is NULL", __func__));
-	KASSERT(k != NULL, ("%s: key is NULL", __func__));
-	KASSERT(skb != NULL, ("%s: skb is NULL", __func__));
+	/*
+	 * Check if we have anythig to do as requested by driver
+	 * or if we are done?
+	 */
+	if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&
+	    (kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0)
+			return (0);
 
-	kc = lsta->kc[k->wk_keyix];
+	hlen = k->wk_cipher->ic_header;
+	if (skb_headroom(skb) < hlen)
+		return (ENOSPC);
 
-	info = IEEE80211_SKB_CB(skb);
-	info->control.hw_key = kc;
+	hdr = (void *)skb->data;
+	hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	p = skb_push(skb, hlen);
+	memmove(p, p + hlen, hdrlen);
 
-	/* MUST NOT happen. KASSERT? */
-	if (kc == NULL) {
-		ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p skb %p, "
-		    "kc is NULL on hw crypto offload\n", __func__, lsta, k, skb);
-		return (ENXIO);
+	/*
+	 * 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);
+
+	p += hdrlen;
+	k->wk_cipher->ic_setiv(k, p);
 
-	IMPROVE("the following should be WLAN_CIPHER_SUITE specific");
-	/* We currently only support CCMP so we hardcode things here. */
+	return (ENXIO);
+}
+static int
+lkpi_hw_crypto_prepare_ccmp(struct ieee80211_key *k,
+    struct ieee80211_key_conf *kc, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr;
+	uint32_t hlen, hdrlen;
+	uint8_t *p;
 
 	hdr = (void *)skb->data;
 
@@ -4668,6 +4690,67 @@ lkpi_hw_crypto_prepare(struct lkpi_sta *lsta, struct ieee80211_key *k,
 
 	return (0);
 }
+
+static int
+lkpi_hw_crypto_prepare(struct lkpi_sta *lsta, struct ieee80211_key *k,
+    struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info;
+	struct ieee80211_key_conf *kc;
+
+	KASSERT(lsta != NULL, ("%s: lsta is NULL", __func__));
+	KASSERT(k != NULL, ("%s: key is NULL", __func__));
+	KASSERT(skb != NULL, ("%s: skb is NULL", __func__));
+
+	kc = lsta->kc[k->wk_keyix];
+
+	info = IEEE80211_SKB_CB(skb);
+	info->control.hw_key = kc;
+
+	/* MUST NOT happen. KASSERT? */
+	if (kc == NULL) {
+		ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p skb %p, "
+		    "kc is NULL on hw crypto offload\n", __func__, lsta, k, skb);
+		return (ENXIO);
+	}
+
+	switch (kc->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		return (lkpi_hw_crypto_prepare_tkip(k, kc, skb));
+	case WLAN_CIPHER_SUITE_CCMP:
+		return (lkpi_hw_crypto_prepare_ccmp(k, kc, skb));
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+	case WLAN_CIPHER_SUITE_CCMP_256:
+	case WLAN_CIPHER_SUITE_GCMP:
+	case WLAN_CIPHER_SUITE_GCMP_256:
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+	default:
+		ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p kc %p skb %p, "
+		    "unsupported cipher suite %u (%s)\n", __func__, lsta, k, kc,
+		    skb, kc->cipher, lkpi_cipher_suite_to_name(kc->cipher));
+		return (EOPNOTSUPP);
+	}
+}
+
+static uint8_t
+lkpi_hw_crypto_tailroom(struct lkpi_sta *lsta, struct ieee80211_key *k)
+{
+	struct ieee80211_key_conf *kc;
+
+	kc = lsta->kc[k->wk_keyix];
+	if (kc == NULL)
+		return (0);
+
+	IMPROVE("which other flags need tailroom?");
+	if (kc->flags & (IEEE80211_KEY_FLAG_PUT_MIC_SPACE))
+		return (32);	/* Large enough to hold everything and pow2. */
+
+	return (0);
+}
 #endif
 
 static void
@@ -4690,7 +4773,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
 	struct lkpi_txq *ltxq;
 	void *buf;
 	ieee80211_keyix keyix;
-	uint8_t ac, tid;
+	uint8_t ac, tid, tailroom;
 
 	M_ASSERTPKTHDR(m);
 #ifdef LINUXKPI_DEBUG_80211
@@ -4748,13 +4831,20 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
 		ieee80211_radiotap_tx(ni->ni_vap, m);
 	}
 
+#ifdef LKPI_80211_HW_CRYPTO
+	if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE)
+		tailroom = lkpi_hw_crypto_tailroom(lsta, k);
+	else
+#endif
+		tailroom = 0;
+
 	/*
 	 * net80211 should handle hw->extra_tx_headroom.
 	 * Though for as long as we are copying we don't mind.
 	 * XXX-BZ rtw88 asks for too much headroom for ipv6+tcp:
 	 * https://lists.freebsd.org/archives/freebsd-transport/2022-February/000012.html
 	 */
-	skb = dev_alloc_skb(hw->extra_tx_headroom + m->m_pkthdr.len);
+	skb = dev_alloc_skb(hw->extra_tx_headroom + tailroom + m->m_pkthdr.len);
 	if (skb == NULL) {
 		static uint8_t skb_alloc_failures = 0;