From nobody Mon Feb 24 20:27:19 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Z1sjR4Sgzz5pq0H; Mon, 24 Feb 2025 20:27:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Z1sjN2vhCz3nxL; Mon, 24 Feb 2025 20:27:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1740428840; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=xvQjMCHmi6s2u4GUsamQ+G15qKDpbgnThzzRP+qS1HU=; b=ndNekVlsDdjVwtRe3+NZTaRE+IzKXukREFLRZG9Vff8QPA90yxOPGwT83SaXAH8r82lCes wHLq/yzLVe9qH2pC4JB1Zm+D14EazwbKCieGVw4SKL9hXb+5vRFsGP3GK0snFxjETmFtv2 OQkiKgLM2RDqx0/GlSKWKA4VZE0/Kw3NW2JNHOr5+8cqh+atF/yBXpSsiu9PCJv3WdJrGZ hxVXnocI+4Sx25XhyZJW34lqpmciRwhqFr2UCyvCZo5cZG98JT0iARG0jFQ6a6DZa5xZQw gTATu8k9nfMt3934xI8qdeg5nkVdcy7di8tF8w36nmZWxy3DcfVNjR8fXpbK7Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1740428840; a=rsa-sha256; cv=none; b=Q1RKSA0VGKcI6hI+jMVlg4miAVK87gpj+ry6yS7kcVBp3GH+d+nDNIXiQf4aL+TY2mIWM/ OhRXnJAJsW/1CZbAXd1jL5kfAno5mZyyB53t/63cdrslgyBlg1CX4FLbV9qXA/5mf7whao hbb6xMgyu74x9tVvsQI5mRWQycdWwdvUnHtuDkZ2OOK/s4rhUtlVqFi9M+5RdErT4TLwUr 6wsn72Ppxl9nxbd0H9n1VSyT9/mGhRLeY9A1qDrWFmU0N94sC0zEsuUZxJiCv8gaPfOGEc QmGaLTkOs2uGWVdXjsgQaIE/xApR77R++E1KLV5nUzIJVZ3bhLWh8FwDId1ukQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1740428840; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=xvQjMCHmi6s2u4GUsamQ+G15qKDpbgnThzzRP+qS1HU=; b=gblxJG1ZpQw2d4BXldH8gK8845Igu8McBw0Qp9rV8WSxTVhYtlAKlODkxPpXDe5sO7Xign qSMUFVXTvKSrWQa6Zi+sR81pt72zTtnPqERF1FSTCSX1C2GElFQlGxHb9GVLryF2YPj/8w ahNLWTD5sDFrNThaHCGOtuvmnkCreWES+6mjn0rvxj9U8mROQh1GfAZ7m/Mlf8CJtIS93k 4hpeKZCzftolnrW8rjUMqCsW5AJzU6CScxKbf9u82cCCwtHkHHBplabPAxAOz8i+qAfG6p kiBHKtKi5FZ/BrDtDeeg4NbXrkvakQqc0bFTsH0DoVl+UOF0Pq0c8JeRC5medA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Z1sjM70lGzwPy; Mon, 24 Feb 2025 20:27:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 51OKRJ9U027569; Mon, 24 Feb 2025 20:27:19 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 51OKRJ2o027566; Mon, 24 Feb 2025 20:27:19 GMT (envelope-from git) Date: Mon, 24 Feb 2025 20:27:19 GMT Message-Id: <202502242027.51OKRJ2o027566@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Bjoern A. Zeeb" Subject: git: 5d6b85d086bc - stable/14 - LinuxKPI: 802.11: hardware crypto offload improvements List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bz X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 5d6b85d086bc76730f052b6a69241fa6dc7c52c7 Auto-Submitted: auto-generated The branch stable/14 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=5d6b85d086bc76730f052b6a69241fa6dc7c52c7 commit 5d6b85d086bc76730f052b6a69241fa6dc7c52c7 Author: Bjoern A. Zeeb AuthorDate: 2024-01-27 22:39:48 +0000 Commit: Bjoern A. Zeeb CommitDate: 2025-02-24 20:26:49 +0000 LinuxKPI: 802.11: hardware crypto offload improvements Implement mac80211 functions ieee80211_iter_keys[_rcu](), and ieee80211_get_key_rx_seq() (*). Implement an internal function lkpi_sta_del_keys() to delete keys when we are leaving RUN (AUTHORIZED) state. Improve and make work (*) the net80211 vap function pointers (*iv_key_set)(), (*iv_key_delete)() implementations. Correct the logic in lkpi_80211_txq_tx_one() and factor most crypto related bits out into lkpi_hw_crypto_prepare() (*). (*) We are currently supporting CCMP only. I would hope we will not have to do full WEP/TKIP support anymore given both are deprecated. The entire logic remains behind the LKPI_80211_HW_CRYPTO pre-processor condition and with this commit in addition behind a tunable. The code is compiled in by default now but the tunable remains off until wider testing has shown no problems. I have seen one net80211 triggered panic on shutdown related to deleting keys which I cannot reproduce anymore and could have been fixed by 9763fec11b83; otherwise we will have to investigate as it shows again. The dedicated hw crypto tracing option can help in that case with debug kernels. Sponsored by: The FreeBSD Foundation Fixes: b35f6cd06612 (cherry picked from commit 11db70b6057e41b259dc2245cd893d5b19179fcc) --- sys/compat/linuxkpi/common/include/net/mac80211.h | 81 ++-- sys/compat/linuxkpi/common/src/linux_80211.c | 492 ++++++++++++++++++--- sys/compat/linuxkpi/common/src/linux_80211.h | 3 +- .../linuxkpi/common/src/linux_80211_macops.c | 2 + 4 files changed, 489 insertions(+), 89 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h index 8d6d690b2f57..69956c90042c 100644 --- a/sys/compat/linuxkpi/common/include/net/mac80211.h +++ b/sys/compat/linuxkpi/common/include/net/mac80211.h @@ -555,6 +555,9 @@ enum ieee802111_key_flag { }; struct ieee80211_key_conf { +#if defined(__FreeBSD__) + const struct ieee80211_key *_k; /* backpointer to net80211 */ +#endif atomic64_t tx_pn; uint32_t cipher; uint8_t icv_len; /* __unused nowadays? */ @@ -1154,7 +1157,7 @@ void linuxkpi_ieee80211_iterate_keys(struct ieee80211_hw *, struct ieee80211_vif *, void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct ieee80211_key_conf *, void *), - void *); + void *, bool); void linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *, void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *, void *), @@ -1520,25 +1523,22 @@ ieee80211_iterate_interfaces(struct ieee80211_hw *hw, linuxkpi_ieee80211_iterate_interfaces(hw, flags, iterfunc, arg); } -static __inline void +static inline void ieee80211_iter_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct ieee80211_key_conf *, void *), void *arg) { - - linuxkpi_ieee80211_iterate_keys(hw, vif, iterfunc, arg); + linuxkpi_ieee80211_iterate_keys(hw, vif, iterfunc, arg, false); } -static __inline void +static inline void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct ieee80211_key_conf *, void *), void *arg) { - - IMPROVE(); /* "rcu" */ - linuxkpi_ieee80211_iterate_keys(hw, vif, iterfunc, arg); + linuxkpi_ieee80211_iterate_keys(hw, vif, iterfunc, arg, true); } static __inline void @@ -2094,33 +2094,6 @@ ieee80211_sta_set_buffered(struct ieee80211_sta *sta, uint8_t tid, bool t) TODO(); } -static __inline void -ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, uint8_t tid, - struct ieee80211_key_seq *seq) -{ - - KASSERT(keyconf != NULL && seq != NULL, ("%s: keyconf %p seq %p\n", - __func__, keyconf, seq)); - - TODO(); - switch (keyconf->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_CCMP_256: - memset(seq->ccmp.pn, 0xfa, sizeof(seq->ccmp.pn)); /* XXX TODO */ - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - memset(seq->aes_cmac.pn, 0xfa, sizeof(seq->aes_cmac.pn)); /* XXX TODO */ - break; - case WLAN_CIPHER_SUITE_TKIP: - seq->tkip.iv32 = 0xfa; /* XXX TODO */ - seq->tkip.iv16 = 0xfa; /* XXX TODO */ - break; - default: - pr_debug("%s: unsupported cipher suite %d\n", __func__, keyconf->cipher); - break; - } -} - static __inline void ieee80211_sched_scan_results(struct ieee80211_hw *hw) { @@ -2466,6 +2439,44 @@ ieee80211_remove_key(struct ieee80211_key_conf *key) TODO(); } +static inline void +ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, int8_t tid, + struct ieee80211_key_seq *seq) +{ + const struct ieee80211_key *k; + const uint8_t *p; + + KASSERT(keyconf != NULL && seq != NULL, ("%s: keyconf %p seq %p\n", + __func__, keyconf, seq)); + KASSERT(tid <= IEEE80211_NUM_TIDS, ("%s: tid out of bounds %d\n", + __func__, tid)); + k = keyconf->_k; + KASSERT(k != NULL, ("%s: keyconf %p ieee80211_key is NULL\n", __func__, keyconf)); + + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + if (tid < 0) + p = (const uint8_t *)&k->wk_keyrsc[IEEE80211_NUM_TIDS]; /* IEEE80211_NONQOS_TID */ + else + p = (const uint8_t *)&k->wk_keyrsc[tid]; + memcpy(seq->ccmp.pn, p, sizeof(seq->ccmp.pn)); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + TODO(); + memset(seq->aes_cmac.pn, 0xfa, sizeof(seq->aes_cmac.pn)); /* XXX TODO */ + break; + case WLAN_CIPHER_SUITE_TKIP: + TODO(); + seq->tkip.iv32 = 0xfa; /* XXX TODO */ + seq->tkip.iv16 = 0xfa; /* XXX TODO */ + break; + default: + pr_debug("%s: unsupported cipher suite %d\n", __func__, keyconf->cipher); + break; + } +} + static __inline void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *key, int tid, struct ieee80211_key_seq *seq) diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index b276f502be76..683de6e0d474 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -39,7 +39,12 @@ * We call the internal versions lxxx (e.g., hw -> lhw, sta -> lsta). */ -#include +/* + * TODO: + * - lots :) + * - HW_CRYPTO: we need a "keystore" and an ordered list for suspend/resume. + */ + #include #include #include @@ -72,12 +77,16 @@ #include "linux_80211.h" #define LKPI_80211_WME -/* #define LKPI_80211_HW_CRYPTO */ -/* #define LKPI_80211_VHT */ +#define LKPI_80211_HW_CRYPTO /* #define LKPI_80211_HT */ +/* #define LKPI_80211_VHT */ + #if defined(LKPI_80211_VHT) && !defined(LKPI_80211_HT) #define LKPI_80211_HT #endif +#if defined(LKPI_80211_HT) && !defined(LKPI_80211_HW_CRYPTO) +#define LKPI_80211_HW_CRYPTO +#endif static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat"); @@ -93,6 +102,12 @@ SYSCTL_DECL(_compat_linuxkpi); SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "LinuxKPI 802.11 compatibility layer"); +#if defined(LKPI_80211_HW_CRYPTO) +static bool lkpi_hwcrypto = false; +SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, hw_crypto, CTLFLAG_RDTUN, + &lkpi_hwcrypto, 0, "Enable LinuxKPI 802.11 hardware crypto offload"); +#endif + /* Keep public for as long as header files are using it too. */ int linuxkpi_debug_80211; @@ -439,7 +454,7 @@ lkpi_lsta_dump(struct lkpi_sta *lsta, struct ieee80211_node *ni, ieee80211_dump_node(NULL, ni); printf("\ttxq_task txq len %d mtx\n", mbufq_len(&lsta->txq)); printf("\tkc %p state %d added_to_drv %d in_mgd %d\n", - lsta->kc, lsta->state, lsta->added_to_drv, lsta->in_mgd); + &lsta->kc[0], lsta->state, lsta->added_to_drv, lsta->in_mgd); #endif } @@ -905,20 +920,173 @@ linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq) #ifdef LKPI_80211_HW_CRYPTO static int -_lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, - enum set_key_cmd cmd) +lkpi_sta_del_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct lkpi_sta *lsta) +{ + int error; + + if (!lkpi_hwcrypto) + return (0); + + lockdep_assert_wiphy(hw->wiphy); + ieee80211_ref_node(lsta->ni); + + error = 0; + for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc); keyix++) { + struct ieee80211_key_conf *kc; + int err; + + if (lsta->kc[keyix] == NULL) + continue; + kc = lsta->kc[keyix]; + + err = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, + LSTA_TO_STA(lsta), kc); + if (err != 0) { + ic_printf(lsta->ni->ni_ic, "%s: set_key cmd %d(%s) for " + "sta %6D failed: %d\n", __func__, DISABLE_KEY, + "DISABLE", lsta->sta.addr, ":", err); + error++; + + /* + * If we free the key here we will never be able to get it + * removed from the driver/fw which will likely make us + * crash (firmware). + */ + continue; + } +#ifdef LINUXKPI_DEBUG_80211 + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(lsta->ni->ni_ic, "%s: set_key cmd %d(%s) for " + "sta %6D succeeded: keyidx %u hw_key_idx %u flags %#10x\n", + __func__, DISABLE_KEY, "DISABLE", lsta->sta.addr, ":", + kc->keyidx, kc->hw_key_idx, kc->flags); +#endif + + lsta->kc[keyix] = NULL; + free(kc, M_LKPI80211); + } + ieee80211_free_node(lsta->ni); + return (error); +} + +static int +_lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) { struct ieee80211com *ic; struct lkpi_hw *lhw; struct ieee80211_hw *hw; struct lkpi_vif *lvif; + struct lkpi_sta *lsta; struct ieee80211_vif *vif; struct ieee80211_sta *sta; struct ieee80211_node *ni; struct ieee80211_key_conf *kc; + struct ieee80211_node_table *nt; int error; + bool islocked; - /* XXX TODO Check (k->wk_flags & IEEE80211_KEY_SWENCRYPT) and don't upload to driver/hw? */ + ic = vap->iv_ic; + lhw = ic->ic_softc; + hw = LHW_TO_HW(lhw); + lvif = VAP_TO_LVIF(vap); + vif = LVIF_TO_VIF(lvif); + + if (vap->iv_bss == NULL) { + ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n", + __func__, vap->iv_bss, vap); + return (0); + } + ni = ieee80211_ref_node(vap->iv_bss); + lsta = ni->ni_drv_data; + if (lsta == NULL) { + ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n", + __func__, ni, ni->ni_bssid, ":"); + ieee80211_free_node(ni); + return (0); + } + sta = LSTA_TO_STA(lsta); + + if (lsta->kc[k->wk_keyix] == NULL) { +#ifdef LINUXKPI_DEBUG_80211 + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(ic, "%s: sta %6D and no key information, " + "keyidx %u wk_macaddr %6D; returning success\n", + __func__, sta->addr, ":", + k->wk_keyix, k->wk_macaddr, ":"); +#endif + ieee80211_free_node(ni); + return (1); + } + + /* This is inconsistent net80211 locking to be fixed one day. */ + nt = &ic->ic_sta; + islocked = IEEE80211_NODE_IS_LOCKED(nt); + if (islocked) + IEEE80211_NODE_UNLOCK(nt); + + wiphy_lock(hw->wiphy); + kc = lsta->kc[k->wk_keyix]; + /* Re-check under lock. */ + if (kc == NULL) { +#ifdef LINUXKPI_DEBUG_80211 + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(ic, "%s: sta %6D and key information vanished, " + "returning success\n", __func__, sta->addr, ":"); +#endif + error = 1; + goto out; + } + + error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kc); + if (error != 0) { + ic_printf(ic, "%s: set_key cmd %d(%s) for sta %6D failed: %d\n", + __func__, DISABLE_KEY, "DISABLE", sta->addr, ":", error); + error = 0; + goto out; + } + +#ifdef LINUXKPI_DEBUG_80211 + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(ic, "%s: set_key cmd %d(%s) for sta %6D succeeded: " + "keyidx %u hw_key_idx %u flags %#10x\n", __func__, + DISABLE_KEY, "DISABLE", sta->addr, ":", + kc->keyidx, kc->hw_key_idx, kc->flags); +#endif + lsta->kc[k->wk_keyix] = NULL; + free(kc, M_LKPI80211); + error = 1; +out: + wiphy_unlock(hw->wiphy); + if (islocked) + IEEE80211_NODE_LOCK(nt); + ieee80211_free_node(ni); + return (error); +} + +static int +lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + + /* XXX-BZ one day we should replace this iterating over VIFs, or node list? */ + /* See also lkpi_sta_del_keys() these days. */ + return (_lkpi_iv_key_delete(vap, k)); +} + +static int +_lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + struct ieee80211com *ic; + struct lkpi_hw *lhw; + struct ieee80211_hw *hw; + struct lkpi_vif *lvif; + struct lkpi_sta *lsta; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ieee80211_node *ni; + struct ieee80211_key_conf *kc; + uint32_t lcipher; + int error; ic = vap->iv_ic; lhw = ic->ic_softc; @@ -926,10 +1094,50 @@ _lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, lvif = VAP_TO_LVIF(vap); vif = LVIF_TO_VIF(lvif); - memset(&kc, 0, sizeof(kc)); - kc = malloc(sizeof(*kc) + k->wk_keylen, M_LKPI80211, M_WAITOK | M_ZERO); - kc->cipher = lkpi_net80211_to_l80211_cipher_suite( + if (vap->iv_bss == NULL) { + ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n", + __func__, vap->iv_bss, vap); + return (0); + } + ni = ieee80211_ref_node(vap->iv_bss); + lsta = ni->ni_drv_data; + if (lsta == NULL) { + ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n", + __func__, ni, ni->ni_bssid, ":"); + ieee80211_free_node(ni); + return (0); + } + sta = LSTA_TO_STA(lsta); + + wiphy_lock(hw->wiphy); + 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 */ + } + + 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: + default: + ic_printf(ic, "%s: CIPHER SUITE %#x not supported\n", __func__, lcipher); + IMPROVE(); + wiphy_unlock(hw->wiphy); + ieee80211_free_node(ni); + return (0); + } + + kc = malloc(sizeof(*kc) + k->wk_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 kc->hw_key_idx = /* set by hw and needs to be passed for TX */; @@ -938,6 +1146,11 @@ _lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, kc->keylen = k->wk_keylen; memcpy(kc->key, k->wk_key, k->wk_keylen); + if (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)) + kc->flags |= IEEE80211_KEY_FLAG_PAIRWISE; + if (k->wk_flags & IEEE80211_KEY_GROUP) + kc->flags &= ~IEEE80211_KEY_FLAG_PAIRWISE; + switch (kc->cipher) { case WLAN_CIPHER_SUITE_CCMP: kc->iv_len = k->wk_cipher->ic_header; @@ -945,44 +1158,41 @@ _lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, break; case WLAN_CIPHER_SUITE_TKIP: default: + /* currently UNREACH */ IMPROVE(); - return (0); + break; }; + lsta->kc[k->wk_keyix] = kc; - ni = vap->iv_bss; - sta = ieee80211_find_sta(vif, ni->ni_bssid); - if (sta != NULL) { - struct lkpi_sta *lsta; - - lsta = STA_TO_LSTA(sta); - lsta->kc = kc; - } - - error = lkpi_80211_mo_set_key(hw, cmd, vif, sta, kc); + error = lkpi_80211_mo_set_key(hw, SET_KEY, vif, sta, kc); if (error != 0) { - /* XXX-BZ leaking kc currently */ - ic_printf(ic, "%s: set_key failed: %d\n", __func__, error); + ic_printf(ic, "%s: set_key cmd %d(%s) for sta %6D failed: %d\n", + __func__, SET_KEY, "SET", sta->addr, ":", error); + lsta->kc[k->wk_keyix] = NULL; + free(kc, M_LKPI80211); + wiphy_unlock(hw->wiphy); + ieee80211_free_node(ni); return (0); - } else { - ic_printf(ic, "%s: set_key succeeded: keyidx %u hw_key_idx %u " - "flags %#10x\n", __func__, - kc->keyidx, kc->hw_key_idx, kc->flags); - return (1); } -} -static int -lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) -{ +#ifdef LINUXKPI_DEBUG_80211 + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(ic, "%s: set_key cmd %d(%s) for sta %6D succeeded: " + "kc %p keyidx %u hw_key_idx %u flags %#010x\n", __func__, + SET_KEY, "SET", sta->addr, ":", + kc, kc->keyidx, kc->hw_key_idx, kc->flags); +#endif - /* XXX-BZ one day we should replace this iterating over VIFs, or node list? */ - return (_lkpi_iv_key_set_delete(vap, k, DISABLE_KEY)); + wiphy_unlock(hw->wiphy); + ieee80211_free_node(ni); + return (1); } + static int lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) { - return (_lkpi_iv_key_set_delete(vap, k, SET_KEY)); + return (_lkpi_iv_key_set(vap, k)); } #endif @@ -2425,6 +2635,24 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int lkpi_lsta_dump(lsta, ni, __func__, __LINE__); +#ifdef LKPI_80211_HW_CRYPTO + if (lkpi_hwcrypto) { + wiphy_lock(hw->wiphy); + error = lkpi_sta_del_keys(hw, vif, lsta); + wiphy_unlock(hw->wiphy); + if (error != 0) { + ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys " + "failed: %d\n", __func__, __LINE__, error); + /* + * Either drv/fw will crash or cleanup itself, + * otherwise net80211 will delete the keys (at a + * less appropriate time). + */ + /* goto out; */ + } + } +#endif + /* Update sta_state (ASSOC to AUTH). */ KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not " @@ -2563,6 +2791,24 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int lkpi_lsta_dump(lsta, ni, __func__, __LINE__); +#ifdef LKPI_80211_HW_CRYPTO + if (lkpi_hwcrypto) { + wiphy_lock(hw->wiphy); + error = lkpi_sta_del_keys(hw, vif, lsta); + wiphy_unlock(hw->wiphy); + if (error != 0) { + ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys " + "failed: %d\n", __func__, __LINE__, error); + /* + * Either drv/fw will crash or cleanup itself, + * otherwise net80211 will delete the keys (at a + * less appropriate time). + */ + /* goto out; */ + } + } +#endif + /* Update sta_state (ASSOC to AUTH). */ KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not " @@ -3143,13 +3389,13 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], lvif->iv_update_bss = vap->iv_update_bss; vap->iv_update_bss = lkpi_iv_update_bss; - /* Key management. */ - if (lhw->ops->set_key != NULL) { #ifdef LKPI_80211_HW_CRYPTO + /* Key management. */ + if (lkpi_hwcrypto && lhw->ops->set_key != NULL) { vap->iv_key_set = lkpi_iv_key_set; vap->iv_key_delete = lkpi_iv_key_delete; -#endif } +#endif #ifdef LKPI_80211_HT /* Stay with the iv_ampdu_rxmax,limit / iv_ampdu_density defaults until later. */ @@ -3161,6 +3407,15 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status, mac); +#ifdef LKPI_80211_HT + /* + * Modern chipset/fw/drv will do A-MPDU in drv/fw and fail + * to do so if they cannot do the crypto too. + */ + if (!lkpi_hwcrypto && ieee80211_hw_check(hw, AMPDU_AGGREGATION)) + vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX; +#endif + if (hw->max_listen_interval == 0) hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval); hw->conf.listen_interval = hw->max_listen_interval; @@ -3991,13 +4246,74 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, return (0); } +#ifdef LKPI_80211_HW_CRYPTO +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; + struct ieee80211_hdr *hdr; + uint32_t hlen, hdrlen; + uint8_t *p; + + 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); + } + + + IMPROVE("the following should be WLAN_CIPHER_SUITE specific"); + /* We currently only support CCMP so we hardcode things here. */ + + hdr = (void *)skb->data; + + /* + * 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 && + /* MFP */ + !((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) != 0 && + ieee80211_is_mgmt(hdr->frame_control))) + return (0); + + hlen = k->wk_cipher->ic_header; + if (skb_headroom(skb) < hlen) + return (ENOSPC); + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + p = skb_push(skb, hlen); + memmove(p, p + hlen, hdrlen); + + /* 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); + + return (0); +} +#endif + static void lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) { struct ieee80211_node *ni; -#ifndef LKPI_80211_HW_CRYPTO struct ieee80211_frame *wh; -#endif struct ieee80211_key *k; struct sk_buff *skb; struct ieee80211com *ic; @@ -4012,6 +4328,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) struct ieee80211_hdr *hdr; struct lkpi_txq *ltxq; void *buf; + ieee80211_keyix keyix; uint8_t ac, tid; M_ASSERTPKTHDR(m); @@ -4022,20 +4339,30 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) ni = lsta->ni; k = NULL; -#ifndef LKPI_80211_HW_CRYPTO - /* Encrypt the frame if need be; XXX-BZ info->control.hw_key. */ + keyix = IEEE80211_KEYIX_NONE; wh = mtod(m, struct ieee80211_frame *); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - /* Retrieve key for TX && do software encryption. */ - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) { - ieee80211_free_node(ni); - m_freem(m); - return; + +#ifdef LKPI_80211_HW_CRYPTO + if (lkpi_hwcrypto) { + k = ieee80211_crypto_get_txkey(ni, m); + if (k != NULL && lsta->kc[k->wk_keyix] != NULL) + keyix = k->wk_keyix; } - } #endif + /* Encrypt the frame if need be. */ + if (keyix == IEEE80211_KEYIX_NONE) { + /* Retrieve key for TX && do software encryption. */ + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + ieee80211_free_node(ni); + m_freem(m); + return; + } + } + } + ic = ni->ni_ic; lhw = ic->ic_softc; hw = LHW_TO_HW(lhw); @@ -4146,7 +4473,19 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) sta = LSTA_TO_STA(lsta); #ifdef LKPI_80211_HW_CRYPTO - info->control.hw_key = lsta->kc; + if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE) { + int error; + + error = lkpi_hw_crypto_prepare(lsta, k, skb); + if (error != 0) { + /* + * We only have to free the skb which will free the + * mbuf and release the reference on the ni. + */ + dev_kfree_skb(skb); + return; + } + } #endif IMPROVE(); @@ -5107,7 +5446,7 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) ic->ic_cryptocaps = 0; #ifdef LKPI_80211_HW_CRYPTO - if (hw->wiphy->n_cipher_suites > 0) { + if (lkpi_hwcrypto && hw->wiphy->n_cipher_suites > 0) { for (i = 0; i < hw->wiphy->n_cipher_suites; i++) ic->ic_cryptocaps |= lkpi_l80211_to_net80211_cyphers( hw->wiphy->cipher_suites[i]); @@ -5346,15 +5685,62 @@ linuxkpi_ieee80211_iterate_interfaces(struct ieee80211_hw *hw, LKPI_80211_LHW_LVIF_UNLOCK(lhw); } +static void +lkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + ieee80211_keyix keyix, struct lkpi_sta *lsta, + void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, + struct ieee80211_sta *, struct ieee80211_key_conf *, void *), + void *arg) +{ + if (!lsta->added_to_drv) + return; + + if (lsta->kc[keyix] == NULL) + return; + + iterfunc(hw, vif, LSTA_TO_STA(lsta), lsta->kc[keyix], arg); +} + void linuxkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct ieee80211_key_conf *, void *), - void *arg) + void *arg, bool rcu) { + struct lkpi_sta *lsta; + struct lkpi_vif *lvif; - UNIMPLEMENTED; + lvif = VIF_TO_LVIF(vif); + + if (rcu) { + if (vif == NULL) { + TODO(); + } else { + IMPROVE("We do not actually match the RCU code"); + TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) { + for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc); + keyix++) + lkpi_ieee80211_iterate_keys(hw, vif, + keyix, lsta, iterfunc, arg); + } + } + } else { + TODO("Used by suspend/resume; order of keys as installed to " + "firmware is important; we'll need to rewrite some code for that"); + lockdep_assert_wiphy(hw->wiphy); + + if (vif == NULL) { + TODO(); + } else { + TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) { + for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc); + keyix++) + lkpi_ieee80211_iterate_keys(hw, vif, + keyix, lsta, iterfunc, arg); + } + } + } } void diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index bb1ecb45636f..40b11ebfef13 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -67,6 +67,7 @@ #define D80211_TRACEX (D80211_TRACE_TX|D80211_TRACE_RX) #define D80211_TRACEX_DUMP (D80211_TRACE_TX_DUMP|D80211_TRACE_RX_DUMP) #define D80211_TRACE_STA 0x00010000 +#define D80211_TRACE_HW_CRYPTO 0x00020000 #define D80211_TRACE_MO 0x00100000 #define D80211_TRACE_MODE 0x0f000000 #define D80211_TRACE_MODE_HT 0x01000000 @@ -151,7 +152,7 @@ struct lkpi_sta { struct mbufq txq; struct mtx txq_mtx; - struct ieee80211_key_conf *kc; + struct ieee80211_key_conf *kc[IEEE80211_WEP_NKID]; enum ieee80211_sta_state state; bool txq_ready; /* Can we run the taskq? */ bool added_to_drv; /* Driver knows; i.e. we called ...(). */ diff --git a/sys/compat/linuxkpi/common/src/linux_80211_macops.c b/sys/compat/linuxkpi/common/src/linux_80211_macops.c index 7440d1d3c26c..1da3c582adb4 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211_macops.c +++ b/sys/compat/linuxkpi/common/src/linux_80211_macops.c @@ -684,6 +684,8 @@ lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct lkpi_hw *lhw; int error; + lockdep_assert_wiphy(hw->wiphy); + lhw = HW_TO_LHW(hw); if (lhw->ops->set_key == NULL) { error = EOPNOTSUPP;