| From e5a46602e523e3221210dd01243b60025d931491 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 29 Dec 2023 11:09:33 +0800 |
| Subject: wifi: mt76: mt7925: fix WoW failed in encrypted mode |
| |
| From: Ming Yen Hsieh <mingyen.hsieh@mediatek.com> |
| |
| [ Upstream commit 47916693ec7cd1b283ffa7554fc48ff4eec2daa1 ] |
| |
| When in suspend mode, WoW (Wake-on-WLAN) fails to wake the system remotely |
| due to incorrect encryption mode settings. For the new mt7925 chipset, the |
| old STA_REC_KEY_V2 command will send incorrect parameters to the firmware. |
| Therefore, STA_REC_KEY_V3 has been introduced as a replacement for it. |
| |
| Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") |
| Signed-off-by: Ming Yen Hsieh <mingyen.hsieh@mediatek.com> |
| Signed-off-by: Felix Fietkau <nbd@nbd.name> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + |
| .../net/wireless/mediatek/mt76/mt7925/main.c | 3 +- |
| .../net/wireless/mediatek/mt76/mt7925/mcu.c | 86 ++++++++++--------- |
| .../net/wireless/mediatek/mt76/mt7925/mcu.h | 70 +++++++++++---- |
| 4 files changed, 103 insertions(+), 57 deletions(-) |
| |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h |
| index cc6cdbc664290..bf023f317031d 100644 |
| --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h |
| +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h |
| @@ -808,6 +808,7 @@ enum { |
| STA_REC_MLD = 0x20, |
| STA_REC_EHT = 0x22, |
| STA_REC_PN_INFO = 0x26, |
| + STA_REC_KEY_V3 = 0x27, |
| STA_REC_HDRT = 0x28, |
| STA_REC_HDR_TRANS = 0x2B, |
| STA_REC_MAX_NUM |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c |
| index b6aa792e5511f..09b53cec750b3 100644 |
| --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c |
| @@ -360,6 +360,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
| mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; |
| mvif->sta.wcid.hw_key_idx = -1; |
| mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; |
| + mvif->sta.vif = mvif; |
| mt76_wcid_init(&mvif->sta.wcid); |
| |
| mt7925_mac_wtbl_update(dev, idx, |
| @@ -527,7 +528,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
| if (cmd == SET_KEY && !mvif->mt76.cipher) { |
| struct mt792x_phy *phy = mt792x_hw_phy(hw); |
| |
| - mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); |
| + mvif->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); |
| mt7925_mcu_add_bss_info(phy, mvif->mt76.ctx, vif, sta, true); |
| } |
| |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c |
| index b21fe015a701b..bafd6ec72ef24 100644 |
| --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c |
| +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c |
| @@ -921,61 +921,67 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, |
| struct ieee80211_key_conf *key, |
| enum set_key_cmd cmd) |
| { |
| + struct mt792x_sta *msta = container_of(wcid, struct mt792x_sta, wcid); |
| struct sta_rec_sec_uni *sec; |
| + struct mt792x_vif *mvif = msta->vif; |
| + struct ieee80211_sta *sta; |
| + struct ieee80211_vif *vif; |
| struct tlv *tlv; |
| |
| - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); |
| + sta = msta == &mvif->sta ? |
| + NULL : |
| + container_of((void *)msta, struct ieee80211_sta, drv_priv); |
| + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); |
| + |
| + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); |
| sec = (struct sta_rec_sec_uni *)tlv; |
| - sec->add = cmd; |
| + sec->bss_idx = mvif->mt76.idx; |
| + sec->is_authenticator = 0; |
| + sec->mgmt_prot = 0; |
| + sec->wlan_idx = (u8)wcid->idx; |
| + |
| + if (sta) { |
| + sec->tx_key = 1; |
| + sec->key_type = 1; |
| + memcpy(sec->peer_addr, sta->addr, ETH_ALEN); |
| + } else { |
| + memcpy(sec->peer_addr, vif->bss_conf.bssid, ETH_ALEN); |
| + } |
| |
| if (cmd == SET_KEY) { |
| - struct sec_key_uni *sec_key; |
| u8 cipher; |
| |
| - cipher = mt76_connac_mcu_get_cipher(key->cipher); |
| - if (cipher == MCU_CIPHER_NONE) |
| + sec->add = 1; |
| + cipher = mt7925_mcu_get_cipher(key->cipher); |
| + if (cipher == CONNAC3_CIPHER_NONE) |
| return -EOPNOTSUPP; |
| |
| - sec_key = &sec->key[0]; |
| - sec_key->cipher_len = sizeof(*sec_key); |
| - |
| - if (cipher == MCU_CIPHER_BIP_CMAC_128) { |
| - sec_key->wlan_idx = cpu_to_le16(wcid->idx); |
| - sec_key->cipher_id = MCU_CIPHER_AES_CCMP; |
| - sec_key->key_id = sta_key_conf->keyidx; |
| - sec_key->key_len = 16; |
| - memcpy(sec_key->key, sta_key_conf->key, 16); |
| - |
| - sec_key = &sec->key[1]; |
| - sec_key->wlan_idx = cpu_to_le16(wcid->idx); |
| - sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; |
| - sec_key->cipher_len = sizeof(*sec_key); |
| - sec_key->key_len = 16; |
| - memcpy(sec_key->key, key->key, 16); |
| - sec->n_cipher = 2; |
| + if (cipher == CONNAC3_CIPHER_BIP_CMAC_128) { |
| + sec->cipher_id = CONNAC3_CIPHER_BIP_CMAC_128; |
| + sec->key_id = sta_key_conf->keyidx; |
| + sec->key_len = 32; |
| + memcpy(sec->key, sta_key_conf->key, 16); |
| + memcpy(sec->key + 16, key->key, 16); |
| } else { |
| - sec_key->wlan_idx = cpu_to_le16(wcid->idx); |
| - sec_key->cipher_id = cipher; |
| - sec_key->key_id = key->keyidx; |
| - sec_key->key_len = key->keylen; |
| - memcpy(sec_key->key, key->key, key->keylen); |
| + sec->cipher_id = cipher; |
| + sec->key_id = key->keyidx; |
| + sec->key_len = key->keylen; |
| + memcpy(sec->key, key->key, key->keylen); |
| |
| - if (cipher == MCU_CIPHER_TKIP) { |
| + if (cipher == CONNAC3_CIPHER_TKIP) { |
| /* Rx/Tx MIC keys are swapped */ |
| - memcpy(sec_key->key + 16, key->key + 24, 8); |
| - memcpy(sec_key->key + 24, key->key + 16, 8); |
| + memcpy(sec->key + 16, key->key + 24, 8); |
| + memcpy(sec->key + 24, key->key + 16, 8); |
| } |
| |
| /* store key_conf for BIP batch update */ |
| - if (cipher == MCU_CIPHER_AES_CCMP) { |
| + if (cipher == CONNAC3_CIPHER_AES_CCMP) { |
| memcpy(sta_key_conf->key, key->key, key->keylen); |
| sta_key_conf->keyidx = key->keyidx; |
| } |
| - |
| - sec->n_cipher = 1; |
| } |
| } else { |
| - sec->n_cipher = 0; |
| + sec->add = 0; |
| } |
| |
| return 0; |
| @@ -2122,21 +2128,21 @@ mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) |
| sec = (struct bss_sec_tlv *)tlv; |
| |
| switch (mvif->cipher) { |
| - case MCU_CIPHER_GCMP_256: |
| - case MCU_CIPHER_GCMP: |
| + case CONNAC3_CIPHER_GCMP_256: |
| + case CONNAC3_CIPHER_GCMP: |
| sec->mode = MODE_WPA3_SAE; |
| sec->status = 8; |
| break; |
| - case MCU_CIPHER_AES_CCMP: |
| + case CONNAC3_CIPHER_AES_CCMP: |
| sec->mode = MODE_WPA2_PSK; |
| sec->status = 6; |
| break; |
| - case MCU_CIPHER_TKIP: |
| + case CONNAC3_CIPHER_TKIP: |
| sec->mode = MODE_WPA2_PSK; |
| sec->status = 4; |
| break; |
| - case MCU_CIPHER_WEP104: |
| - case MCU_CIPHER_WEP40: |
| + case CONNAC3_CIPHER_WEP104: |
| + case CONNAC3_CIPHER_WEP40: |
| sec->mode = MODE_SHARED; |
| sec->status = 0; |
| break; |
| diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h |
| index 0218fd2a0eb01..9fce054e50657 100644 |
| --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h |
| +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h |
| @@ -159,6 +159,20 @@ enum { |
| UNI_EVENT_SCAN_DONE_NLO = 3, |
| }; |
| |
| +enum connac3_mcu_cipher_type { |
| + CONNAC3_CIPHER_NONE = 0, |
| + CONNAC3_CIPHER_WEP40 = 1, |
| + CONNAC3_CIPHER_TKIP = 2, |
| + CONNAC3_CIPHER_AES_CCMP = 4, |
| + CONNAC3_CIPHER_WEP104 = 5, |
| + CONNAC3_CIPHER_BIP_CMAC_128 = 6, |
| + CONNAC3_CIPHER_WEP128 = 7, |
| + CONNAC3_CIPHER_WAPI = 8, |
| + CONNAC3_CIPHER_CCMP_256 = 10, |
| + CONNAC3_CIPHER_GCMP = 11, |
| + CONNAC3_CIPHER_GCMP_256 = 12, |
| +}; |
| + |
| struct mt7925_mcu_scan_chinfo_event { |
| u8 nr_chan; |
| u8 alpha2[3]; |
| @@ -383,25 +397,22 @@ struct sta_rec_eht { |
| u8 _rsv2[3]; |
| } __packed; |
| |
| -struct sec_key_uni { |
| - __le16 wlan_idx; |
| - u8 mgmt_prot; |
| - u8 cipher_id; |
| - u8 cipher_len; |
| - u8 key_id; |
| - u8 key_len; |
| - u8 need_resp; |
| - u8 key[32]; |
| -} __packed; |
| - |
| struct sta_rec_sec_uni { |
| __le16 tag; |
| __le16 len; |
| u8 add; |
| - u8 n_cipher; |
| - u8 rsv[2]; |
| - |
| - struct sec_key_uni key[2]; |
| + u8 tx_key; |
| + u8 key_type; |
| + u8 is_authenticator; |
| + u8 peer_addr[6]; |
| + u8 bss_idx; |
| + u8 cipher_id; |
| + u8 key_id; |
| + u8 key_len; |
| + u8 wlan_idx; |
| + u8 mgmt_prot; |
| + u8 key[32]; |
| + u8 key_rsc[16]; |
| } __packed; |
| |
| struct sta_rec_hdr_trans { |
| @@ -441,7 +452,7 @@ struct sta_rec_mld { |
| sizeof(struct sta_rec_bfee) + \ |
| sizeof(struct sta_rec_phy) + \ |
| sizeof(struct sta_rec_ra) + \ |
| - sizeof(struct sta_rec_sec) + \ |
| + sizeof(struct sta_rec_sec_uni) + \ |
| sizeof(struct sta_rec_ra_fixed) + \ |
| sizeof(struct sta_rec_he_6g_capa) + \ |
| sizeof(struct sta_rec_eht) + \ |
| @@ -510,6 +521,33 @@ struct mt7925_wow_pattern_tlv { |
| u8 rsv[4]; |
| } __packed; |
| |
| +static inline enum connac3_mcu_cipher_type |
| +mt7925_mcu_get_cipher(int cipher) |
| +{ |
| + switch (cipher) { |
| + case WLAN_CIPHER_SUITE_WEP40: |
| + return CONNAC3_CIPHER_WEP40; |
| + case WLAN_CIPHER_SUITE_WEP104: |
| + return CONNAC3_CIPHER_WEP104; |
| + case WLAN_CIPHER_SUITE_TKIP: |
| + return CONNAC3_CIPHER_TKIP; |
| + case WLAN_CIPHER_SUITE_AES_CMAC: |
| + return CONNAC3_CIPHER_BIP_CMAC_128; |
| + case WLAN_CIPHER_SUITE_CCMP: |
| + return CONNAC3_CIPHER_AES_CCMP; |
| + case WLAN_CIPHER_SUITE_CCMP_256: |
| + return CONNAC3_CIPHER_CCMP_256; |
| + case WLAN_CIPHER_SUITE_GCMP: |
| + return CONNAC3_CIPHER_GCMP; |
| + case WLAN_CIPHER_SUITE_GCMP_256: |
| + return CONNAC3_CIPHER_GCMP_256; |
| + case WLAN_CIPHER_SUITE_SMS4: |
| + return CONNAC3_CIPHER_WAPI; |
| + default: |
| + return CONNAC3_CIPHER_NONE; |
| + } |
| +} |
| + |
| int mt7925_mcu_set_dbdc(struct mt76_phy *phy); |
| int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, |
| struct ieee80211_scan_request *scan_req); |
| -- |
| 2.43.0 |
| |