Whenever sta_flush() function is invoked, all STAs present in that
interface are flushed. In case of MLO, it is desirable to only flush such
STAs that are at least using a given link id as one of their links.
Add support for this by making change in the __sta_info_flush API argument
to accept a link ID. And then, only if the STA is using the given link as
one of its links, it would be flushed.
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Link: https://msgid.link/20240205162952.1697646-3-quic_adisi@quicinc.com
[reword commit message, in particular this isn't about "active" links]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
        link_conf->ema_ap = false;
        link_conf->bssid_indicator = 0;
 
-       __sta_info_flush(sdata, true);
+       __sta_info_flush(sdata, true, -1);
        ieee80211_free_keys(sdata, true);
 
        link_conf->enable_beacon = false;
        if (params->mac)
                return sta_info_destroy_addr_bss(sdata, params->mac);
 
-       sta_info_flush(sdata);
+       sta_info_flush(sdata, params->link_id);
        return 0;
 }
 
 
        drv_reset_tsf(local, sdata);
 
        if (!ether_addr_equal(ifibss->bssid, bssid))
-               sta_info_flush(sdata);
+               sta_info_flush(sdata, -1);
 
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.cfg.ibss_joined) {
 
        ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
 
-       sta_info_flush(sdata);
+       sta_info_flush(sdata, -1);
 
        spin_lock_bh(&ifibss->incomplete_lock);
        while (!list_empty(&ifibss->incomplete_stations)) {
 
         * would have removed them, but in other modes there shouldn't
         * be any stations.
         */
-       flushed = sta_info_flush(sdata);
+       flushed = sta_info_flush(sdata, -1);
        WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0);
 
        /* don't count this interface for allmulti while it is down */
 
        netif_carrier_off(sdata->dev);
 
        /* flush STAs and mpaths on this iface */
-       sta_info_flush(sdata);
+       sta_info_flush(sdata, -1);
        ieee80211_free_keys(sdata, true);
        mesh_path_flush_by_iface(sdata);
 
 
        sdata->vif.cfg.ssid_len = 0;
 
        /* remove AP and TDLS peers */
-       sta_info_flush(sdata);
+       sta_info_flush(sdata, -1);
 
        /* finally reset all BSS / config parameters */
        if (!ieee80211_vif_is_mld(&sdata->vif))
 
        lockdep_assert_wiphy(sdata->local->hw.wiphy);
 
        ifocb->joined = false;
-       sta_info_flush(sdata);
+       sta_info_flush(sdata, -1);
 
        spin_lock_bh(&ifocb->incomplete_lock);
        while (!list_empty(&ifocb->incomplete_stations)) {
 
 }
 
 
-int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans)
+int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans,
+                    int link_id)
 {
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta, *tmp;
        WARN_ON(vlans && !sdata->bss);
 
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               if (sdata == sta->sdata ||
-                   (vlans && sdata->bss == sta->sdata->bss)) {
-                       if (!WARN_ON(__sta_info_destroy_part1(sta)))
-                               list_add(&sta->free_list, &free_list);
-                       ret++;
-               }
+               if (sdata != sta->sdata &&
+                   (!vlans || sdata->bss != sta->sdata->bss))
+                       continue;
+
+               if (link_id >= 0 && sta->sta.valid_links &&
+                   !(sta->sta.valid_links & BIT(link_id)))
+                       continue;
+
+               if (!WARN_ON(__sta_info_destroy_part1(sta)))
+                       list_add(&sta->free_list, &free_list);
+
+               ret++;
        }
 
        if (!list_empty(&free_list)) {
 
  *
  * @sdata: sdata to remove all stations from
  * @vlans: if the given interface is an AP interface, also flush VLANs
+ * @link_id: if given (>=0), all those STA entries using @link_id only
+ *          will be removed. If -1 is passed, all STA entries will be
+ *          removed.
  */
-int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans);
+int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans,
+                    int link_id);
 
 /**
  * sta_info_flush - flush matching STA entries from the STA table
  * Returns the number of removed STA entries.
  *
  * @sdata: sdata to remove all stations from
+ * @link_id: if given (>=0), all those STA entries using @link_id only
+ *          will be removed. If -1 is passed, all STA entries will be
+ *          removed.
  */
-static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata)
+static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata,
+                                int link_id)
 {
-       return __sta_info_flush(sdata, false);
+       return __sta_info_flush(sdata, false, link_id);
 }
 
 void sta_set_rate_info_tx(struct sta_info *sta,