wifibroadcast is a Linux/Nerves-only Elixir rewrite of
wfb-ng.
It keeps the WFB link packet-oriented and low-latency, but expresses the data path as a Membrane pipeline so the individual stages are explicit and easier to reason about, inspect, test, compose, and extend.
This project is intended to interoperate with wfb-ng where compatibility
matters, while moving the RX/TX path, radio control, and key handling into
Elixir.
wfb-ng is a long-range packet radio link
built on raw WiFi monitor-mode transport. This project follows the same core
ideas and keeps compatibility with the upstream ecosystem in the places that
matter for packet exchange.
Important upstream ideas that this project keeps:
- packet-oriented transport instead of byte-stream framing, for lower latency
- raw IEEE 802.11 monitor-mode RX/TX
- forward error correction (FEC)
- SIMD-accelerated native FEC where available
- libsodium-based stream encryption and authentication
- Linux traffic shaping / packet marking support
drone.key/gs.keycompatibility with existingwfb-ngsetups
This project is not a full clone of the entire wfb-ng operational stack. It
focuses on the core RX/TX data path, packet processing, key handling, and radio
control in Elixir.
For the broader wfb-ng ecosystem, upstream docs are still the best reference:
- Upstream repository: https://github.com/svpcom/wfb-ng
- Upstream wiki: https://github.com/svpcom/wfb-ng/wiki
One of the main goals of this project is to make the WFB link easier to reason about.
Instead of treating RX and TX as opaque binaries, wifibroadcast models the
link as explicit pipeline stages. That makes it easier to see, test, and modify
what happens at each step:
- radio capture / injection
- radiotap parsing
- WFB packet routing
- decrypt / encrypt
- FEC decode / encode
- payload unwrap / wrap
In practice, that means the RX/TX path is easier to debug, easier to compose with other Elixir components, and easier to swap or extend parts of the chain.
- Linux / Nerves only
- monitor-mode capable WiFi hardware
libsodiumdevelopment headers and library available at build time- a working C toolchain for Bundlex native compilation
cap_net_adminandcap_net_rawonbeam.smp, orsudo, for raw radio control andAF_PACKETRX/TX
Install native build dependencies:
sudo pacman -S --needed base-devel libsodiumsudo dnf install -y gcc make libsodium-develsudo apt-get update
sudo apt-get install -y build-essential libsodium-devThis package targets the same raw WiFi monitor-mode world as wfb-ng, so
hardware and driver quality matter a lot.
Current radio control behavior is aligned with the wfb-ng ecosystem,
especially for:
rtl8812aurtl8812eu
If you are using those chipsets, follow the upstream driver guidance:
If you only need RX, any monitor-mode capable card may work for capture, but TX behavior depends heavily on driver support and monitor-mode injection quality.
Add wifibroadcast to your dependencies:
defp deps do
[
{:wifibroadcast, "~> 0.1.0"}
]
endThen fetch dependencies:
mix deps.getwifibroadcast is intended to receive traffic sent by wfb-ng and to transmit
traffic that wfb-ng can receive.
Current compatibility-related behavior includes:
drone.key/gs.keyfile layout compatible withwfb-ng- password-derived key generation compatible with
wfb-ng - driver-specific TX power handling aligned with
wfb-ngconventions forrtl8812auandrtl8812eu - raw monitor-mode packet handling built around the same WFB packet model
This package intentionally does not claim to replace every higher-level
wfb-ng operational feature such as system images, service layout, telemetry
tooling, IP tunnel management, or OSD components.
The RX side is built from Membrane elements and runs on real monitor-mode hardware:
Wifibroadcast.Membrane.Radio.Sourcecaptures monitor-mode traffic in pure Elixir viaAF_PACKET, applies WFB ingress filtering, and routes packets bylink_idandradio_portWifibroadcast.Radiotap.Parserdecodes radiotap metadata intobuffer.metadataWifibroadcast.Membrane.WFB.Decryptdecrypts WFB session/data packet payloads while preserving the packet contractWifibroadcast.Membrane.WFB.FecDecoderaccepts session/data packets, performs FEC recovery, and emits ordered source shards
The TX side has the matching Membrane stages needed to build a WFB transmit path:
Wifibroadcast.Membrane.WFB.PayloadWrapwraps packetized payloads intowpacket_hdr_t <> payloadWifibroadcast.Membrane.WFB.FecEncodergroups wrapped payloads into source/parity shards and emits session/data packetsWifibroadcast.Membrane.WFB.Encryptoptionally encrypts the session/data packet payloads without changing the packet contractWifibroadcast.Membrane.Radio.Sinkfans in multipleradio_portbranches, adds radiotap + 802.11 + outer WFB headers, and injects frames throughAF_PACKET
Radio.Sink defaults to low-latency injection with qdisc bypass enabled. If
you want Linux traffic control to classify TX packets, set use_qdisc?: true
and a fwmark_base. In that mode:
- source data packets and session packets use
fwmark_base - parity packets use
fwmark_base + 1
See examples/README.md for a TX pipeline snippet.
Wifibroadcast.generate_wfb_keys/1 writes the standard drone.key and
gs.key files in the current working directory.
Generate random keys:
iex -S mixWifibroadcast.generate_wfb_keys()Generate password-derived keys that stay compatible with wfb-ng:
Wifibroadcast.generate_wfb_keys("shared-password")The resulting files use the same layout expected by the Encrypt and Decrypt
stages.
Wifibroadcast.Radio.Control uses pure-Elixir rtnetlink and nl80211 calls.
That includes:
- interface up/down changes
- monitor-mode changes
- regulatory region changes
- channel and frequency changes
- TX power changes
Example:
Wifibroadcast.Radio.Control.set_region("BO")
Wifibroadcast.set_card_monitor_mode("wlan0")
Wifibroadcast.Radio.Control.set_frequency("wlan0", 5825, 20)
Wifibroadcast.set_card_tx_power("wlan0", :rtl8812au, 30)If you want to switch monitor mode, change channel or frequency, set TX power,
and use raw packet RX/TX without starting the whole VM as root, grant Linux
file capabilities to the actual Erlang VM executable: beam.smp.
What the capabilities do:
cap_net_adminlets the BEAM perform the network-admin operations used here, including link up/down, monitor mode, regulatory changes, channel or frequency changes, TX power changes, and socket options such asSO_MARKcap_net_rawlets the BEAM open raw andAF_PACKETsockets for radio RX/TX
What setcap changes:
setcapwrites file capabilities onto thebeam.smpexecutable itself; it does not modify this project- every
iex,mix, release, or Erlang node started from that exactbeam.smppath gets those capabilities when it starts - any code running inside those VMs can use them; the capabilities are not
scoped to
wifibroadcast - if you use the same Erlang installation for unrelated work, those BEAM workloads also get the same network privileges
- other Erlang installations are unaffected unless you run
setcapon theirbeam.smptoo
For the smallest blast radius, prefer a dedicated Erlang installation or runtime for radio work.
Grant the capabilities once per Erlang installation:
erl_path="$(realpath "$(which erl)")"
beam_path="$(realpath "$(dirname "$erl_path")"/../erts-*/bin/beam.smp)"
sudo setcap 'cap_net_admin,cap_net_raw+ep' "$beam_path"
getcap "$beam_path"erl_path="$(realpath "$(which erl)")"
beam_path="$(realpath "$(dirname "$erl_path")"/../erts-*/bin/beam.smp)"
sudo setcap 'cap_net_admin,cap_net_raw+ep' "$beam_path"
getcap "$beam_path"set erl_path (realpath (which erl))
set beam_path (realpath (dirname $erl_path)/../erts-*/bin/beam.smp)
sudo setcap 'cap_net_admin,cap_net_raw+ep' $beam_path
getcap $beam_pathTo remove the capabilities later, rerun the matching beam_path snippet above
and then:
sudo setcap -r "$beam_path"Notes:
- rerun
setcapafter upgrading Erlang/OTP, because a newbeam.smpbinary replaces the old one - the capability change applies only to the resolved
beam.smp; if you have multiple Erlang installs, other installs are unaffected - if you do not want to grant capabilities to
beam.smp, running the examples withsudostill works as a fallback
Runnable smoke examples live in examples/README.md:
examples/radio_smoke.exsexamples/wfb_decrypt_smoke.exsexamples/wfb_fec_decoder_smoke.exs
These are intended for step-by-step validation on real Linux / Nerves hardware.
This project is directly inspired by and intentionally interoperates with
wfb-ng. Credit goes to the upstream
authors and maintainers for the original WFB tooling, protocol conventions,
hardware knowledge, and ecosystem documentation that this rewrite builds on.