Hi guys,
This is a recipe for Pi3B only (not 3B+, not 0w), to get the built-in
wlan0 interface working as a WPA2 STA and the "virtual AP" interface
working at the same time. For now I use an open AP, IIRC a WPA2 AP works
as well, I haven't tried other combinations.
It seems to work so far for me on a buildroot, 32-bit, busybox init with
ifupdown, Pi 3B (Linux rpi3 4.14.50-v7 #1 SMP Mon Oct 15 14:26:41 CEST
2018 armv7l GNU/Linux)
I'm posting this because:
- I've spent a long time trying to make STA+AP work on brcm 43430 in a
reliable and repeatable way, and according to my stress-test it seems
I've achieved that
- I suppose some here might want to test that with PcP, which is not
too different from my buildroot system, and I have a hunch the wifi
virtual AP could sustain streaming to a couple of wifi speakers.
Unfortunately I don't have time to test this recipe myself on PcP but
I think it should mostly apply and work.
I can't really answer further questions:
- I expose here the gist of my recipe and fundamentally I do not
understand why it works...
- For sure you can't expect it to work with something like Raspbian
or a systemd-based OS: dhcpcd and systemd have their way of managing
interfaces, and this changes everything.
- Along my quest I've had systems where removing/reinserting the
brcmfmac module would help getting STA+AP work, and others where doing
that just makes the OS crash...
Folks running Raspbian or a systemd OS might want to refer to 'this
excellent post'
(https://raspberrypi.stackexchange.com/questions/89803/access-point-as-wifi-repeater-optional-with-bridge)
on StackExchange. I know for a fact the author Ingo has been researching
on the question for a while, too.
Ok, now the recipe:
- Bring up the wlan0 interface with the normal wpa_supplicant daemon
(in "pre-up") and next, add a wpa_cli instance with something like
this...
Code:
[ -f /var/run/wpastate.wlan0.pid ] || /usr/sbin/wpa_cli -B -i wlan0 -a
/usr/local/bin/hostapd_helper.sh -P /var/run/wpastate.wlan0.pid
...having hostapd_helper.sh as this:
Code:
#!/bin/sh
freq_to_chan(){
F="$1"
[ $F -eq 2484 ] && echo 14 && return
[ $F -lt 2484 ] && echo $(( (F-2407) / 5)) && return
echo $(( F / 5 - 1000))
}
case $2 in
"CONNECTED")
F=$(/usr/sbin/wpa_cli -i ${1} status | grep freq | cut -d '=' -f 2 | xargs)
[ -n "$F" ] && C=$(freq_to_chan ${F})
[ -n "$C" ] && echo ${F} ${C} > /var/run/network/wpastate.${1}
;;
"DISCONNECTED")
rm -f /var/run/network/wpastate.${1}
;;
esac
exit 0
This makes wpa_supplicant report its current frequency and channel in
file /var/run/wpastate.wlan0 when it is connected. hostapd needs that
to launch the AP successfully.
- Tear wlan0 down like that (in "post-down"):
Code:
# Use the cli to stop the backend. Our cli exits in turn
if [ -e /var/run/wpastate.wlan0.pid ]; then
/usr/sbin/wpa_cli -i wlan0 terminate
else
pkill -f "/usr/sbin/wpa_supplicant -B -i wlan0"
pkill -f "/usr/sbin/wpa_cli -B -i wlan0"
fi
rm -f /var/run/wpastate.wlan0.pid
rm -f /var/run/network/wpastate.wlan0
- Bring up the ap0 interface this way (in "pre-up"):
Code:
/usr/sbin/iw phy0 interface add ap0 type __ap
/usr/sbin/iw ap0 set power_save off
/sbin/ip link set ap0 address 02:96:ea:ca:ff:f4
I suggest you set the MAC to "02:something" (see MAC addr classes and
linux bridge behaviour as to why.) power_save off really seems to make
a difference, make sure to apply it to both ap0 and wlan0.
- Tear ap0 down like that (in "post-down"):
Code:
/usr/sbin/iw ap0 del
- You also need a bridge interface (I called it local0), there is
nothing special about it. Recommend not shutting down STP but using a
short forward delay to speed up DHCP lease acquisition.
- You need a DHCP server listening on the bridge, as usual dnsmasq
does just fine.
- You need a hostapd config, nothing special about it. For the record
here is my open AP test config in /etc/hostapd/hostapd-ap0.conf:
Code:
ctrl_interface=/var/run/hostapd
ctrl_interface_group=netdev
interface=ap0
bridge=local0
driver=nl80211
country_code=FR
ssid=test
wpa=0
hw_mode=g
channel=11
wmm_enabled=1
ieee80211n=1
ieee80211d=1
max_num_sta=5
logger_syslog=0
logger_stdout=0
- The last piece of the puzzle is the start/stop hostapd script. The
stop action is simple, in essence it does:
Code:
kill $(cat /var/run/hostapd.ap0.pid)
rm -f /tmp/hostapd-ap0.conf
ifdown ap0
ifdown local0