Thanks to Albert for the initial hint, see https://blog.thewalr.us/2017/09/26/raspberry-pi-zero-w-simultaneous-ap-and-managed-mode-wifi/
However, I decided to use systemd-networkd instead of /e/n/i, and it seems no ugly workaround is needed.
I have this rule in /etc/udev/rules.d/70-phy.rules :
SUBSYSTEM=="ieee80211", ACTION=="add|change", DRIVERS=="brcmfmac", \
RUN+="/sbin/iw phy %k interface add ap0 type __ap"
Note the absence of MAC address setting - it's weird, but when the MAC address is set to another value, any client trying to connect to the AP would successfully associate and then disassociate 18 seconds later in an endless cycle.
Additionally I have this rule in /etc/udev/rules.d/80-wpa.rules :
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="brcmfmac", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="wlan*", NAME="sta0"
Strictly this isn't needed, however I intend to optionally add USB WiFi adapters, and this will make the device names predictable.
Interface config for ap0 in /etc/systemd/network/ap0.network :
[Match]
Name=ap0
[Network]
Address=192.168.10.254/24
IPForward=1
and /etc/systemd/network/sta.network
[Match]
Name=sta*
[Network]
DHCP=ipv4
IPForward=1
To start wpa_supplicant, this is the service file /etc/systemd/system/wpa_supplicant@.service :
[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
BindsTo=sys-subsystem-net-devices-%i.device
[Service]
Type=simple
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant.conf -i %I
[Install]
Alias=multi-user.target.wants/wpa_supplicant@%I.service
WantedBy=multi-user.target
To start hostapd, /etc/systemd/system/hostapd@.service :
[Unit]
Description=HostAP Daemon
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
BindsTo=sys-subsystem-net-devices-%i.device
[Service]
Type=simple
ExecStart=/usr/sbin/hostapd /etc/hostapd/hostapd-%I.conf
[Install]
WantedBy=multi-user.target
Alias=multi-user.target.wants/hostapd@%I.service
Both services need to be enabled:
systemctl enable wpa_supplicant@sta0
systemctl enable hostapd@ap0
In any normal AP setup you will have a DHCP server running, and dnsmasq is easy to configure. The file /etc/dnsmasq.conf :
interface=ap0
dhcp-range=ap0,192.168.10.129,192.168.10.250,12h
You will also need files to configure wpa_supplicant and hostapd. There is nothing special about them, so I am not going to add them here.
Unfortunately I found it very fragmented instruction and using it wasn't able to set up my Rpi. Maybe for some Linux guru it is useful, but not for me. Will stick to Albert's version