]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7996: fix MLO set key and group key issues
authorShayne Chen <shayne.chen@mediatek.com>
Thu, 6 Nov 2025 06:42:01 +0000 (14:42 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Dec 2025 13:03:14 +0000 (14:03 +0100)
[ Upstream commit e11be918d91e7d33ac4bad41dbe666a9abf1cfaa ]

This patch fixes the following key issues:
- Pass correct link BSS to mt7996_mcu_add_key(), and use HW beacon
  protection mode for mt7990 chipset
- Do not do group key deletion for GTK and IGTK due to FW design, the
  delete key command will delete all group keys of a link BSS
- For deleting BIGTK, FW adds a new flow, but the "sec->add" field
  should be filled with "SET_KEY". Note that if BIGTK is not deleted, it
  will cause beacon decryption issue when switching from an AP interface
  to a station interface

Fixes: 0c45d52276fd ("wifi: mt76: mt7996: fix setting beacon protection keys")
Co-developed-by: Allen Ye <allen.ye@mediatek.com>
Signed-off-by: Allen Ye <allen.ye@mediatek.com>
Co-developed-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Link: https://patch.msgid.link/20251106064203.1000505-10-shayne.chen@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/mediatek/mt76/mt7996/mac.c
drivers/net/wireless/mediatek/mt76/mt7996/main.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h

index 284f2eea71e5bf0a34c7fe84084d998164a31a05..fe31db5440a844a6046d87761dcbf0d97ed1fe0c 100644 (file)
@@ -794,6 +794,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
        u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
        __le16 fc = hdr->frame_control, sc = hdr->seq_ctrl;
        u16 seqno = le16_to_cpu(sc);
+       bool hw_bigtk = false;
        u8 fc_type, fc_stype;
        u32 val;
 
@@ -819,7 +820,11 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
            info->flags & IEEE80211_TX_CTL_USE_MINRATE)
                val |= MT_TXD1_FIXED_RATE;
 
-       if (key && multicast && ieee80211_is_robust_mgmt_frame(skb)) {
+       if (is_mt7990(&dev->mt76) && ieee80211_is_beacon(fc) &&
+           (wcid->hw_key_idx2 == 6 || wcid->hw_key_idx2 == 7))
+               hw_bigtk = true;
+
+       if ((key && multicast && ieee80211_is_robust_mgmt_frame(skb)) || hw_bigtk) {
                val |= MT_TXD1_BIP;
                txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
        }
index dc0fcf5cb7fb1b36e8d3193787dced851782cb9c..beb455185f90434a4e5de6459fddeeb478e8fa52 100644 (file)
@@ -249,12 +249,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        else if (idx == *wcid_keyidx)
                *wcid_keyidx = -1;
 
-       if (cmd != SET_KEY && sta)
+       /* only do remove key for BIGTK */
+       if (cmd != SET_KEY && !is_bigtk)
                return 0;
 
        mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key);
 
-       err = mt7996_mcu_add_key(&dev->mt76, vif, key,
+       err = mt7996_mcu_add_key(&dev->mt76, link, key,
                                 MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
                                 &msta_link->wcid, cmd);
 
index 21be88e76c655304b6312f4a82634da6369be3f6..5bde9959bbb99d25f19b388bd49284324009144e 100644 (file)
@@ -2527,7 +2527,7 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
 }
 
 static int
-mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
+mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid,
                       struct sk_buff *skb,
                       struct ieee80211_key_conf *key,
                       enum set_key_cmd cmd)
@@ -2539,7 +2539,10 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
 
        tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));
        sec = (struct sta_rec_sec_uni *)tlv;
-       sec->add = 0;
+       /* due to connac3 FW design, we only do remove key for BIGTK; even for
+        * removal, the field should be filled with SET_KEY
+        */
+       sec->add = SET_KEY;
        sec->n_cipher = 1;
        sec_key = &sec->key[0];
        sec_key->wlan_idx = cpu_to_le16(wcid->idx);
@@ -2579,29 +2582,33 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
                sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256;
                break;
+       case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+               if (!is_mt7990(dev))
+                       return -EOPNOTSUPP;
+               sec_key->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_256;
+               break;
        default:
                return -EOPNOTSUPP;
        }
 
-       sec_key->bcn_mode = BP_SW_MODE;
+       sec_key->bcn_mode = is_mt7990(dev) ? BP_HW_MODE : BP_SW_MODE;
 
        return 0;
 }
 
-int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
+int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_vif_link *link,
                       struct ieee80211_key_conf *key, int mcu_cmd,
                       struct mt76_wcid *wcid, enum set_key_cmd cmd)
 {
-       struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv;
        struct sk_buff *skb;
        int ret;
 
-       skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
-                                             MT7996_STA_UPDATE_MAX_SIZE);
+       skb = __mt76_connac_mcu_alloc_sta_req(dev, (struct mt76_vif_link *)link,
+                                             wcid, MT7996_STA_UPDATE_MAX_SIZE);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
 
-       ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd);
+       ret = mt7996_mcu_sta_key_tlv(dev, wcid, skb, key, cmd);
        if (ret) {
                dev_kfree_skb(skb);
                return ret;
@@ -2721,12 +2728,18 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
 static void
 mt7996_mcu_beacon_cont(struct mt7996_dev *dev,
                       struct ieee80211_bss_conf *link_conf,
+                      struct mt7996_vif_link *link,
                       struct sk_buff *rskb, struct sk_buff *skb,
                       struct bss_bcn_content_tlv *bcn,
                       struct ieee80211_mutable_offsets *offs)
 {
-       struct mt76_wcid *wcid = &dev->mt76.global_wcid;
-       u8 *buf;
+       u8 *buf, keyidx = link->msta_link.wcid.hw_key_idx2;
+       struct mt76_wcid *wcid;
+
+       if (is_mt7990(&dev->mt76) && (keyidx == 6 || keyidx == 7))
+               wcid = &link->msta_link.wcid;
+       else
+               wcid = &dev->mt76.global_wcid;
 
        bcn->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
        bcn->tim_ie_pos = cpu_to_le16(offs->tim_offset);
@@ -2801,7 +2814,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        info = IEEE80211_SKB_CB(skb);
        info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mlink->band_idx);
 
-       mt7996_mcu_beacon_cont(dev, link_conf, rskb, skb, bcn, &offs);
+       mt7996_mcu_beacon_cont(dev, link_conf, link, rskb, skb, bcn, &offs);
        if (link_conf->bssid_indicator)
                mt7996_mcu_beacon_mbss(rskb, skb, bcn, &offs);
        mt7996_mcu_beacon_cntdwn(rskb, skb, &offs, link_conf->csa_active);
index 1727e73a99ce69e85a2daeff7311833cdc034c35..b942928c79e280833da72a89e8dcb1fb5a844d2d 100644 (file)
@@ -848,7 +848,7 @@ void mt7996_update_channel(struct mt76_phy *mphy);
 int mt7996_init_debugfs(struct mt7996_dev *dev);
 void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len);
 bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len);
-int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
+int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_vif_link *link,
                       struct ieee80211_key_conf *key, int mcu_cmd,
                       struct mt76_wcid *wcid, enum set_key_cmd cmd);
 int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,