wifi: mt76: mt7996: fix MLO set key and group key issues

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: 0c45d52276 ("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>
This commit is contained in:
Shayne Chen
2025-11-06 14:42:01 +08:00
committed by Felix Fietkau
parent 4fb3b4e7d1
commit e11be918d9
4 changed files with 34 additions and 15 deletions

View File

@@ -795,6 +795,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;
@@ -820,7 +821,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);
}

View 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);

View File

@@ -2530,7 +2530,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)
@@ -2542,7 +2542,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);
@@ -2582,29 +2585,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;
@@ -2724,12 +2731,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);
@@ -2804,7 +2817,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);

View File

@@ -849,7 +849,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,