Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Prevent AP probing during suspend

Submitting AP probe/null during suspend can cause unexpected
disconnect on resume because of timeout waiting for ack status:

wlan0: Failed to send nullfunc to AP 11:22:33:44:55:66 after 500ms, disconnecting

This is especially the case when we enter suspend when a scan is
ongoing, indeed, scan is cancelled from __ieee80211_suspend, leading
to a corresponding (aborted) scan complete event, which in turn causes
the submission of an immediate monitor null frame (restart_sta_timer).
The corresponding packet or ack will not be processed before resuming,
causing a timeout & disconnect on resume.

Delay the AP probing when suspending/suspended.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Link: https://lore.kernel.org/r/1634805927-1113-1-git-send-email-loic.poulain@linaro.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Loic Poulain and committed by
Johannes Berg
b33fb28c 63fa0426

+14
+3
net/mac80211/ieee80211_i.h
··· 1241 1241 */ 1242 1242 bool suspended; 1243 1243 1244 + /* suspending is true during the whole suspend process */ 1245 + bool suspending; 1246 + 1244 1247 /* 1245 1248 * Resuming is true while suspended, but when we're reprogramming the 1246 1249 * hardware -- at that time it's allowed to use ieee80211_queue_work()
+7
net/mac80211/mlme.c
··· 2589 2589 goto out; 2590 2590 } 2591 2591 2592 + if (sdata->local->suspending) { 2593 + /* reschedule after resume */ 2594 + mutex_unlock(&sdata->local->mtx); 2595 + ieee80211_reset_ap_probe(sdata); 2596 + goto out; 2597 + } 2598 + 2592 2599 if (beacon) { 2593 2600 mlme_dbg_ratelimited(sdata, 2594 2601 "detected beacon loss from AP (missed %d beacons) - probing\n",
+4
net/mac80211/pm.c
··· 27 27 if (!local->open_count) 28 28 goto suspend; 29 29 30 + local->suspending = true; 31 + mb(); /* make suspending visible before any cancellation */ 32 + 30 33 ieee80211_scan_cancel(local); 31 34 32 35 ieee80211_dfs_cac_cancel(local); ··· 179 176 /* need suspended to be visible before quiescing is false */ 180 177 barrier(); 181 178 local->quiescing = false; 179 + local->suspending = false; 182 180 183 181 return 0; 184 182 }