Hijacking Wi-Fi Direct for Seamless Wi-Fi Onboarding on Raspberry Pi without using BLE
In captive portal applications, specifically when using Wi-Fi onboarding flow over the same Wi-Fi adapter:
-
Windows, GNOME, and ChromeOS will immediately disconnect if their connectivity check endpoint does not return 204 at any time, which happens during the short period of disconnection with the AP & managed multi-role mode.
-
iOS and macOS will wait and retry many times probing captive.apple.com valid https certificate response during the disconnection while sticking and scanning the same SSID.
hostapd with virtual interface and wpa_supplicant are used in most setups, clients lose connectivity very briefly when changing Wi-Fi credentials, station disconnection and initial network onboarding in IoT applications.
When wpa_supplicant reloads, hostapd tends to 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 on station frequency change, causing interruption when hostapd follows the station frequency.
As a workaround, 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 is optional as a result, more on that later.
Wi-Fi Direct is not required on the client for connection (iOS and others).
This solution will not only keep the client connected to the AP device while changing Wi-Fi station settings, but will also operate on a different Wi-Fi channel than the station that can be manually specified.
A frequency mismatch with the station slightly reduces throughput.
The following setup was tested on RPi Zero 2, 3, 4 and 5, in which they all support multi role multi channel switching, check by running:
root@piz:~# iw list | grep -A10 'valid interface combinations'Output indicates #channels <=2 for P2P-GO & managed configuration as we will use later instead of AP & Managed:
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 Device supports SAE with AUTHENTICATE command Device supports scan flush. Device supports randomizing MAC-addr in sched scans. max # scan plans: 1 max scan plan interval: 508 max scan plan iterations: 0The following configuration makes Wi-Fi Direct functionality inoperable since we are only using GO Persistent mode as an alternative software access point.
wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 p2p_go_intent=15 persistent_reconnect=1 p2p_go_ht40=1 country=US #AP config network={ ssid="IoT-WiFi-Setup" psk="mysecretpassword" proto=RSN key_mgmt=WPA-PSK pairwise=CCMP auth_alg=OPEN mode=3 mesh_fwding=1 disabled=2 # You can also set the channel here if you don't want the AP to follow on-first-connect-station frequency # Use `wpa_cli reconfigure` to change the channel live with CSA if supported } #Clients can be added later (live reload with wpa_cli reconfigure) network={ ssid="Home Network" psk="secrete" key_mgmt=WPA-PSK mesh_fwding=1 ht40=1 }wpa_supplicant won’t setup P2P-GO automatically, since it’s designed to be managed by WPS daemon, invoke manually:
wpa_cli p2p_group_add persistent=0By default P2P-GO will use the current station channel for softAP, it will not sync after setup.
You can optionally change it for better performance in wpa_cli interactive mode or by editing wpa_supplicant.config followed by wpa_cli reconfigure without causing any interruption provided that clients and AP support CSA, most wireless N clients and higher support it
wpa_cli interactive command:
p2p_set listen_channel 11When changing the home network credentials or joining a different network, edit wpa_supplicant.conf and simply issue:
wpa_cli reconfigureSensitive clients connected to the softAP won’t notice any hiccups, except a slightly increased latency can be measured. (20ms 200 byte ICMP)
Performance notes (download/ingress only):
- Raspberry Pi Zero 2W
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 saturates the AP and station at the same time.)