wifi: mt76: mt7925: fix WoW failed in encrypted mode
authorMing Yen Hsieh <mingyen.hsieh@mediatek.com>
Fri, 29 Dec 2023 03:09:33 +0000 (11:09 +0800)
committerFelix Fietkau <nbd@nbd.name>
Thu, 22 Feb 2024 08:55:17 +0000 (09:55 +0100)
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>
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
drivers/net/wireless/mediatek/mt76/mt7925/main.c
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
drivers/net/wireless/mediatek/mt76/mt7925/mcu.h

index db96ddbeb9e70ca833df0ecfb9aac2a5e4648ad6..657a4d1f856b2268f137053649968b713963bcaa 100644 (file)
@@ -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
index 5671e08dec6542755d2b495abbc1050f7e509dfe..c74ba9642fc8d14c899c7afa7efb71a1fd467b11 100644 (file)
@@ -359,6 +359,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,
@@ -526,7 +527,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);
        }
 
index 0299045b4b8331d827a18d9020c87cd51ed56d21..8c3233182083f07a8c9a84d35f779223f600fefa 100644 (file)
@@ -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;
index 0218fd2a0eb01a9fb4263b85d154a2f909b95fb0..9fce054e50657178d9392059e4622280912a8591 100644 (file)
@@ -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);