Local Mesh (batman-adv)
Distributed Receive needs a way for two or three Ground Agents to find each other and exchange WFB-ng fragments without a central router. We use batman-adv (Better Approach To Mobile Ad-hoc Networking, advanced) - a Linux kernel mesh routing layer that has shipped with mainline since 2011. batman-adv handles every layer-2 routing decision: who can talk to whom, what the best path is when there are multiple hops, when a neighbor has gone silent, and which node should advertise the cloud uplink. It runs as a kernel module (modprobe batman-adv) and exposes a virtual bat0 interface that looks like an ordinary Ethernet bridge to userspace.
Why batman-adv
Three other options were on the table:| Option | Why we did not pick it |
|---|---|
| Ad-hoc IPv4 + manual routes | No self-healing, no auto-rejoin, fragile |
| ZeroTier or Tailscale (overlay VPN) | Requires public internet to bootstrap; fails in the field |
| Custom userspace router | Reinventing well-trodden ground; batman-adv has been in the kernel for 14 years |
The second USB WiFi dongle
batman-adv runs on a second USB WiFi dongle, separate from the RTL8812EU that handles WFB-ng to the drone. Two different dongles for two different jobs:| Dongle | Role | Default band |
|---|---|---|
| Primary RTL8812EU | WFB-ng monitor mode for the drone link | 5 GHz, channel 149 |
| Mesh carrier (any 802.11s/IBSS-capable dongle) | batman-adv mesh between Ground Agents | 2.4 GHz, channel 1 |
Carrier: 802.11s or IBSS
batman-adv carries traffic over either 802.11s (the IEEE mesh spec, with proper authentication via SAE) or IBSS (ad-hoc, no authentication, fallback for drivers that lack 802.11s support). The default is802.11s. Configurable in /etc/ados/config.yaml:
wpasupplicant-mesh-sae (or wpad-mesh-wolfssl) package, which the ground-station install path tries to pull in by default. If neither is available on your distro, fall back to IBSS by setting carrier: ibss.
Mesh ID and PSK
Two adjacent deployments on the same channel must not see each other’s traffic. batman-adv uses two pieces of identity:- mesh_id - a short string like
ados-XXXXXXXXXXshared by every node in the deployment. It becomes the 802.11s SSID (or IBSS name). - mesh_psk - a 32-byte shared key that authenticates 802.11s mesh peers via SAE.
device_id via SHA-256 truncation; the PSK is 32 random bytes from secrets.token_bytes(32) saved to /etc/ados/mesh/psk.key (mode 0600).
Relays do not generate these. They receive both as part of the encrypted invite bundle during pairing and write them into the same locations on disk.
What runs on the box
When a node transitions torelay or receiver role, the supervisor starts ados-batman.service, which runs the mesh_manager.py service. That service:
modprobe batman-adv- Brings the second USB WiFi dongle up in mesh or IBSS mode at the configured channel
- Joins the deployment by
mesh_idand authenticates with the shared PSK - Attaches the wireless interface to
bat0viabatctl if add - Brings
bat0up - Sets the gateway mode (
batctl gw_mode serverorgw_mode client) based on the node’s role and uplink state - Polls
batctl n -Handbatctl gwl -Hevery 2 seconds for neighbors and gateways - Publishes mesh state to
/run/ados/mesh-state.jsonso the REST API and the GCS can read it - Publishes
MeshEvents on the event bus when neighbors join or leave, when partition is detected, and when the selected gateway changes
Cloud gateway election
Any node on the mesh can carry an internet uplink (4G, Ethernet, WiFi client). batman-adv’s gateway election picks one node to advertise as the gateway and the rest of the mesh routes their cloud-bound traffic through it.mesh_manager enables gw server on a node when:
ground_station.cloud_uplink: force_on- OR
cloud_uplink: autoand/run/ados/uplink-activeexists (uplink_router has confirmed the node has a working uplink)
gw client and picks the highest-TQ gateway. When the active gateway dies, batman-adv evicts it within a few seconds and the next-best gateway takes over. The GCS Hardware tab Mesh sub-view shows the gateway list, their bandwidth class, their TQ, and which one is selected.
You can pin a specific gateway:
Diagnostics
mesh_manager service writes its working snapshot to /run/ados/mesh-state.json. The REST /api/v1/ground-station/mesh route reads from that file, not from batctl directly, so a fresh batctl query and a stale REST snapshot can disagree by up to 2 seconds (the poll interval).
Where to next
- Three Deployment Roles - direct, relay, receiver.
- Field Tap-to-Pair - how nodes get the mesh ID and PSK in the first place.
- Mesh Troubleshooting - when batman-adv does not come up.