Skip to content

Keep the Wi-Fi driver out of screen-off suspend mode while the AP runs - #19

Open
poqdavid wants to merge 3 commits into
ravindu644:mainfrom
poqdavid:wifi-awake
Open

poqdavid wants to merge 3 commits into
ravindu644:mainfrom
poqdavid:wifi-awake

Conversation

@poqdavid

@poqdavid poqdavid commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Clients that join the hotspot while the phone's screen is off get no IPv6 (no SLAAC, no DHCPv6) until the screen comes back on. IPv4 keeps working.

The cause is the Wi-Fi driver's suspend mode. At screen off, Android sends the driver SETSUSPENDMODE 1. MediaTek's gen4m driver then puts the AP's BSS into firmware suspend mode along with the phone's own, and the firmware drops the multicast that clients send: Router Solicitations (ff02::2), DHCPv6 (ff02::1:2), mDNS. DHCPv4 is broadcast, so it isn't affected.

This PR adds WIFI_AWAKE (-a, on by default). While the AP runs, the monitor sends DRIVER SETSUSPENDMODE 0 to wpa_supplicant on the Wi-Fi interface, once at its start and then on its existing 3 s beat.

How it was found

  • tcpdump on vaplan0 in the managed-mode OpenWrt container: with the screen locked, the client's Router Solicitations never arrived. Right after unlocking, one arrived and odhcpd answered it within 0.6 ms.
  • Ruled out: the bridge's multicast snooping, CPU sleep (a kernel wakelock didn't help), and Android's settings (wifi_suspend_optimizations_enabled, cmd wifi force-hi-perf-mode), none of which changed anything.
  • Driver source (gen4m, SM-A155F / MT6789): priv_driver_set_suspend_mode() calls p2pSetSuspendMode(), which calls wlanNotifyFwSuspend() on the AP's BSS (the hotspot is a P2P role there). For the phone's own interface the driver keeps 33:33:00:00:00:01 allowed while suspended; nothing is kept for the AP.
  • Sending SETSUSPENDMODE 0 by hand made the Router Solicitations arrive with the screen locked.

Why through wpa_supplicant

  • Android sets suspend mode the same way, so the command reaches every driver Android can put into suspend mode.
  • The supplicant hands DRIVER commands to the vendor's own library, which packs them the way that driver reads them: gen4m takes the text inline, AOSP and Broadcom take a pointer. The engine doesn't need to know any of that.
  • It's the same route the engine already uses for DRIVER COUNTRY, fire and forget, since replies don't come back on Samsung's firmware.

Tested by hand on the phone. After forcing suspend mode on, sending the command through the supplicant gave:

priv_support_driver_cmd: driver cmd "SETSUSPENDMODE 0" on wlan0
priv_driver_set_suspend_mode: Set suspend mode [0]

and the laptop's Router Solicitation got through again.

Changes

  • backend: -a / WIFI_AWAKE (default 1). wifi_awake() in radio/driver.c; the monitor calls it at its start and on every beat, in both modes. WPA_CTRL_DIR moves from channel.c to radio/internal.h, shared with DRIVER COUNTRY.
  • app: a "Keep Wi-Fi awake with screen off" switch in Settings, under "Start access point at boot", on by default. Saved to ap.conf, so a boot start honours it too. Locked while the AP runs, like the main screen's settings.
  • docs: How-It-Works, monitor section.

Cost

  • One command covers both the AP and the phone's own Wi-Fi client, so while the AP runs the client side loses its screen-off power saving too. That's a little more battery if the phone is also connected to a Wi-Fi network. The AP is awake for its beacons anyway.
  • One DRIVER command every 3 s through the supplicant. The driver skips it when it's already out of suspend mode, and it rides the existing beat, so it adds no wakeups.
  • Nothing is put back at the stop: Android sends SETSUSPENDMODE 1 again at the next screen off.

Testing

  • make check with new tests: the option's default and parsing, the command reaching a fake supplicant socket, and -1 when there's no supplicant. Passes on glibc and musl. clang-format clean; static musl build with -Werror.
  • On SM-A155F (MT6789): <final build: hotspot started, ap.log shows "Keeping the WiFi driver out of suspend mode while the AP runs", phone locked, client reconnected and got IPv6 within a few seconds>

Notes

Image

Android puts the WiFi driver into suspend mode at screen off, and
MediaTek's puts the AP's BSS in with the phone's own, where the firmware
drops what clients multicast: Router Solicitations, DHCPv6, mDNS.
Clients joining with the screen off got no IPv6 until it came back on.
With -a 1 (WIFI_AWAKE, the default) the monitor sends DRIVER
SETSUSPENDMODE 0 to the supplicant on the WiFi interface at its start
and on every beat, the way Android sets suspend mode; the vendor's
library packs it the way that driver reads it, and a repeat is a no-op
there. WPA_CTRL_DIR moves to radio/internal.h, shared with DRIVER
COUNTRY.

Signed-off-by: poqdavid <poq-david@live.com>
Under Start access point at boot, on by default, saved to ap.conf as
WIFI_AWAKE so a boot start honours it too. The engine reads it at the
start, so it is locked while the access point runs.

Signed-off-by: poqdavid <poq-david@live.com>
How-It-Works says what WIFI_AWAKE does and why, and how the monitor
reaches the driver through the supplicant.

Signed-off-by: poqdavid <poq-david@live.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant