How does 802.11r actually work?
In a given roaming connection, there are 3 keys:
- Master Session Key (MSK).
- R0, a key derived from the MSK.
- R1, a key derived from R0.
There are 3 players:
- The client.
- R0KH, the R0 Key Handler, may or may not be an AP.
- R1KH, the R1 Key Handler, an AP.
In "pull mode":
1. The client connects to the first AP.
2. The client is given a key and an R0KH-ID (the _NAS Identifier_, named for [RADIUS'](https://en.wikipedia.org/wiki/RADIUS) [Network Access Server](https://en.wikipedia.org/wiki/Network_access_server)).
3. The client connects to the second AP.
4. The client gives R0KH-ID to the second AP.
5. The second AP, now R1KH, contacts R0KH using the ID and its own R1KH-ID.
6. R0KH sends R1KH a key R1 derived from R0 and R1KH-ID.
7. R1KH, gives the client R1.
In "push mode":
1. R0KH knows all its APs.
2. R0KH sends each AP a unique R1 derived from R0 and the AP's R1KH-ID.
3. the client connects normally.
For PSK mode, the MSK is the PSK, so any AP can generate R0 and R1 for any NAS Identifier.
## Router configuration { #router }
My router is a [PC Engines APU 1d4](https://www.pcengines.ch/apu1d4.htm), which has:
- 3 ethernet ports.
- 1 wifi card.
One of the ethernet ports is for WAN, and the other two and wifi card are LAN.
The LAN interfaces are joined with a bridge, `br0`.
### WAN { #router/wan }
This is a fairly normal [`systemd-networkd`](https://wiki.archlinux.org/index.php/Systemd-networkd) client config, with the addition of `IPForward=yes`:
{{ file( configs.router, '/etc/systemd/network/wan.network' ) }}
### LAN { #router/lan }
The LAN is controlled with `systemd-networkd` where possible, and the wifi is managed by `hostapd`.
There are three parts to the `networkd` configuration:
- Create a bridge network device.
- Connect the LAN ethernet ports to it.
- Configure the bridge to be a DHCP server & NAT gateway.
First, create a bridge `br0`:
{{ file( configs.router, '/etc/systemd/network/bridge.netdev' ) }}
Connect the LAN ethernet ports to the bridge:
{{ file( configs.router, '/etc/systemd/network/lan.network' ) }}
Finally, configure the local network on the bridge itself.
- `systemd-networkd` includes a minimal DHCP server, so also enable that.
- Note the addition of both `IPForward=yes` and `IPMasquerade=yes` to set up NAT.
{{ file( configs.router, '/etc/systemd/network/bridge.network' ) }}
### WiFi { #router/wifi }
Because `hostapd` has its own bridge management, it isn't included in the `systemd-networkd` configuration.
This configuration:
- Uses our bridge `br0`.
- Uses the standard Linux WiFi driver set (others exist for other chipsets).
- Automatically selects a channel at start.
- Enables 802.11n (`hostapd` also supports 802.11ac).
- Enables WPA2 with a Pre-Shared Key (PSK).
- Enables pre-authentication (802.11i) on our bridge `br0`.
- Enables roaming (802.11r):
- `nas_identifier` must be 6 bytes, and different between APs. I use the interface MAC.
- `mobility_domain` must be 2 bytes, and is shared between APs.
{{ file( configs.shared, '/etc/hostapd/hostapd.conf' ) }}
## Kitchen
The WiFi in the kitchen is provided by a [Raspberry Pi 2B](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/) and a USB WiFi adapter that supports _host mode_.
I chose this hardware because I already owned it.
### LAN { #kitchen/lan }
This is a simpler version of the [Router's LAN configuration](#router/lan), but with only two steps:
- Create a bridge network device.
- Connect the LAN ethernet ports to it.
As before, create a bridge `br0`:
{{ file( configs.bouncer, '/etc/systemd/network/bridge.netdev' ) }}
Connect the ethernet port to the bridge:
{{ file( configs.bouncer, '/etc/systemd/network/wired.network' ) }}
Configure the local network on the bridge itself.
Because this is not the primary router, it can be just another DHCP client:
{{ file( configs.bouncer, '/etc/systemd/network/bridge.network' ) }}
### WiFi { #kitchen/wifi }
This is basically the same as the [Router's WiFi configuration](#router/wifi), although remember to change the `nas_identifier`!
{% endmarkdown %}