[PATCH v3] ath11k: add ath11k_mac_op_flush_sta to properly flush pending packets

Florian Maurer f.maurer at outlook.de
Sat Nov 15 15:11:03 PST 2025


When a STA is marked as no longer authorized, if the driver doesn't
implement flush_sta(), mac80211 calls ieee80211_flush_queues() to
flush hardware queues to avoid sending unencrypted frames.

This has became a problem for ath11k because ieee80211_flush_queues()
will stop all traffic and call ath11k_flush, which waits until the
whole HW queue is empty. In a busy environment this will trigger a
timeout warning and stalls other STAs.

Fix this by implementing flush_sta method using WMI command to flush
frames of a specific STA.
Flushed frames will be marked as discard in tx complete indication.

warning print "ath11k c000000.wifi: failed to flush transmit queue 0"
was observed on various openwrt devices, and is fixed through this patch.

Tested-by: Florian Maurer  <f.maurer at outlook.de>
Tested-by: Flole <flole at flole.de>
Co-developed-by: Benjamin Berg <benjamin at sipsolutions.net>
Signed-off-by: Benjamin Berg <benjamin at sipsolutions.net>
Signed-off-by: Florian Maurer <f.maurer at outlook.de>
---
We tested this patch and it solved the problem of flushing the transmit
queues taking too long when the AP is busy.
Setting more than 0xFF leads to firmware crashes in AP/MESH mode.
Setting bit 17 in AP mode crashes as well.

There is reason to believe that bits 25-28 should be flushed
in STA mode, which is tested with openwrt as well.
This should make sure that no unencrypted frames are sent out on
station removal.

Regards
Florian

 drivers/net/wireless/ath/ath11k/mac.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 3276fe443502..69010d3c6b95 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -8640,6 +8640,26 @@ static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v
 	ath11k_mac_flush_tx_complete(ar);
 }
 
+static void ath11k_mac_op_flush_sta(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_sta *sta)
+{
+	struct ath11k_vif *arvif = (void *)vif->drv_priv;
+	struct ath11k *ar = hw->priv;
+	struct peer_flush_params params = {
+		.peer_tid_bitmap = 0xFF,
+		.vdev_id = arvif->vdev_id,
+	};
+	int ret;
+
+	if (vif->type == NL80211_IFTYPE_STATION)
+		params.peer_tid_bitmap |= 0x1e000000;
+
+	ret = ath11k_wmi_send_peer_flush_tids_cmd(ar, sta->addr, &params);
+	if (ret)
+		ath11k_warn(ar->ab, "failed to flush sta %pM: %d\n", sta->addr, ret);
+}
+
 static bool
 ath11k_mac_has_single_legacy_rate(struct ath11k *ar,
 				  enum nl80211_band band,
@@ -10095,6 +10115,7 @@ static const struct ieee80211_ops ath11k_ops = {
 	.set_bitrate_mask		= ath11k_mac_op_set_bitrate_mask,
 	.get_survey			= ath11k_mac_op_get_survey,
 	.flush				= ath11k_mac_op_flush,
+	.flush_sta			= ath11k_mac_op_flush_sta,
 	.sta_statistics			= ath11k_mac_op_sta_statistics,
 	CFG80211_TESTMODE_CMD(ath11k_tm_cmd)
 



More information about the ath11k mailing list