]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7915: ensure that only one sta entry is active per mac address
authorFelix Fietkau <nbd@nbd.name>
Mon, 30 Dec 2024 19:41:57 +0000 (20:41 +0100)
committerFelix Fietkau <nbd@nbd.name>
Tue, 14 Jan 2025 12:34:36 +0000 (13:34 +0100)
When a client is roaming to a different AP interface, a duplicate wtbl entry
can be created. This can lead to lost packets or aggregation issues until
the old entry expires.
In order to fix this issue, delete any conflicting entries from WTBL
whenever a station is authorized.

Link: https://patch.msgid.link/20241230194202.95065-9-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/main.c

index 2d4457fbb5abdb90ceced255bae026fcef3e89aa..fd337aede99e155a01710f0623bb2f09b3775eed 100644 (file)
@@ -368,8 +368,12 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        int idx = key->keyidx;
        int err = 0;
 
-       if (sta && !wcid->sta)
+       if (sta && !wcid->sta) {
+               if (cmd != SET_KEY)
+                       return 0;
+
                return -EOPNOTSUPP;
+       }
 
        /* The hardware does not support per-STA RX GTK, fallback
         * to software mode for these.
@@ -765,6 +769,57 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
        return 0;
 }
 
+struct drop_sta_iter {
+       struct mt7915_dev *dev;
+       struct ieee80211_hw *hw;
+       struct ieee80211_vif *vif;
+       u8 sta_addr[ETH_ALEN];
+};
+
+static void
+__mt7915_drop_sta(void *ptr, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct drop_sta_iter *data = ptr;
+       struct ieee80211_sta *sta;
+       struct mt7915_sta *msta;
+
+       if (vif == data->vif || vif->type != NL80211_IFTYPE_AP)
+               return;
+
+       sta = ieee80211_find_sta_by_ifaddr(data->hw, data->sta_addr, mac);
+       if (!sta)
+               return;
+
+       msta = (struct mt7915_sta *)sta->drv_priv;
+       mt7915_mcu_add_sta(data->dev, vif, sta, CONN_STATE_DISCONNECT, false);
+       msta->wcid.sta_disabled = 1;
+       msta->wcid.sta = 0;
+}
+
+static void
+mt7915_drop_other_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+                     struct ieee80211_sta *sta)
+{
+       struct mt76_phy *ext_phy = dev->mt76.phys[MT_BAND1];
+       struct drop_sta_iter data = {
+               .dev = dev,
+               .hw = dev->mphy.hw,
+               .vif = vif,
+       };
+
+       if (vif->type != NL80211_IFTYPE_AP)
+               return;
+
+       memcpy(data.sta_addr, sta->addr, ETH_ALEN);
+       ieee80211_iterate_active_interfaces(data.hw, 0, __mt7915_drop_sta, &data);
+
+       if (!ext_phy)
+               return;
+
+       data.hw = ext_phy->hw;
+       ieee80211_iterate_active_interfaces(data.hw, 0, __mt7915_drop_sta, &data);
+}
+
 int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
                         struct ieee80211_sta *sta, enum mt76_sta_event ev)
 {
@@ -793,6 +848,7 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
                return 0;
 
        case MT76_STA_EVENT_AUTHORIZE:
+               mt7915_drop_other_sta(dev, vif, sta);
                return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false);
 
        case MT76_STA_EVENT_DISASSOC: