Skip to content

Commit a25b030

Browse files
committed
New post: Show how to use mesh+roaming
This post show how to use the new features in the 26.06 release.
1 parent eba6590 commit a25b030

4 files changed

Lines changed: 431 additions & 0 deletions

File tree

_data/authors.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ troglobit:
33
url: https://troglobit.com
44
vatn:
55
name: Jon-Olov Vatn
6+
mattiaswal:
7+
name: Mattias Walström
8+
url: https://github.com/mattiaswal
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
---
2+
title: Seamless Wi-Fi with Mesh Backhaul and Roaming
3+
author: mattiaswal
4+
date: 2026-07-02 08:00:00 +0200
5+
categories: [howto]
6+
tags: [wifi, mesh, roaming, networking]
7+
image:
8+
path: /assets/img/wifi-mesh-roaming-hero.svg
9+
alt: Seamless Wi-Fi with 802.11s mesh backhaul and 802.11r/k/v fast roaming
10+
show_in_post: false
11+
---
12+
13+
Covering a building or a yard with Wi-Fi usually means several access
14+
points sharing one network name, so a laptop or a phone keeps working as
15+
it moves between them. Two problems show up quickly:
16+
17+
1. **Getting the network to every AP.** Pulling Ethernet to each AP is the
18+
reliable way, but it is not always possible. Where you cannot run a
19+
cable, a wireless backhaul has to carry the traffic instead.
20+
2. **Moving clients between APs without dropping them.** A client that has
21+
to fully re-authenticate every time it changes AP will stutter on voice
22+
calls and long downloads. Fast roaming closes that gap.
23+
24+
Infix [**v26.06**][release] adds both pieces: 802.11s mesh for the
25+
wireless backhaul, and 802.11r/k/v for fast roaming. Basic access point
26+
support arrived in v26.01; this release is what ties several APs into
27+
one network. The rest of this post builds a three-node network with
28+
them and explains why each part is configured the way it is. At the
29+
end we look at the automated test that verifies the setup.
30+
31+
The [Wi-Fi documentation][docs] has the reference material behind each
32+
setting: bands, channels, security modes, and the full list of roaming
33+
knobs. This post is the worked example.
34+
35+
## The design
36+
37+
Three nodes cover the area. Each node does two jobs at once, and that is
38+
why each one needs two radios:
39+
40+
- **radio0 (mesh backhaul).** All three nodes join one 802.11s mesh on
41+
5 GHz. The mesh carries traffic between the nodes, so only one node needs
42+
a wire back to the rest of the LAN. The others reach it over the air.
43+
- **radio1 (client access).** Each node runs an access point on 2.4 GHz
44+
with the same SSID and the same passphrase. This is the network clients
45+
actually see and roam across.
46+
47+
![Network topology](/assets/img/wifi-mesh-roaming-topology.svg){: width="800" }
48+
_Three nodes bridge a 5 GHz mesh backhaul and a 2.4 GHz roaming AP; only gw1 has a wire._
49+
50+
Keeping backhaul and access on different bands matters. If the mesh and
51+
the AP shared one radio they would also share one channel and take turns on
52+
the air, and every client frame would compete with backhaul traffic.
53+
Splitting them, 5 GHz for the mesh and 2.4 GHz for clients, lets both run
54+
at full tilt, and the wider 5 GHz channels suit the backhaul where the
55+
throughput adds up.
56+
57+
A bridge (`br0`) on each node ties the mesh interface, the AP interface,
58+
and (on the wired node) the uplink into one layer-2 segment. With mesh
59+
forwarding on, the mesh acts as a transparent backhaul: a client attached
60+
to gw3's AP sits on the same LAN as something plugged into gw1, and the
61+
frames cross the mesh without anyone configuring a route.
62+
63+
> A mesh point and an access point cannot share a radio; Infix rejects
64+
> that combination. Plan on two radios per node.
65+
{: .prompt-info }
66+
67+
## Building it
68+
69+
The three nodes are configured almost identically. Only gw1 carries the
70+
wired uplink; gw2 and gw3 are reachable purely over the mesh. The examples
71+
below show gw1 in full, then the one difference for the others.
72+
73+
### 1. The shared secrets
74+
75+
Every node needs two keystore entries: one passphrase for the mesh (all
76+
mesh links use WPA3-SAE) and one for the client AP. Use the same two
77+
secrets on all three nodes.
78+
79+
```console
80+
admin@gw1:/> configure
81+
admin@gw1:/config/> edit keystore symmetric-key mesh-secret
82+
admin@gw1:/config/keystore/.../mesh-secret/> set key-format passphrase-key-format
83+
admin@gw1:/config/keystore/.../mesh-secret/> change cleartext-symmetric-key
84+
Passphrase: ************
85+
Retype passphrase: ************
86+
admin@gw1:/config/keystore/.../mesh-secret/> end
87+
admin@gw1:/config/> edit keystore symmetric-key wifi-secret
88+
admin@gw1:/config/keystore/.../wifi-secret/> set key-format passphrase-key-format
89+
admin@gw1:/config/keystore/.../wifi-secret/> change cleartext-symmetric-key
90+
Passphrase: ************
91+
Retype passphrase: ************
92+
admin@gw1:/config/keystore/.../wifi-secret/> leave
93+
```
94+
95+
### 2. The radios
96+
97+
radio0 carries the mesh, so it needs a band, a channel, and a real country
98+
code. The mesh refuses to start without them. radio1 carries the AP on
99+
2.4 GHz.
100+
101+
```console
102+
admin@gw1:/> configure
103+
admin@gw1:/config/> edit hardware component radio0 wifi-radio
104+
admin@gw1:/config/hardware/component/radio0/wifi-radio/> set country-code SE
105+
admin@gw1:/config/hardware/component/radio0/wifi-radio/> set band 5GHz
106+
admin@gw1:/config/hardware/component/radio0/wifi-radio/> set channel 36
107+
admin@gw1:/config/hardware/component/radio0/wifi-radio/> end
108+
admin@gw1:/config/> edit hardware component radio1 wifi-radio
109+
admin@gw1:/config/hardware/component/radio1/wifi-radio/> set country-code SE
110+
admin@gw1:/config/hardware/component/radio1/wifi-radio/> set band 2.4GHz
111+
admin@gw1:/config/hardware/component/radio1/wifi-radio/> set channel 1
112+
admin@gw1:/config/hardware/component/radio1/wifi-radio/> leave
113+
```
114+
115+
All three nodes use the same mesh channel (36), since mesh peers must meet
116+
on one channel, and the same AP channel (1), so a roaming client does not
117+
have to change channel as it moves.
118+
119+
### 3. The mesh interface
120+
121+
`wifi0` rides on radio0 as the 802.11s mesh point. The `mesh-id` is the
122+
mesh equivalent of an SSID: every node that should join uses the same one.
123+
Leaving `forwarding` at its default (`true`) is what lets the mesh be
124+
bridged.
125+
126+
```console
127+
admin@gw1:/config/> edit interface wifi0
128+
admin@gw1:/config/interface/wifi0/> set wifi radio radio0
129+
admin@gw1:/config/interface/wifi0/> set wifi mesh-point mesh-id backhaul
130+
admin@gw1:/config/interface/wifi0/> set wifi mesh-point security secret mesh-secret
131+
admin@gw1:/config/interface/wifi0/> leave
132+
```
133+
134+
### 4. The access point, with roaming
135+
136+
`wifi1` rides on radio1 as the client-facing AP. The roaming settings are
137+
the point of this step. All three APs must agree on the SSID, the
138+
passphrase, and the mobility domain. That trio is what tells a client the
139+
three APs are one roaming network rather than three unrelated ones.
140+
141+
Using `mobility-domain hash` derives the domain from the SSID, so the three
142+
APs land on the same domain without anyone copying a hex value around.
143+
144+
```console
145+
admin@gw1:/config/> edit interface wifi1
146+
admin@gw1:/config/interface/wifi1/> set wifi radio radio1
147+
admin@gw1:/config/interface/wifi1/> set wifi access-point ssid campus
148+
admin@gw1:/config/interface/wifi1/> set wifi access-point security mode wpa2-wpa3-personal
149+
admin@gw1:/config/interface/wifi1/> set wifi access-point security secret wifi-secret
150+
admin@gw1:/config/interface/wifi1/> set wifi access-point roaming dot11r
151+
admin@gw1:/config/interface/wifi1/> set wifi access-point roaming dot11r mobility-domain hash
152+
admin@gw1:/config/interface/wifi1/> set wifi access-point roaming dot11k
153+
admin@gw1:/config/interface/wifi1/> set wifi access-point roaming dot11v
154+
admin@gw1:/config/interface/wifi1/> leave
155+
```
156+
157+
The three roaming features do different jobs:
158+
159+
- **dot11r** (Fast BSS Transition) is the one that makes the handoff quick.
160+
It pre-shares the keys so a roaming client skips the full WPA handshake,
161+
cutting the gap from roughly a second to under 50 ms.
162+
- **dot11k** (Radio Resource Management) hands the client a neighbour list,
163+
so it already knows which APs to look at instead of scanning blindly.
164+
- **dot11v** (BSS Transition Management) lets an AP nudge a client toward a
165+
better one.
166+
167+
### 5. The bridge
168+
169+
`br0` joins the mesh and the AP into one segment. On gw1 the wired uplink
170+
joins too, which is what gives the other nodes a path to the rest of the
171+
LAN.
172+
173+
```console
174+
admin@gw1:/config/> edit interface br0
175+
admin@gw1:/config/interface/br0/> set type bridge
176+
admin@gw1:/config/interface/br0/> end
177+
admin@gw1:/config/> set interface wifi0 bridge-port bridge br0
178+
admin@gw1:/config/> set interface wifi1 bridge-port bridge br0
179+
admin@gw1:/config/> set interface eth0 bridge-port bridge br0
180+
admin@gw1:/config/> leave
181+
```
182+
183+
gw2 and gw3 are identical except they have no wired uplink, so drop the
184+
`eth0` line. Their br0 carries only `wifi0` (mesh) and `wifi1` (AP), and
185+
they reach the LAN over the mesh.
186+
187+
## Checking it works
188+
189+
**Did the mesh form?** Each node should list the other two as peers:
190+
191+
```console
192+
admin@gw1:/> show interface wifi0
193+
...
194+
mode : mesh-point
195+
mesh id : backhaul
196+
peers : 2
197+
```
198+
199+
**Is a client associated, and where?** The AP lists the clients on it. As
200+
a client roams, it disappears from one node's list and shows up on another:
201+
202+
```console
203+
admin@gw2:/> show interface wifi1
204+
...
205+
mode : access-point
206+
ssid : campus
207+
stations : 1
208+
```
209+
210+
**Does traffic actually cross the mesh?** Attach a client to gw3's AP (the
211+
node with no wire) and reach something on the wired LAN behind gw1. If
212+
that works, the mesh is carrying the traffic.
213+
214+
## How we keep it working
215+
216+
A worked example that only ever ran by hand tends to rot. This one has an
217+
automated counterpart in the Infix regression test suite:
218+
219+
test/case/interfaces/wifi_mesh_roaming/
220+
221+
It brings up three nodes exactly as above (mesh backhaul on radio0, a
222+
roaming AP on radio1, all bridged) plus a fourth node as the client. It
223+
then checks the claims this post makes:
224+
225+
- the three nodes form a mesh (each sees its peers);
226+
- a client associates to the `campus` SSID;
227+
- traffic reaches the client across the mesh backhaul;
228+
- when the AP the client is on goes away, the client roams to another node
229+
carrying the same SSID and mobility domain, and traffic recovers.
230+
231+
In simulation every radio hears every other at the same strength, so there
232+
is no signal gradient to drift a client from one AP to the next. The test
233+
forces the move instead. It takes down the AP the client is on and
234+
confirms the client lands on another one and keeps talking. That is a
235+
harsher check than a gentle signal-based drift: it proves the second AP
236+
accepts the client and the backhaul re-converges, with no human in the
237+
loop.
238+
239+
The virtual radios are `mac80211_hwsim`, and a small relay, `wifimedium`,
240+
carries frames between the separate guests so they can hear each other.
241+
On real hardware none of that exists. The radios use the air, and the
242+
same configuration applies unchanged.
243+
244+
[docs]: https://kernelkit.org/infix/latest/wifi/
245+
[release]: https://github.com/kernelkit/infix/releases/tag/v26.06.0
Lines changed: 96 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)