Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save TalalMash/af78a8e3fc71d3310a0d9a191433e5a4 to your computer and use it in GitHub Desktop.
Save TalalMash/af78a8e3fc71d3310a0d9a191433e5a4 to your computer and use it in GitHub Desktop.
Repurposing Wi-Fi Direct for Seamless Wi-Fi Onboarding as an alternative to BLE

Repurposing Wi-Fi Direct for Seamless Wi-Fi Onboarding as an alternative to BLE

SoftAP multi-role Issues (AP + Managed)

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.


The 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 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment