Releases: and-elf/omm
Releases · and-elf/omm
Release list
v0.5.0
Added
- Topology clients labelled by hostname/IP, not MAC (#35). The topology view
showed each associated client as a raw MAC, which is poor UX.GET /topology
now enriches clients with their DHCP-assignedipandhostname, resolved on
the controller from dnsmasq's lease file (/tmp/dhcp.leases) — a member node
is a bridged dumb AP and holds no leases, so resolution happens where the merged
graph is served. The view labels a client by hostname, falling back to IP, then
the MAC when neither resolved; the MAC and IP are kept on the node's data. A
client with no lease (static, self-addressed, or transient) renders by MAC as
before. - Any ethernet jack just works on a non-controller node (#42). A satellite's
wan jack was a dead routed wan: only its lan jack(s) carried clients or extended
the network, so plugging a computer — or another node — into the wan jack did
nothing. On a non-controller node the network posture now folds every
ethernet jack (incl. the wan jack,network.wan.device) intobr-lanas a plain
bridge relay port and stands the routed wan down, so any device works on any
port with zero configuration. A controller keeps its wan jack as the routed
internet uplink. - Dual-band / multi-band client AP (#36). A claimed home previously
broadcast its client AP on a single radio (typically 5 GHz), so 2.4 GHz-only
devices had no AP to join.ApplyProfilenow authors the client AP across
multiple bands: the primaryomm_apstays on theradio/band-resolved
radio, and each band in the newap_bandsprofile field ("2g"/"5g"/"6g")
resolves to that node's matching radio, authored asomm_ap_<band>(e.g.
omm_ap_2g, coexisting withomm_meshon the same 2.4 GHz radio/channel).
Emptyap_bandsdefaults to also broadcasting on 2.4 GHz, so every home gets a
dual-band AP with no configuration; set a single band (e.g.["5g"]) to opt
out. Bands absent on a node are skipped (not fatal), and narrowingap_bands
prunes the now-staleomm_ap_<band>sections on re-apply. - Xiaomi AX3600 as a build/deploy target.
build-devices.shgains an
ax3600label anddeploy.shrecognises it. The board is a Qualcomm IPQ8071A
(qualcommax/ipq807x, Cortex-A53) — the sameaarch64_cortex-a53ISA group as
the ZB8103AX, so the release feed's arm64 package already covered it; this just
makes the local dev tooling first-class for it. Because two boards now share
one ISA,deploy.shdisambiguates byboard_name(xiaomi,ax3600) before
falling back touname -m. No profile changes were needed: the mesh radio is
auto-selected by band, which picks the AX3600's 2.4 GHz radio (radio2).
Changed
- Backhaul model: wired is primary, the mesh is a carrier-loss backup. The
short-lived "batman-always-on, per-port enslavement" model (which routed a wired
node over the wireless mesh and broke ethernet clients in a mixed
wired+wireless bridge) is replaced by the failover model: every ethernet port is
a plainbr-lanrelay, and the 802.11s mesh + batman-adv is authored as a
standby that the daemon's carrier-toggle failover brings up only when the
wired uplink loses carrier (and tears back down when the wire returns) — so the
fast wire is always preferred and wired + mesh never bridge-loop. The uplink port
to watch is auto-detected (the bridge port through which the node reaches its
gateway, so any jack works) or set viauplink_port. Wired ports are enslaved to
batman only via an explicitbatman_ports; batman still forwards the mesh
loop-free multi-hop when it activates. Restoresinternal/backhaul(the switch
loop) and removes the per-port beacon classifier (PortScan/SniffOMMBeacon/
Classify). - Network posture management now defaults ON (
manage_network, opt-out).
Making a wan jack usable as a client/backhaul port physically requires standing
down its routed role first — a netdev cannot be bothnetwork.wan's device and
abr-lanmember, and a satellite that keeps its own DHCP/gateway becomes a
rogue DHCP server on the home segment. That bridged dumb-AP posture used to sit
behindmanage_network=0, so #42 could not be delivered without it. The flag
now defaults to1: a non-controller stands down its routed wan and every
ethernet jack joins the home L2, while a controller keeps the stock routed-wan
gateway (never disrupted). Setmanage_network=0to opt out entirely on a
device you hand-wire and do not want meshd to reconfigure. - Mesh-node network posture now bridges into the home (single gateway). A
claimed satellite (manage_network=1) previously only stood down its
authoritative DHCP, leaving its own routed/NAT'dwanup — so its bridged
802.11s mesh was an island and mesh traffic could not reach the home WAN, which
egresses only through the controller's gateway over the mesh. The Mesh-node
posture now authors the same bridged shape as Guest: it folds every ethernet
jack (incl. the wan jack) intobr-lanas a plain relay,lanbecomes a DHCP
client, the routedwan/wan6are disabled, and authoritative DHCP is stood
down, so the node is a pure L2 bridge into the home and its default route points
at the controller. The 802.11s mesh stays a carrier-loss backhaul standby (see
the backhaul-model change above), so wired + mesh never bridge-loop. Verified
end-to-end on hardware: reset → wired auto-onboard → mesh-node, pulling the real
home profile.
v0.4.0
What's Changed
- Per-device cross-build wrapper + 802.11s mesh / wired multi-AP docs by @and-elf in #15
- 802.11s auto-fallback to multi-AP + per-node backhaul in LuCI by @and-elf in #16
- Lifecycle-managed network posture (Guest dumb-AP so discovery works) by @and-elf in #17
- Discovery/enrollment fixes + zero-config wired onboarding by @and-elf in #18
- docs(changelog): record unreleased onboarding/network/discovery changes by @and-elf in #19
- Zero-touch defaults + mesh-capable wpad provisioning by @and-elf in #20
- fix(config): default identity dir to an absolute path by @and-elf in #22
- feat(meshd): auto-propagate controller profile edits to joined nodes by @and-elf in #21
- feat(profiles): host the 802.11s mesh on a dedicated backhaul radio by @and-elf in #23
- fix: a configured node actually joins its controller on boot; failover reconciles mesh state by @and-elf in #25
- feat(backhaul): prioritize ethernet, fail over to the wireless mesh by @and-elf in #24
- feat(backhaul): batman-adv multi-hop routing (#26) by @and-elf in #30
- fix(topology): connect real nodes with typed links in the topology view by @and-elf in #31
- feat(topology): surface onboarded-but-silent nodes in the graph (#29) by @and-elf in #32
- Fix topology view (wired links, clients, LuCI) and add node removal by @and-elf in #33
- feat(web): adopt the LuCI host theme when embedded in an iframe by @and-elf in #34
Full Changelog: v0.3.0...v0.4.0
v0.3.0
Added
- Backhaul connection type in the topology graph. Each node now reports how
it reaches the mesh — over a wired ethernet uplink or the wireless mesh —
derived from a configured uplink interface under/sys/class/net
(carrier/operstate). The value rides on the node'sselfvertex, is
preserved by the controller-side aggregator when that node is merged into the
mesh-wide graph, and surfaces as abackhaulfield on a topology node; the
Topology view marks wired nodes with a solid border and wireless with a dashed
one. Set the uplink interface withMESHD_BACKHAUL_IFACE(UCIbackhaul_iface);
empty =>unknown. Newinternal/topology/backhaul.go. - Status LED reflecting onboarding state.
meshdnow drives a node's status
LED from its onboarding state so an installer can read it off the device
without a companion app: blinking while unclaimed, a heartbeat while it joins,
solid once a home is active. The LED is the kernel sysfs LED named by
MESHD_LED_NAME(UCIled_name, defaultgreen:status); a board lacking that
LED is a graceful no-op, so the same build runs unchanged across hardware. Set
MESHD_LED=0(UCIled_enabled '0') to leave the LED alone. New
internal/deviceledpackage. - Wired auto-onboard. An unclaimed node that is on the wire (ethernet
backhaul) can now enroll into a discovered controller unattended, with no setup
wizard: when it is still unclaimed, its ethernet uplink is up, and a controller
other than its own Home has been discovered, it joins (the lowest discovered
home_id, chosen deterministically), applies the returned profile, marks setup
complete and tears down the first-boot setup AP. Opt-in via
MESHD_AUTO_ONBOARD_WIRED(UCIauto_onboard_wired, default off); requires
MESHD_BACKHAUL_IFACEto be set, runs only when no explicitMESHD_JOIN
controllers are configured, and completes unattended only when the controller
auto-adopts. Newinternal/onboardpackage.
v0.2.0
Added
- First-boot setup access point. While a device is unclaimed (setup not
complete)meshdnow brings up a known, label-printable WiFi AP
(OMM-Setup-<last4-of-node-id>) on a small static network
(192.168.254.1/24) serving its open management API, so a companion app can
reach an out-of-the-box node before it has joined any network. The AP is torn
down automatically once onboarding completes. Open by default; set
MESHD_SETUP_AP_KEYfor WPA2,MESHD_SETUP_AP_RADIOto choose the radio, or
MESHD_SETUP_AP=0to disable (e.g. a radio-less wired controller). New
internal/setupappackage;uci.ClientgainedSetSection/Delete. Covered
by a real-OpenWrt-container e2e (TestSetupAPLifecycleE2E) asserting the uci
sections appear on boot and are removed once onboarding completes. - Companion onboarding app. The Vue frontend now also builds as a
cross-platform companion app (Capacitor: Android/iOS/desktop), whose first goal
is to make adding a node a few-tap flow. It discovers controllers on the LAN
(native mDNS_mesh._tcp, falling back to the daemon's/scan), can target a
specific device over the LAN (an unclaimed node's setup-AP address or a
controller's announced URL), and guides adding a node end to end (/onboard):
read the device's setup label (QR — OMM-JSON, theWIFI:standard, or a bare
SSID), join its setup AP, reach it, request enrollment (/enroll/join), and
confirm adoption — including signing in to a split-mode controller (LuCI
session.loginover/ubus) when its management API is localhost-bound. The
native capabilities (mDNS / WiFi-join / QR scan) sit behind a bridge that is a
no-op in the browser, so the existing PWA is unchanged. See the design spec in
doc/companion-app.md. - Guided onboarding wizard + wireless-only enrollment. The onboarding flow is
now a three-page wizard — choose Home → choose device → confirm — that
auto-progresses between steps and adopts the node in the background once the
app holds a controller client, with no manual approve step. A node without an
Ethernet uplink can now be enrolled over WiFi:meshdgains
POST /setup/uplink(unclaimed devices only) which brings up a station
wifi-iface+ DHCP-client network from supplied home-WiFi credentials so the
node can reach its controller, torn down with the setup AP once onboarding
completes (internal/setupapEnableUplink). On Android the wizard offers a
setup-AP picker (OMM-Setup-*); iOS/web keep the QR/manual path. Covered by a
real-OpenWrt-container e2e (TestSetupUplinkE2E). See §13–§14 of
doc/companion-app.md. - Companion-app local dev workflow.
scripts/run-dev-stack.shplus a Vite
dev-server proxy for all meshd REST endpoints make it possible to drive the
companion app against a localmeshdfor manual enrollment testing.
MESHD_DEV_CORS(development only) lets a cross-origin app call the management
API directly, logging a warning when enabled. The onboarding wizard can also
target an explicit node URL (e.g. a wired node) instead of the setup-AP default. - Companion app packaging. The frontend now builds as native Android/iOS apps
(Capacitor) with the QR (@capacitor-mlkit/barcode-scanning) and WiFi-join
(@falconeta/capacitor-wifi-connect) plugins wired in; desktop ships as the
installable PWA. Native platform projects are generated on a dev machine
(gitignored) vianpm run cap:*. See the build steps, required permissions and
the on-device verification matrix in
doc/companion-app-packaging.md. (Native mDNS
awaits a Capacitor-8 plugin; until then discovery falls back to the daemon's
/scan.) - Release publishes the Android companion app. A
v*tag now also builds
and (with anANDROID_KEYSTORE_BASE64secret) signs the Android APK and
attaches it to the GitHub Release. The job is decoupled from the meshd package
jobs, so it never blocks the OpenWrt release; iOS (App Store/TestFlight) and
desktop (the installable PWA) are out of scope. Required secrets are listed in
doc/companion-app-packaging.md. - End-to-end test for the LuCI integration.
TestLuCIWorkflowE2Eboots a
real OpenWrt userland with the builtmeshd+luci-app-meshdpackages and
the full LuCI stack (ubusd + rpcd + uhttpd), then drives the operator
workflows over the authenticated/ubusendpoint exactly as the PWA does:
the ACL gate, node enrollment + adopt, the Home/profile lifecycle, and a
wireless client device surfacing through the topology read. Runs in thee2e
CI job; see doc/luci-integration-testing.md.
Fixed
- Creating a Home through the setup wizard failed with ubus error 5.
Selecting a freshly created Home applied its (non-existent) profile, and the
API treated the missing profile as a fatal 500 — even though meshd's own
auto-select already treats it as non-fatal. Selecting a Home with no profile
yet now succeeds; only real apply failures error. - Opaque ubus error 5 from the LuCI Mesh Manager. The rpcd plugin used
curl -f, which discarded meshd's JSON error body on any HTTP error, leaving
rpcd to report a bareNO_DATA(5). The plugin now passes meshd's
{"error": …}body back through so the PWA shows the real reason. - Local meshd builds now run on OpenWrt.
scripts/build.shdefaults to
CGO_ENABLED=0, producing a statically-linked binary; the previous dynamic
(glibc) build failed on OpenWrt's musl userland with
can't execute '/usr/bin/meshd': No such file or directory. - Onboarding wizard's default node client. A function-typed prop default was
treated as a factory, so the default client was a function rather than a
client; the wizard now reaches the node without an explicitcreateClient.
v0.1.1
Fixed
- LuCI Mesh Manager "Access denied". The LuCI host view handed the embedded
PWAL.env.token(LuCI's CSRF token) as the/ubussession token; rpcd does
not recognise it as a session, so every meshd ubus call the PWA made was
rejected. The view now passesL.env.sessionid(the rpcd ubus session id),
so the Mesh Manager works inside LuCI.
v0.1.0
First release with the full secure OpenWrt integration: a mutual-TLS mesh
control plane, a native LuCI app, and signed opkg and apk package feeds.
Added
- Mesh mutual TLS. The mesh control plane is served over mutual TLS on both
the server and client side, using a CN-not-hostname identity model with
trust-on-first-use. - Per-Home PKI. Each Home is its own certificate authority; nodes are issued
a Home-CA node certificate automatically at adoption. - Separate control planes. Management and mesh control planes run on
separate listeners, isolating the device-facing API from the inter-node mesh. - LuCI app (
luci-app-meshd). rpcd plugin, ACLs, and an embedded LuCI view;
shipped in releases (architecture-independent). The PWA runs inside LuCI over
an authenticated ubus session, auto-selecting the ubus transport when embedded. - opkg feed. Every release publishes an opkg feed index
(Packages/Packages.gz), usign-signed (Packages.sig) when a key is
configured; the signing public key (omm-feed.pub) is published as an asset. - apk packages & feed. Real, signed apk-v3 packages (
apk mkpkg) plus a
signed apk repository index (packages.adb) for OpenWrt's apk userland; the
signing public key (omm-apk.pub) is published as an asset. - Profile application. Home profiles are applied when the active Home
changes, with a netifd reload so the changes take effect immediately.
Changed
- On install,
uci-defaultsflips meshd to its secure posture automatically. - Discovery derives the announced API host from the packet source, removing the
need to configure it manually.
Removed
- The Home/node-delete and factory-reset API endpoints.
Fixed
- Release version strings are now valid for apk (stricter than opkg): non-tag
builds use0.0.0_gitinstead of the apk-invalid0.0.0-dev. - The release publish step is idempotent — re-running a release no longer fails
if the release already exists. - Profiles are re-applied when the active Home changes.
- Removed duplicate meshd init/config files left at old paths.
Security
- Inter-node mesh traffic is authenticated and encrypted end-to-end (per-Home CA
- mutual TLS).
- opkg and apk package feeds are cryptographically signed and verified on the
device against published public keys.
v0.0.2: fix(ci): make the release publish step idempotent
`gh release create` hard-fails if a release for the tag already exists, so re-running the workflow or re-pushing a tag broke with "release already exists". Create the release only when missing; otherwise upload assets to the existing one with --clobber.