From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794283752; b=dh1PaoFqXkkHRFG4kVIEG/jM+GERL6H7DY/7UoeZhaYV8nCDWw3j4kphIYq2/tGS9Urp Ceq4zKptfbXqIVbJKK8E9X1upRxt+AyQpx0tZeTTD71EhWHr7AoxTu/cZgB9aWSlFIKl8 UmYSJpjxBTUXaAn7hEucbMsyP+EjvsnUmEigB97tNhVC+AbUgVP2sOg1HrZv6iyyor/Uw dHpdS9rRSHzN9dEqjZEID3acgRC+/GsXTa2nwq8SiJgJkmt2AYoe1nmlj7x3SA0yG01K7 vPCOqkdCxAjau5KUKnkerm4y8yNFyE8o2LKKjlJbCNe5r9JHAJvcEC2pUpnH3o8rLrA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794283752; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=uIg9BmWQAnrz47gSq3Vz9mkjB1byyfzr0QI4srhIF7I=; b=5WL9LrjQUPgez9/z+vnOAqav5PSxzN9U39YNiz6It8lzjAjoh4K+AAja4t7EDy9/54Xi 9bXwxKL3Yc9qOuH2AtUUAgyMm0elleSlEAssQU6DInw6juVghqhcpUwZ0I3Q+10I2N744 msMXmBoPJuNE7Jer6KMQR4pzK9D8qDm4QxEIPFQocjK1pTojWTCWhc1Df5HDZ3gfI9QKp ahHill1GhBQFxsdKQazMO4x8bPT15sVc8SpaYaCbR5hbP9g18QNJZB/2ECX5pQV0ppdyb r9pMS2M6rFuTasS/1eOQZw37cevN1h63MJC6oLfhY/RZrWyr5F7bBYG7yq1yFSlhyWA== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=BSJR6otF; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E76BA606A31C for ; Tue, 10 Nov 2026 04:09:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=BSJR6otF Received: by smtp.kernel.org (Postfix) with ESMTPSA id E74201F008A2; Tue, 10 Nov 2026 04:09:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1794283751; bh=uIg9BmWQAnrz47gSq3Vz9mkjB1byyfzr0QI4srhIF7I=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BSJR6otFdOdNsoCy16XA46Us+EKybG694Xq8x2wkdMa8Az+s4E2TrveqEBhAgboOD jO65TrDP4VBavgTUdj55GYYWnFJ6czu3kiBRpDa0t2kUsGQ/cDmn1u7Vr8qkIDfw3Q ph8WjZVq7E5zSAjOU0eaF+b8V3rtc/kEH/xcFDAqWHEUxzXWFzYxEmCWYuu8uBgM49 DWfs1VmhzGNWtpLWCDlS98jzaso95Wak3OSLdq8tL6wlEIYyvsXFk5aKXamqp/SMcD 8c1uqqsHz6wXobRtYstdjlMp5VrNkwQoZJD2f2nM4/3tdXc90syOqm65R9oXOX48Do TihUJwUCZsMmQ== From: Sasha Levin To: stable@vger.kernel.org Cc: Stanislaw Gruszka , Johannes Berg , Sasha Levin Subject: [PATCH 5.10.y] wifi: mac80211: queue frames while off-channel Date: Mon, 9 Nov 2026 23:09:09 -0500 Message-ID: <20261110040852.320508-1-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261107061449-failed-5.10-13e51269b665@kernel.org> References: <20261107061449-failed-5.10-13e51269b665@kernel.org> X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Stanislaw Gruszka [ Upstream commit 13e51269b6656768dc595ed6025e4974f2026543 ] Drivers without FAST_XMIT and hardware scan support currently drop TX frames during software scanning while being off-channel. This happens in ieee80211_tx_h_check_assoc() before frames reach internal TX queue. Move the off-channel check to invoke_tx_handlers_late(), after ieee80211_queue_skb(). Frames can then remain queued and be transmitted when the interface returns on-channel. This how TX works currently when code goes via ieee80211_xmit_fast() path. Below is rt2x00 driver ping output example while scanning, before and after the fix. After the fix, packets are no longer lost. Some have increased latency, what is expected behavior. BEFORE: 64 bytes from 192.168.0.1: icmp_seq=29 ttl=64 time=3.61 ms 64 bytes from 192.168.0.1: icmp_seq=31 ttl=64 time=3.33 ms # Missed 30 64 bytes from 192.168.0.1: icmp_seq=32 ttl=64 time=4.03 ms 64 bytes from 192.168.0.1: icmp_seq=34 ttl=64 time=3.10 ms # Missed 33 64 bytes from 192.168.0.1: icmp_seq=36 ttl=64 time=3.04 ms # Missed 35 64 bytes from 192.168.0.1: icmp_seq=38 ttl=64 time=3.05 ms # Missed 37 64 bytes from 192.168.0.1: icmp_seq=40 ttl=64 time=4.14 ms # Missed 39 64 bytes from 192.168.0.1: icmp_seq=41 ttl=64 time=4.50 ms AFTER: 64 bytes from 192.168.0.1: icmp_seq=29 ttl=64 time=3.40 ms 64 bytes from 192.168.0.1: icmp_seq=30 ttl=64 time=6.10 ms 64 bytes from 192.168.0.1: icmp_seq=31 ttl=64 time=4.69 ms 64 bytes from 192.168.0.1: icmp_seq=32 ttl=64 time=4.49 ms 64 bytes from 192.168.0.1: icmp_seq=33 ttl=64 time=148 ms 64 bytes from 192.168.0.1: icmp_seq=34 ttl=64 time=6.83 ms 64 bytes from 192.168.0.1: icmp_seq=35 ttl=64 time=8.66 ms 64 bytes from 192.168.0.1: icmp_seq=36 ttl=64 time=13.0 ms 64 bytes from 192.168.0.1: icmp_seq=37 ttl=64 time=4.78 ms 64 bytes from 192.168.0.1: icmp_seq=38 ttl=64 time=3.85 ms Cc: Signed-off-by: Stanislaw Gruszka Link: https://patch.msgid.link/20260908124651.2995-1-stf_xl@wp.pl Signed-off-by: Johannes Berg [ sashal: retained the existing out_free cleanup path in ieee80211_8023_xmit() ] Signed-off-by: Sasha Levin --- net/mac80211/tx.c | 50 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 73b79a9611011..6c9df5e2a0d64 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -291,7 +291,6 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); bool assoc = false; @@ -299,23 +298,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && - test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) && - !ieee80211_is_probe_req(hdr->frame_control) && - !ieee80211_is_any_nullfunc(hdr->frame_control)) - /* - * When software scanning only nullfunc frames (to notify - * the sleep state to the AP) and probe requests (for the - * active scan) are allowed, all other frames should not be - * sent and we should not get here, but if we do - * nonetheless, drop them to avoid sending them - * off-channel. See the link below and - * ieee80211_start_scan() for more. - * - * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089 - */ - return TX_DROP; - if (tx->sdata->vif.type == NL80211_IFTYPE_OCB) return TX_CONTINUE; @@ -801,6 +783,33 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) return TX_CONTINUE; } +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_check_offchannel(struct ieee80211_tx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + + if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) + return TX_CONTINUE; + + if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && + test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) && + !ieee80211_is_probe_req(hdr->frame_control) && + !ieee80211_is_any_nullfunc(hdr->frame_control)) { + /* + * When software scanning only nullfunc frames (to notify + * the sleep state to the AP) and probe requests (for the + * active scan) are allowed, all other frames should not be + * sent and we should not get here, but if we do + * nonetheless, drop them to avoid sending them + * off-channel. See __ieee80211_start_scan() for more. + */ + return TX_DROP; + } + + return TX_CONTINUE; +} + static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid) { u16 *seq = &sta->tid_seq[tid]; @@ -1825,6 +1834,7 @@ static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx) goto txh_done; } + CALL_TXH(ieee80211_tx_h_check_offchannel); CALL_TXH(ieee80211_tx_h_michael_mic_add); CALL_TXH(ieee80211_tx_h_sequence); CALL_TXH(ieee80211_tx_h_fragment); @@ -4282,10 +4292,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, skb_get_hash(skb); } - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) && - test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) - goto out_free; - memset(info, 0, sizeof(*info)); tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -- 2.53.0