From: rcfa <kernel@cubiculum.net>
To: Johannes Berg <johannes@sipsolutions.net>
Cc: linux-wireless@vger.kernel.org, Ping-Ke Shih <pkshih@realtek.com>
Subject: [PATCH wireless] wifi: mac80211: deauthenticate on stop if an association just completed
Date: Sun, 1 Nov 2026 20:12:51 +0000 [thread overview]
Message-ID: <20261101201251.1106968-1-kernel@cubiculum.net> (raw)
When an interface goes down, cfg80211_leave() runs on NETDEV_GOING_DOWN
and disconnects if the interface is connected. An association that
userspace started (NL80211_CMD_ASSOCIATE) and that is still in progress
is left to mac80211, and ieee80211_mgd_stop() abandons it later, from
ndo_stop. In between, the wiphy lock is not held and SDATA_STATE_RUNNING
is still set, so the association response can still be processed and
the association succeeds. ieee80211_do_stop() then goes on with an
associated interface: sta_info_flush() removes the AP station and the
WARN_ON_ONCE() on its result fires, an MLD also warns "destroying
interface with valid links", and the interface is removed from the
driver while its links still have channel contexts, which are never
unassigned.
ieee80211_mgd_quiesce() has worked around the same race for suspend
since commit be72afe0a438 ("mac80211: fix another suspend vs.
association race"), by deauthenticating if the interface is associated
by then. Do the same in ieee80211_mgd_stop(). When it runs,
SDATA_STATE_RUNNING is clear and the wiphy lock is held, so no further
association response can be processed.
The window opened when cfg80211 stopped tracking authentication state:
until then, cfg80211_mlme_down() also deauthenticated from BSSes that
were authenticated but not yet associated, which aborted an association
in progress.
This was seen with an RTL8922AU (rtw89, USB) on Linux 7.1.5 and
wpa_supplicant 2.11 associating by MLO to an AP MLD, when NetworkManager
took the interface down to change its MAC address for a scan in the
same second as the association completed:
wlan0: associated
WARNING: net/mac80211/iface.c:536 at ieee80211_do_stop+0x8e9/0xb50 [mac80211]
Call Trace:
ieee80211_stop
__dev_close_many
__dev_change_flags
netif_change_flags
do_setlink
rtnl_newlink
destroying interface with valid links 0x0002
WARNING: net/mac80211/iface.c:563 at ieee80211_do_stop+0x9d8/0xb50 [mac80211]
rtw89 then kept the interface on its channel manager's active list, and
its next scan looped forever with the wiphy lock held, which hung RTNL.
That is being fixed in rtw89 separately.
Timing alone did not reproduce the race (0 of 29 attempts), so its end
state was reproduced with a test-only hook in ieee80211_deauth() that
ignores the next WLAN_REASON_DEAUTH_LEAVING request, which leaves the
interface associated when ndo_stop runs (rtw89 had its own fix in both
runs). Without this change, the
second round warned as above, then in ieee80211_prep_connection(),
ieee80211_set_disassoc() and cfg80211_process_disassoc(), and ended in
a NULL pointer dereference in ieee80211_rx_mgmt_beacon(). With it, both
of 2 rounds deauthenticated on stop ("deauthenticating from ... by local
choice (Reason: 3=DEAUTH_LEAVING)"), with no warning or oops, and the
interface reconnected.
The problem was found with Claude Code (Claude Opus 5.5) while analysing
that hang, and this change and changelog were written in the same
session.
Fixes: 95de817b9034 ("cfg80211: stop tracking authenticated state")
Signed-off-by: rcfa <kernel@cubiculum.net>
---
Notes:
Testing: the results above are from Linux 7.1.5 (Kali 7.1.5-1kali1)
with this change applied to its mac80211. This port to wireless/main
differs only in context and has been compile-tested only: x86_64
allmodconfig with gcc 16.2 (CONFIG_WERROR=y), net/mac80211/ with and
without W=1, and sparse on mlme.c, with no new warnings. The test-only
hook and the script that drives it are available on request.
The rtw89 side is posted separately, for rtw-next:
"wifi: rtw89: take the interface off the active list when removing it"
net/mac80211/mlme.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 3c31c16860ab..5791d5b5fe86 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -10838,6 +10838,25 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
wiphy_hrtimer_work_cancel(sdata->local->hw.wiphy,
&ifmgd->uhr_omp.status_work);
+ /*
+ * As in ieee80211_mgd_quiesce(): cfg80211 cannot abort an ongoing
+ * association when it disconnects on NETDEV_GOING_DOWN, so the
+ * association response may still have been processed before we got
+ * here. Deauthenticate if the association succeeded, rather than
+ * remove the interface from the driver with the AP station, links
+ * and channel contexts still in place.
+ */
+ if (ifmgd->associated) {
+ u8 bssid[ETH_ALEN];
+ struct cfg80211_deauth_request req = {
+ .reason_code = WLAN_REASON_DEAUTH_LEAVING,
+ .bssid = bssid,
+ };
+
+ memcpy(bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
+ ieee80211_mgd_deauth(sdata, &req);
+ }
+
if (ifmgd->assoc_data)
ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT, NULL);
if (ifmgd->auth_data)
base-commit: 25e73f1d6868c759c8eb56cad4e411692c5341b4
--
2.53.0
reply other threads:[~2026-11-01 20:46 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261101201251.1106968-1-kernel@cubiculum.net \
--to=kernel@cubiculum.net \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
--cc=pkshih@realtek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox