Commit 47916693 authored by Ming Yen Hsieh's avatar Ming Yen Hsieh Committed by Felix Fietkau
Browse files

wifi: mt76: mt7925: fix WoW failed in encrypted mode



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: c948b5da ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Signed-off-by: default avatarMing Yen Hsieh <mingyen.hsieh@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 6864bc73
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+2 −1
Original line number Diff line number Diff line
@@ -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);
	}

+46 −40
Original line number Diff line number Diff line
@@ -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;
+54 −16
Original line number Diff line number Diff line
@@ -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);