BLE-provisioned network configuration for headless embedded Linux. A systemd
service (netprovd) advertises a GATT service that a paired client can use to
list interfaces, read IP configuration, scan Wi-Fi, and set DHCP / static IPv4
/ Wi-Fi credentials. Written in Rust, talks to NetworkManager over D-Bus.
The companion netprov CLI speaks the same protocol over TCP (loopback, for
dev) or BLE (for production).
flowchart TD
Client["BLE client (netprov CLI)"]
NM["NetworkManager (system)"]
subgraph Daemon["netprovd (systemd service, runs as root)"]
direction LR
GATT["BLE GATT Server"]
Session["Auth & Session"]
Facade["Network Facade"]
GATT --> Session --> Facade
end
Client -->|"GATT over LE (bonded + app-layer HMAC auth)"| GATT
Facade -->|D-Bus| NM
Three Rust crates in one workspace:
| Crate | Role |
|---|---|
netprov-protocol |
Wire format: CBOR messages, framing, HMAC auth helpers. Transport-agnostic. |
netprov-server |
netprovd daemon. BLE GATT driver, session state machine, NetworkFacade (mock + nmrs). |
netprov-client |
netprov CLI. Connects over BLE (via --ble-peer) or TCP behind the dev-tcp feature. |
Builds for amd64 and aarch64 are produced by CI as artifacts. On a target
box:
sudo dpkg -i netprov_0.1.0-1_arm64.deb
sudo netprovd keygen --install # generate and install a production PSK
sudo systemctl enable --now netprovd # start at boot + nowThe deb does not auto-start — the admin must install a production key first.
Running with the embedded dev key (the committed PSK under packaging/) logs
a loud warning every 60 seconds.
NETPROV_PRODUCTION=1 in the unit's environment disables the dev-key
fallback; the service refuses to start without a real key at
/etc/netprov/key.
The full request/response surface is exercised end-to-end over TCP against an
in-memory MockFacade:
# one terminal
cp packaging/dev-key.bin /tmp/netprov-key.bin && chmod 600 /tmp/netprov-key.bin
cargo run -p netprov-server --bin netprovd -- serve-tcp --listen 127.0.0.1:9600
# another terminal
cargo run -p netprov-client --features dev-tcp --bin netprov -- \
--key-path /tmp/netprov-key.bin --endpoint 127.0.0.1:9600 listlist, ip <iface>, wifi-status, wifi-scan, wifi-connect, set-dhcp,
set-static all work against the mock.
See packaging/SMOKE-TEST.md for the two-box
hardware-in-the-loop runbook.
cargo test --workspace # default: no BLE, no NM
cargo build -p netprov-server --features live-ble # + BLE GATT server
cargo build -p netprov-server --features live-nm # + real NetworkManager
cargo deb -p netprov-server # build the .deblive-ble implies live-nm (production BLE needs NM). live-nm-destructive
gates the mutating NmrsFacade integration tests that are unsafe to run in
CI.
The Dioxus desktop app is gated behind the desktop feature because it needs
native GTK/WebKit development libraries on Linux. On Ubuntu/Debian:
sudo apt-get install -y \
pkg-config \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libayatana-appindicator3-dev \
libxdo-devThen run the BLE-first desktop app with:
cargo run -p netprov-app --features desktopThe app talks to target devices over BLE; the TCP transport remains a dev/test path for protocol regression coverage.
| Tier | In CI? | Covers |
|---|---|---|
| Unit tests | Yes | Protocol: CBOR round-trips, framing, HMAC, bounded strings. Plus proptests. |
| Session-layer | Yes | Session state machine against MockFacade. |
| Client↔server loopback | Yes | Full request/response surface via tokio::io::duplex. |
| Live NetworkManager | Opt-in | --features live-nm -- --ignored. Requires NM on the system bus. |
| Live BLE e2e | Opt-in | --features live-ble + two BLE-equipped boxes. |
- Design spec
- Part 1 plan — protocol, session, mock facade, loopback
- Part 2 plan — BLE GATT, systemd, NmrsFacade, cargo-deb, CI
MIT OR Apache-2.0.