Acting as access point and client at the same time
In captive portal applications, specifically when using Wi-Fi onboarding flow over the same Wi-Fi adapter:
-
Windows, iOS and macOS will retry during the disconnection while scanning the same SSID, which works well if the authentication succeeds and connection is established in less than 5 seconds. Otherwise, the user has to be instructed to manually reconnect, breaking UX flow.
-
Android, GNOME, and ChromeOS will disconnect if their connectivity check endpoint (polled) does not return
204
at any time during the short period of disconnection.
hostapd
with virtual interface and wpa_supplicant
are used in most setups, clients lose connectivity very briefly when changing Wi-Fi credentials in wpad/wpa_supplicant.
When wpa_supplicant
reloads, hostapd
will also reload while sending disassociation commands to clients due to lost VAP socket interface.
Sending Channel Switch Announcements (CSA) is not always possible in VAP configuration, causing interruption as hostapd
follows the station frequency.
Wi-Fi Direct persistent group (P2P-GO
) can be used as a software access point.
On most Wi-Fi adapters, P2P-GO
supports multi role and multi channel as well as CSA which becomes optional as a result.
Wi-Fi Direct is not required on the client for connection (iOS and others).
This setup also allows the AP to operate on a different Wi-Fi channel than the station interface.
wpa_supplicant
does not send disassocation requests to clients when recreating the group, which is useful for softAP configuration changes.
The following setup was tested on:
- Radxa Zero 3W
- RPi Z2W, 3B+, 4 and 5
- Orange Pi Zero 1 (2016 - 10$)
in which they all support multi role multi channel switching, check by running:
root@piz:~# iw list | grep -A10 'valid interface combinations'
Output indicates at least #channels <=2
for P2P-GO & managed
which is needed for uninterrupted reconfiguration:
Raspberry Pi Zero 2W valid interface combinations:
* #{ managed } <= 2, #{ P2P-device } <= 1, #{ P2P-client, P2P-GO } <= 1, total <= 3, #channels <= 2
* #{ managed } <= 1, #{ AP } <= 1, #{ P2P-client } <= 1, #{ P2P-device } <= 1, total <= 4, #channels <= 1
Radxa Zero 3W valid interface combinations:
* #{ managed, mesh point } <= 1, #{ AP } <= 1, #{ P2P-client, P2P-GO } <= 1, #{ P2P-device } <= 1, total <= 4, #channels <= 3
The following configuration makes Wi-Fi Direct functionality inoperable since we are only using GO Persistent
mode as an alternative software access point.
For existing and running wpa_supplicant
service managed by NetworkManager you can use wpa_cli for full config:
wpa_cli -i wlan0 <<EOF
add_network
set_network 1 mode 3
set_network 1 disabled 2
set_network 1 ssid "IoT-WiFi-Setup"
set_network 1 psk "secrete"
set_network 1 key_mgmt WPA-PSK
set_network 1 proto RSN
set_network 1 pairwise CCMP
set_network 1 auth_alg OPEN
p2p_group_add persistent=1 ht40
wps_er_stop
EOF
Otherwise for spontaenous wpa_supplicant
daemon:
wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
p2p_go_intent=15
persistent_reconnect=1
country=US # Important, requires regulatory.db for CSA and multi-channel support, else P2P will stick to station channel with lowest channel width
#AP config
network={
ssid="IoT-WiFi-Setup"
psk="secrete"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
auth_alg=OPEN
mode=3
disabled=2
}
#Clients can be added later (live reload with wpa_cli reconfigure)
network={
ssid="Home Network"
psk="secret"
key_mgmt=WPA-PSK
ht40=1
}
When using configuration file, wpa_supplicant
will not setup P2P-GO automatically, since it’s designed to be managed by WPS daemon, invoke manually and disable enrollment:
wpa_cli p2p_group_add persistent=0 ht40
wpa_cli wps_er_stop
For Wi-Fi 6, enable HE and max channel width supported by the hardware (requires recent wpa_supplicant):
p2p_group_add persistent=1 he max_oper_chwidth=80 vht ht40
By default P2P-GO
will use the current station channel for softAP, unless indicated with freq=
, it will not sync after station reconfiguration which is desirable for compatibility for clients with no CSA.
When changing the home network credentials or joining a different network, edit wpa_supplicant.conf
and reconfigure station only:
wpa_cli -iwlan0 reconfigure
Sensitive clients connected to the softAP won’t notice any interruption, except slightly increased latency can be measured for a second.
Performance notes:
- Radxa Zero 3W (AIC8800 vendor kernel 5.15 b6) - 420 Mbit in station-only mode
Ingress | Station Speed | AP Speed |
---|---|---|
Sequential - Same channel | 305 Mbit | 260 Mbit |
Sequential - Channel mismatch | 305 Mbit | 258 Mbit |
Concurrent - Same channel | 200 Mbit | 75 Mbit |
Concurrent - Channel mismatch | 160 Mbit | 50 Mbit |
Concurrent Egress - Same channel | 116 Mbit | - |
Concurrent Egress - Channel mismatch | 105 Mbit | - |
- Raspberry Pi Zero 2W - 50 Mbit in station-only mode
Ingress | Station Speed | AP Speed |
---|---|---|
Sequential - Same channel | 40 Mbit | 47 Mbit |
Sequential - Channel mismatch | 35 Mbit | 36 Mbit |
Concurrent - Same channel | 12 Mbit | 10 Mbit |
Concurrent - Channel mismatch | 10 Mbit | 16 Mbit |
Concurrent Egress - Same channel | 20 Mbit | - |
Concurrent Egress - Channel mismatch | 17 Mbit | - |
Concurrent egress is equivalent to setting up the Pi as a Wi-Fi repeater, speeds are from the client connected to Pi forwarding traffic from AP