Commit eddc7286 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

wifi: mt76: mt7996: fix key add/remove imbalance

Ensure that a key for a link is only added and removed once.
When bringing up a link, only upload keys for that particular link, instead
of iterating over all of them.

Link: https://patch.msgid.link/20250915075910.47558-7-nbd@nbd.name


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 04414d7b
Loading
Loading
Loading
Loading
+90 −83
Original line number Diff line number Diff line
@@ -182,31 +182,20 @@ mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlin
static int
mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
		  struct ieee80211_key_conf *key)
		  unsigned int link_id, struct ieee80211_key_conf *key)
{
	struct mt7996_dev *dev = mt7996_hw_dev(hw);
	int idx = key->keyidx;
	unsigned int link_id;
	unsigned long links;

	if (key->link_id >= 0)
		links = BIT(key->link_id);
	else if (sta && sta->valid_links)
		links = sta->valid_links;
	else if (vif->valid_links)
		links = vif->valid_links;
	else
		links = BIT(0);

	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
	struct mt7996_sta_link *msta_link;
	struct mt7996_vif_link *link;
	int idx = key->keyidx;
	u8 *wcid_keyidx;
		int err;

	link = mt7996_vif_link(dev, vif, link_id);
	if (!link)
			continue;
		return 0;

	if (!mt7996_vif_link_phy(link))
		return 0;

	if (sta) {
		struct mt7996_sta *msta;
@@ -215,7 +204,7 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		msta_link = mt76_dereference(msta->link[link_id],
					     &dev->mt76);
		if (!msta_link)
				continue;
			return 0;

		if (!msta_link->wcid.sta)
			return -EOPNOTSUPP;
@@ -258,31 +247,31 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		*wcid_keyidx = -1;

	if (cmd != SET_KEY && sta)
			continue;
		return 0;

	mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key);

		err = mt7996_mcu_add_key(&dev->mt76, vif, key,
	return mt7996_mcu_add_key(&dev->mt76, vif, key,
				  MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
				  &msta_link->wcid, cmd);
		if (err)
			return err;
}

	return 0;
}
struct mt7996_key_iter_data {
    enum set_key_cmd cmd;
    unsigned int link_id;
};

static void
mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		struct ieee80211_sta *sta, struct ieee80211_key_conf *key,
		void *data)
{
	enum set_key_cmd *cmd = data;
	struct mt7996_key_iter_data *it = data;

	if (sta)
		return;

	WARN_ON(mt7996_set_hw_key(hw, *cmd, vif, NULL, key));
	WARN_ON(mt7996_set_hw_key(hw, it->cmd, vif, NULL, it->link_id, key));
}

int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
@@ -293,9 +282,12 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
	struct mt7996_sta_link *msta_link = &link->msta_link;
	struct mt7996_phy *phy = mphy->priv;
	enum set_key_cmd key_cmd = SET_KEY;
	struct mt7996_dev *dev = phy->dev;
	u8 band_idx = phy->mt76->band_idx;
	struct mt7996_key_iter_data it = {
		.cmd = SET_KEY,
		.link_id = link_conf->link_id,
	};
	struct mt76_txq *mtxq;
	int mld_idx, idx, ret;

@@ -373,7 +365,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
				   CONN_STATE_PORT_SECURE, true);
	rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid);

	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &key_cmd);
	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);

	if (mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED)
		mvif->mt76.deflink_id = link_conf->link_id;
@@ -388,12 +380,15 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
	struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76);
	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
	struct mt7996_sta_link *msta_link = &link->msta_link;
	enum set_key_cmd key_cmd = DISABLE_KEY;
	struct mt7996_phy *phy = mphy->priv;
	struct mt7996_dev *dev = phy->dev;
	struct mt7996_key_iter_data it = {
		.cmd = SET_KEY,
		.link_id = link_conf->link_id,
	};
	int idx = msta_link->wcid.idx;

	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &key_cmd);
	ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it);

	mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL,
			   CONN_STATE_DISCONNECT, false);
@@ -594,8 +589,9 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
			  struct ieee80211_key_conf *key)
{
	struct mt7996_dev *dev = mt7996_hw_dev(hw);
	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
	int err;
	unsigned int link_id;
	unsigned long links;
	int err = 0;

	/* The hardware does not support per-STA RX GTK, fallback
	 * to software mode for these.
@@ -629,11 +625,22 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		return -EOPNOTSUPP;
	}

	if (!mt7996_vif_link_phy(&mvif->deflink))
		return 0; /* defer until after link add */

	mutex_lock(&dev->mt76.mutex);
	err = mt7996_set_hw_key(hw, cmd, vif, sta, key);

	if (key->link_id >= 0)
		links = BIT(key->link_id);
	else if (sta && sta->valid_links)
		links = sta->valid_links;
	else if (vif->valid_links)
		links = vif->valid_links;
	else
		links = BIT(0);

	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
		err = mt7996_set_hw_key(hw, cmd, vif, sta, link_id, key);
		if (err)
			break;
	}
	mutex_unlock(&dev->mt76.mutex);

	return err;