Individual per-passphrase Wifi VLANs using wpa_psk_file (no RADIUS required)

After a lot of fiddling and trial-and-error I found the problem: The default hostapd provided by wpad-basic is not enough, one needs the fully featured hostapd or wpad. This is not immediately obvious because the stripped down default one fails silently for most of the relevant options, with the exception of vlan_tagged_interface which it rejects violently.

So for posterity, here's my recipe for a dumb AP, and per-passphrase VLAN segmentation of clients:

First of all, the default wpad-basic will not suffice. We need a fully featured hostapd, either installed on its own or as part of the non-basic wpad:

# remove the default stripped-down wpad containing a stripped-down hostapd:
opkg remove wpad-basic-wolfssl
# removing the package does not kill the process, we need to manually do that:
killall hostapd
# install a fully-featured wpad containing a fully-featured hostapd:
opkg install wpad-wolfssl

For a single tagged ethernet port connecting to the router upstream, in /etc/config/network no changes are necessary. Especially it's not necessary to create custom bridges or interfaces. All of that will be done by hostapd at startup.

/etc/config/wireless needs the following options for the relevant wifi-iface:

        option wpa_psk_file '/etc/hostapd.wpa_psk'
        option vlan_file '/etc/hostapd.vlan'
        option vlan_tagged_interface 'eth0'
        option vlan_bridge 'br-vlan'
        option dynamic_vlan '1'

Of note: vlan_tagged_interface and vlan_bridge are prefixes to which the VLAN ID will be appended.

/etc/hostapd.wpa_psk needs to specify which passphrase should be go into which VLAN ID (in this example, clients connecting with the passphrase "supersecret" will go into VLAN ID 101):

vlanid=101 00:00:00:00:00:00 supersecret

/etc/hostapd.vlan needs to specify the wifi interface created for each (possible) VLAN ID. This can be named anything, but for consistency I choose to name it like a VLAN-tagged interface:

101 wlan0.101

This will result in:

  • creation of the wifi interface wlan0.101 as specified in /etc/hostapd.vlan
  • creation of the eth0.101 interface as specified by the vlan_tagged_interface prefix plus a dot and the VLAN ID, conveniently automatically tagging VLAN ID 101 on eth0
  • creation of the br-vlan101 bridge as specified by the vlan_bridge prefix plus the VLAN ID, with the previous two interfaces in it
root@OpenWrt:~# brctl show
bridge name     bridge id               STP enabled     interfaces
br-vlan101              8000.4018b1eb3c80       no              wlan0.101
br-lan          7fff.4018b1eb3c80       no              eth0

It may get a little bit more complicated if the outgoing interface should not be a singular tagged ethernet port but a bridge. In this case one would probably have to, in network config, create a bridge named something like br-vlan.101 containing the tagged ethernet ports and then use br-vlan as the vlan_tagged_interface prefix option. I haven't tried that yet because I have no need for that, but I don't see why it shouldn't work.