From: Sean Wang <sean.wang@kernel.org>
To: nbd@nbd.name
Cc: linux-wireless@vger.kernel.org,
linux-mediatek@lists.infradead.org, yu-ching.liu@mediatek.com,
jenhao.yang@mediatek.com, posh.sun@mediatek.com,
Chengwei Yu <chengwei.yu@mediatek.com>,
Sean Wang <sean.wang@mediatek.com>
Subject: [PATCH 09/23] wifi: mt76: mt7925: implement mt7925_nan_set_key for NAN security
Date: Sun, 27 Sep 2026 16:02:51 -0500 [thread overview]
Message-ID: <20260927210306.737669-10-sean.wang@kernel.org> (raw)
In-Reply-To: <20260927210306.737669-1-sean.wang@kernel.org>
From: Chengwei Yu <chengwei.yu@mediatek.com>
Wire up NAN/NAN_DATA group key installation on top of the MCU command
and per-peer WTBLs from prior commits:
- NAN RX IGTK/BIGTK (keyidx 4-7, sta != NULL): lazy WTBL alloc via
nan_rx_igtk_wcid; installed as NAN_KEY_TYPE_MC_MGMT_RX_KEY.
- NAN_DATA RX GTK (keyidx 1-2, sta != NULL): lazy WTBL alloc via
nan_rx_gtk_wcid; installed as NAN_KEY_TYPE_MC_RX_KEY.
- NAN_DATA TX GTK: -EOPNOTSUPP; NDC ID unavailable at set_key time,
keeping mac80211 in SW crypto until NDC-aware support lands.
mt7925_set_key() routes NAN/NAN_DATA vifs through mt7925_nan_set_key()
and blocks NAN_DATA group keys from reaching set_link_key, preventing
silent HW-offload of the unsupported TX GTK path.
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Chengwei Yu <chengwei.yu@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 27 +++
.../net/wireless/mediatek/mt76/mt7925/nan.c | 154 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7925/nan.h | 16 ++
.../net/wireless/mediatek/mt76/mt792x_core.c | 7 +
4 files changed, 204 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 1b253989f43b..6c603d57e89f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -765,6 +765,33 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt792x_link_sta *mlink;
int err;
+ /* Route NAN/NAN_DATA keys.
+ *
+ * mt7925_nan_set_key() owns every key that needs a dedicated WTBL and
+ * returns -EOPNOTSUPP to signal "not mine, use the normal HW path".
+ * Three cases legitimately reach the normal path:
+ *
+ * NAN + pairwise (NM-TK): set_link_key via NMI peer WTBL
+ * NAN_DATA + pairwise (ND-TK): set_link_key via NDI peer WTBL
+ * NAN + group (TX IGTK/BIGTK): set_link_key via NAN iface WTBL
+ *
+ * NAN_DATA TX GTK is the one group key on NAN_DATA that nan_set_key
+ * also declines (-EOPNOTSUPP) because NDC ID is unavailable at set_key
+ * time. It must NOT reach set_link_key: that function would succeed
+ * and silently install the key on the interface WTBL, causing mac80211
+ * to mark it as HW-offloaded and skip SW crypto. Return -EOPNOTSUPP
+ * so mac80211 uses SW encryption until TX GTK support is complete.
+ */
+ if (vif->type == NL80211_IFTYPE_NAN || vif->type == NL80211_IFTYPE_NAN_DATA) {
+ err = mt7925_nan_set_key(hw, cmd, vif, sta, key);
+ if (err != -EOPNOTSUPP)
+ return err;
+ /* Block NAN_DATA group keys from reaching set_link_key. */
+ if (vif->type == NL80211_IFTYPE_NAN_DATA &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EOPNOTSUPP;
+ }
+
/* The hardware does not support per-STA RX GTK, fallback
* to software mode for these.
*/
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
index 0579501207eb..e1dfcdc88382 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c
@@ -1581,3 +1581,157 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
return ret ?: -ENOMEM;
}
+
+/* Allocate a WTBL slot for a lazily-created per-peer NAN group key wcid.
+ * Mirrors mt76_wcid_alloc/init but wires the slot into the RCU wcid table and
+ * clears the hardware admission counter, matching what mt7925_mac_link_sta_add
+ * does for every normal per-link wcid. Caller must hold dev->mt76.mutex; RCU
+ * publish is the final step so readers always see a fully initialised wcid.
+ */
+int mt7925_nan_wcid_alloc(struct mt792x_dev *dev, struct mt76_wcid *wcid)
+{
+ int idx;
+
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
+ if (idx < 0)
+ return -ENOSPC;
+
+ wcid->idx = idx;
+ wcid->tx_info |= MT_WCID_TX_INFO_SET;
+ mt76_wcid_init(wcid, 0);
+ mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+ rcu_assign_pointer(dev->mt76.wcid[idx], wcid);
+
+ return 0;
+}
+
+/* NAN RX IGTK/BIGTK (keyidx 4-7, sta != NULL): lock first, then lazy alloc. */
+static int mt7925_nan_set_rx_igtk(struct mt792x_dev *dev,
+ const u8 *local_addr, const u8 *peer_addr,
+ struct mt792x_sta *msta,
+ enum set_key_cmd cmd,
+ struct ieee80211_key_conf *key)
+{
+ enum mt7925_nan_key_operation key_op;
+ u16 wtbl_idx;
+ int err;
+
+ mt792x_mutex_acquire(dev);
+
+ /* Lazy allocation of per-peer RX IGTK/BIGTK WTBL: mt76_wcid_alloc()
+ * touches the shared wcid mask and mt7925_mac_wtbl_update() writes
+ * hardware registers, so both need dev->mt76.mutex and a woken chip.
+ */
+ if (msta->nan_rx_igtk_wcid.idx == MT792x_WCID_IDX_UNSET) {
+ if (cmd != SET_KEY) {
+ mt792x_mutex_release(dev);
+ return 0;
+ }
+ err = mt7925_nan_wcid_alloc(dev, &msta->nan_rx_igtk_wcid);
+ if (err) {
+ mt792x_mutex_release(dev);
+ return err;
+ }
+ }
+
+ key_op = (cmd == SET_KEY) ? NAN_KEY_OP_SET_KEY : NAN_KEY_OP_CLS_KEY;
+ wtbl_idx = msta->nan_rx_igtk_wcid.idx;
+
+ err = mt7925_nan_manage_key_cmd(dev, key_op, NAN_KEY_TYPE_MC_MGMT_RX_KEY,
+ wtbl_idx, local_addr, peer_addr,
+ &(struct mt7925_nan_key_info){
+ .algo_id = mt7925_mcu_get_cipher(key->cipher),
+ .key_id = key->keyidx,
+ .key_len = key->keylen,
+ .key_data = key->key,
+ });
+ mt792x_mutex_release(dev);
+ return err;
+}
+
+/* NAN_DATA GTK (keyidx 1-2): lock first, then lazy alloc for RX; TX unsupported. */
+static int mt7925_nan_set_data_gtk(struct mt792x_dev *dev,
+ struct ieee80211_sta *sta,
+ struct mt792x_sta *msta,
+ enum set_key_cmd cmd,
+ struct ieee80211_key_conf *key)
+{
+ static const u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ enum mt7925_nan_key_operation key_op;
+ enum mt7925_nan_key_type key_type;
+ u8 *peer_addr, *local_addr;
+ u16 wtbl_idx;
+ int err;
+
+ mt792x_mutex_acquire(dev);
+
+ key_op = (cmd == SET_KEY) ? NAN_KEY_OP_SET_KEY : NAN_KEY_OP_CLS_KEY;
+
+ if (sta) {
+ /* RX GTK: per-peer dedicated WTBL */
+ peer_addr = sta->addr;
+ local_addr = (u8 *)bcast_addr;
+ key_type = NAN_KEY_TYPE_MC_RX_KEY;
+
+ /* Lazy allocation of per-peer RX GTK WTBL */
+ if (msta->nan_rx_gtk_wcid.idx == MT792x_WCID_IDX_UNSET) {
+ if (key_op != NAN_KEY_OP_SET_KEY) {
+ mt792x_mutex_release(dev);
+ return 0;
+ }
+ err = mt7925_nan_wcid_alloc(dev, &msta->nan_rx_gtk_wcid);
+ if (err) {
+ mt792x_mutex_release(dev);
+ return err;
+ }
+ }
+
+ wtbl_idx = msta->nan_rx_gtk_wcid.idx;
+ } else {
+ /* TX GTK: not supported yet; NDC ID is unavailable at set_key
+ * time so the correct TX GTK table entry cannot be selected.
+ */
+ dev_warn(dev->mt76.dev,
+ "nan: TX GTK not supported (missing NDC ID)\n");
+ mt792x_mutex_release(dev);
+ return -EOPNOTSUPP;
+ }
+
+ err = mt7925_nan_manage_key_cmd(dev, key_op, key_type, wtbl_idx,
+ local_addr, peer_addr,
+ &(struct mt7925_nan_key_info){
+ .algo_id = mt7925_mcu_get_cipher(key->cipher),
+ .key_id = key->keyidx,
+ .key_len = key->keylen,
+ .key_data = key->key,
+ });
+ mt792x_mutex_release(dev);
+ return err;
+}
+
+int mt7925_nan_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta;
+
+ /* NAN RX IGTK/BIGTK (keyidx 4-7, sta != NULL) */
+ if (vif->type == NL80211_IFTYPE_NAN && sta &&
+ key->keyidx >= NAN_KEY_IDX_MGMT_INTEG_MIN &&
+ key->keyidx <= NAN_KEY_IDX_MGMT_INTEG_MAX)
+ return mt7925_nan_set_rx_igtk(dev, vif->addr, sta->addr, msta,
+ cmd, key);
+
+ /* NAN_DATA GTK (keyidx 1-2) */
+ if (vif->type == NL80211_IFTYPE_NAN_DATA &&
+ key->keyidx >= NAN_KEY_IDX_GTK_MIN &&
+ key->keyidx <= NAN_KEY_IDX_GTK_MAX)
+ return mt7925_nan_set_data_gtk(dev, sta, msta, cmd, key);
+
+ /* Unicast keys (NM-TK, ND-TK) and NAN TX IGTK/BIGTK use the normal
+ * hardware path via set_link_key.
+ */
+ return -EOPNOTSUPP;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
index f15a16b773bb..9a47940f5d61 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h
@@ -127,6 +127,16 @@ enum mt7925_nan_key_type {
#define WTBL_RESERVED_ENTRY 0xFFFF
#define NAN_PACKET_NUMBER_LEN 6
+/* NAN key index ranges from the Wi-Fi NAN spec. mac80211 passes keyidx
+ * straight from wpa_supplicant without interpretation, so the driver must
+ * define these boundaries itself -- no kernel-wide equivalent exists.
+ * Wi-Fi NAN spec 7.1.3.2 (GTKSA), 7.1.3.3 (IGTKSA), 7.1.3.4 (BIGTKSA).
+ */
+#define NAN_KEY_IDX_GTK_MIN 1 /* GTKSA: key ID 1-2 */
+#define NAN_KEY_IDX_GTK_MAX 2
+#define NAN_KEY_IDX_MGMT_INTEG_MIN 4 /* IGTKSA (4-5) + BIGTKSA (6-7) */
+#define NAN_KEY_IDX_MGMT_INTEG_MAX 7
+
/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic
* MCU-event RX path and consumed by mt7925_nan_deferred_work()
*/
@@ -600,6 +610,12 @@ int mt7925_nan_manage_key_cmd(struct mt792x_dev *dev,
const u8 *peer_addr,
const struct mt7925_nan_key_info *key);
+int mt7925_nan_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
+
+int mt7925_nan_wcid_alloc(struct mt792x_dev *dev, struct mt76_wcid *wcid);
+
void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
index c8e42447f43a..94bd0e3fe2e3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -824,6 +824,13 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
wiphy->nan_capa.max_channel_switch_time = 12;
wiphy->nan_capa.dev_capabilities = NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SECURE_NAN);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT);
+ /* Per-peer group key WTBL needed for NAN RX IGTK/BIGTK delivery:
+ * ieee80211_key_enable_hw_accel() drops per-STA group keys unless
+ * this flag is set or the vif is NAN_DATA.
+ */
+ ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK);
}
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
--
2.43.0
next prev parent reply other threads:[~2026-09-27 21:09 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 21:02 [PATCH 00/23] wifi: mt76: mt7925: add NAN security and improve NDP reliability (part 2) Sean Wang
2026-09-27 21:02 ` [PATCH 01/23] wifi: mt76: mt7925: make NMI address TLV tail padding explicit Sean Wang
2026-09-27 21:02 ` [PATCH 02/23] wifi: mt76: mt7925: add NMI/NDI MAC address setter helpers Sean Wang
2026-10-06 9:25 ` Felix Fietkau
2026-09-27 21:02 ` [PATCH 03/23] wifi: mt76: mt7925: implement NAN MAC address randomization Sean Wang
2026-10-06 9:18 ` Felix Fietkau
2026-09-27 21:02 ` [PATCH 04/23] wifi: mt76: mt7925: wire up NAN MAC randomization lifecycle Sean Wang
2026-09-27 21:02 ` [PATCH 05/23] wifi: mt76: mt7925: add NAN low power event control on suspend/resume Sean Wang
2026-09-27 21:02 ` [PATCH 06/23] wifi: mt76: mt7925: implement NAN key management MCU command Sean Wang
2026-09-27 21:02 ` [PATCH 07/23] wifi: mt76: mt7925: add per-peer RX IGTK/BIGTK and RX GTK WTBLs Sean Wang
2026-09-27 21:02 ` [PATCH 08/23] wifi: mt76: mt7925: add NDC-aware TX GTK table for NAN_DATA Sean Wang
2026-10-06 9:20 ` Felix Fietkau
2026-09-27 21:02 ` Sean Wang [this message]
2026-09-27 21:02 ` [PATCH 10/23] wifi: mt76: mt7925: install NAN BIP keys standalone in sta_key_tlv Sean Wang
2026-09-27 21:02 ` [PATCH 11/23] wifi: mt76: mt7925: do not disable RX NAPI twice on unload Sean Wang
2026-09-27 21:02 ` [PATCH 12/23] wifi: mt76: mt7925: assign the interface WTBL to the NAN management TXQ Sean Wang
2026-09-27 21:02 ` [PATCH 13/23] wifi: mt76: mt7925: do not deactivate shared NAN BSS on peer STA removal Sean Wang
2026-09-27 21:02 ` [PATCH 14/23] wifi: mt76: gate NAN unicast mgmt by peer availability via STA queues Sean Wang
2026-09-27 21:02 ` [PATCH 15/23] wifi: mt76: mt7925: hold NAN mgmt TX to the discovery window Sean Wang
2026-09-27 21:02 ` [PATCH 16/23] wifi: mt76: mt7925: double the retry budget for NAN unicast management Sean Wang
2026-09-27 21:02 ` [PATCH 17/23] wifi: mt76: mt7925: let TX status of DW-held NAN frames outlive the DW period Sean Wang
2026-09-27 21:03 ` [PATCH 18/23] wifi: mt76: mt7925: defer the NAN joined-cluster event out of NAN_START Sean Wang
2026-09-27 21:03 ` [PATCH 19/23] wifi: mt76: mt7925: steer NAN handshake frames by committed-bitmap state Sean Wang
2026-09-27 21:03 ` [PATCH 20/23] wifi: mt76: mt7925: disable only the RX NAPI instances that exist Sean Wang
2026-09-27 21:03 ` [PATCH 21/23] wifi: mt76: mt7925: stop queueing resets once the device is being removed Sean Wang
2026-09-27 21:03 ` [PATCH 22/23] wifi: mt76: mt7925: bound the lifetime of NAN unicast management frames Sean Wang
2026-09-27 21:03 ` [PATCH 23/23] wifi: mt76: mt7925: always deliver the joined-cluster event through the deferred work Sean Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260927210306.737669-10-sean.wang@kernel.org \
--to=sean.wang@kernel.org \
--cc=chengwei.yu@mediatek.com \
--cc=jenhao.yang@mediatek.com \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=nbd@nbd.name \
--cc=posh.sun@mediatek.com \
--cc=sean.wang@mediatek.com \
--cc=yu-ching.liu@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox