| Message ID | CAG0XsJEivMe8Dp+c0yuLtgZ50a6ToR3YGNsg8=ZNzJ068yb2tA@mail.gmail.com |
|---|---|
| State | Changes Requested |
| Headers | show |
| Series | ap: never disconnect idle stations sooner than ap_max_inactivity | expand |
On Sat, Sep 26, 2026 at 08:39:57AM -0700, hc86862997@gmail.com wrote: > hostapd adopts the client-advertised BSS Max Idle Period from the > (re)association request and lets it override the AP-wide > ap_max_inactivity, in two places: > > - ap_handle_timer(): > if (sta->max_idle_period) > max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; > - ap_sta_alloc(): the same computation for the initial timer > registration. > > Some clients (Apple) advertise a short BSS Max Idle Period (~20 units, > about 20 s) for power saving - they expect the AP to buffer frames for > them, not to be disconnected. The result is deterministic: with the > screen off (idle), the client is removed exactly 20 s after > association: The BSS max idle period indicated in the (Re)Association Request frame is an explicit request from the STA to use the provided idle timeout. If it is known that the particular clients referenced here do this incorrectly (i.e., ask for 20000 TUs but do not send keep-alive frames before that times out), this should be reported to the STA vendor as an issue that needs to be fixed in the STA. > Raising ap_max_inactivity has no effect for such clients because the > adoption overwrites it By design.. I.e., that is the correct AP behavior on accepting a STA requested value. > Fix: never disconnect a station sooner than the AP-wide > ap_max_inactivity - floor the adopted value in both places. That would break the expected functionality. The correct fix for this would be to fix the STA. If that is not doable, potentially adding a new configuration parameter to add a minimum acceptable timeout from STA could be considered as a workaround (i.e., min_acceptable_idle_period to complement the already available max_acceptable_idle_period). > Verification: an Apple MLO client left idle with the screen off was > previously kicked at exactly 20 s on every attempt; with this patch it > stays associated indefinitely. Clients that do not advertise BSS Max > Idle Period are unaffected. (Also reported to OpenWrt: > https://github.com/openwrt/openwrt/issues/25416 ) > > --- Please read the top level CONTRIBUTIONS file. I would need a Signed-off-by: line from the author or copyright holder of the patch to be able to consider applying it to hostap.git.
--- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -631,8 +631,22 @@ return; } - if (sta->max_idle_period) - max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; + if (sta->max_idle_period) { + /* + * Never disconnect a station sooner than the AP-wide + * ap_max_inactivity: some clients (e.g. Apple) advertise a + * short BSS Max Idle Period for power saving and expect + * buffered keep-alives, not disassociation. Adopting the + * value as-is made idle stations get kicked ~20s after + * association when the data poll went unanswered. + */ + int adopted = (sta->max_idle_period * 1024 + 999) / 1000; + + if (adopted < max_inactivity) + adopted = max_inactivity; + max_inactivity = adopted; + } if ((sta->flags & WLAN_STA_ASSOC) && (sta->timeout_next == STA_NULLFUNC || @@ -945,8 +959,22 @@
Hi, hostapd adopts the client-advertised BSS Max Idle Period from the (re)association request and lets it override the AP-wide ap_max_inactivity, in two places: - ap_handle_timer(): if (sta->max_idle_period) max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; - ap_sta_alloc(): the same computation for the initial timer registration. Some clients (Apple) advertise a short BSS Max Idle Period (~20 units, about 20 s) for power saving - they expect the AP to buffer frames for them, not to be disconnected. The result is deterministic: with the screen off (idle), the client is removed exactly 20 s after association: deauthenticated due to inactivity (timer DEAUTH/REMOVE) Raising ap_max_inactivity has no effect for such clients because the adoption overwrites it - we verified 20-second kicks with ap_max_inactivity=86400 present in the running configuration (MT7996 AP-MLD, hostapd 831364bf). Clients without the element keep using the AP-wide timeout, which is why the bug looks client-specific. Fix: never disconnect a station sooner than the AP-wide ap_max_inactivity - floor the adopted value in both places. Verification: an Apple MLO client left idle with the screen off was previously kicked at exactly 20 s on every attempt; with this patch it stays associated indefinitely. Clients that do not advertise BSS Max Idle Period are unaffected. (Also reported to OpenWrt: https://github.com/openwrt/openwrt/issues/25416 ) --- src/ap/sta_info.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) } sta->supported_rates_len = i; - if (sta->max_idle_period) - max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; + if (sta->max_idle_period) { + /* + * Never disconnect a station sooner than the AP-wide + * ap_max_inactivity: some clients (e.g. Apple) advertise a + * short BSS Max Idle Period for power saving and expect + * buffered keep-alives, not disassociation. Adopting the + * value as-is made idle stations get kicked ~20s after + * association when the data poll went unanswered. + */ + int adopted = (sta->max_idle_period * 1024 + 999) / 1000; + + if (adopted < max_inactivity) + adopted = max_inactivity; + max_inactivity = adopted; + } if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "