wifi: mac80211: purge TX queues in flush_queues flow
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Thu, 28 Sep 2023 14:35:38 +0000 (17:35 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 23 Oct 2023 09:45:17 +0000 (11:45 +0200)
When this flow is invoked with the "drop" parameter as true,
we only drop the frames from the hw queues, but not from the
sw queues.
So when we call wake_queues() after hw queue purging, all the
frames from the sw queues will be TX'ed,
when what we actually want to do is to purge all queues
in order to not TX anything...
This can cause, for example, TXing data frames to the peer
after the deauth frame was sent.
Fix this by purging the sw queues in addition to the hw queues
if the drop parameter is true.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230928172905.8fc2ee23e56f.I8b3f6def9c28ea96261e2d31df8786986fb5385b@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/sta_info.c
net/mac80211/util.c

index e92eaf835ee056782a4e8998eb1d976a093ae06a..70b6870fe5b4f6e157b5c5e8d40e69f08b03c7f3 100644 (file)
@@ -2390,6 +2390,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
                        struct txq_info *txq, int tid);
 void ieee80211_txq_purge(struct ieee80211_local *local,
                         struct txq_info *txqi);
+void ieee80211_purge_sta_txqs(struct sta_info *sta);
 void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata);
 void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
index ba36fc29e5324da33cc26648d936b2ee6ba2a7d3..450700173422dab5fd154278063dadf051df9d9b 100644 (file)
@@ -113,6 +113,23 @@ static int link_sta_info_hash_del(struct ieee80211_local *local,
                               &link_sta->link_hash_node, link_sta_rht_params);
 }
 
+void ieee80211_purge_sta_txqs(struct sta_info *sta)
+{
+       struct ieee80211_local *local = sta->sdata->local;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+               struct txq_info *txqi;
+
+               if (!sta->sta.txq[i])
+                       continue;
+
+               txqi = to_txq_info(sta->sta.txq[i]);
+
+               ieee80211_txq_purge(local, txqi);
+       }
+}
+
 static void __cleanup_single_sta(struct sta_info *sta)
 {
        int ac, i;
@@ -139,16 +156,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
                atomic_dec(&ps->num_sta_ps);
        }
 
-       for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-               struct txq_info *txqi;
-
-               if (!sta->sta.txq[i])
-                       continue;
-
-               txqi = to_txq_info(sta->sta.txq[i]);
-
-               ieee80211_txq_purge(local, txqi);
-       }
+       ieee80211_purge_sta_txqs(sta);
 
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
index 98a3bffc6991e3f7bacb40105bab66c75ac2d59f..b6be187104415ff3178f87524a1afe37e8ecbe20 100644 (file)
@@ -693,6 +693,19 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH,
                                        false);
 
+       if (drop) {
+               struct sta_info *sta;
+
+               /* Purge the queues, so the frames on them won't be
+                * sent during __ieee80211_wake_queue()
+                */
+               list_for_each_entry(sta, &local->sta_list, list) {
+                       if (sdata != sta->sdata)
+                               continue;
+                       ieee80211_purge_sta_txqs(sta);
+               }
+       }
+
        drv_flush(local, sdata, queues, drop);
 
        ieee80211_wake_queues_by_reason(&local->hw, queues,