Skip to content

openthread-br: locate the RCP dongle through otbr-rcp - #30276

Draft
LorbusChris wants to merge 4 commits into
openwrt:masterfrom
LorbusChris:openthread-br-rcp-discovery
Draft

openthread-br: locate the RCP dongle through otbr-rcp#30276
LorbusChris wants to merge 4 commits into
openwrt:masterfrom
LorbusChris:openthread-br-rcp-discovery

Conversation

@LorbusChris

@LorbusChris LorbusChris commented Aug 14, 2026

Copy link
Copy Markdown

Should land after #30091, whose commits this branch includes until it merges; the change here is the last commit only.

The protocol handler required a hand-written radio_url, so pointing the border router at its dongle meant knowing which ttyACM the kernel had picked, and a replug that renumbered the device broke the interface until someone edited the config.

Bring over the otbr-rcp wrapper from the matter-openwrt packaging: when no radio_url is set, the handler resolves the dongle by its USB properties (a cdc_acm interface on a device whose product string names OpenThread), with an rcp option to pin a bus position or a fixed serial device, and optional firmware install and update through handler plugins. Discovery runs in the setup phase rather than under the launched command, since a flash can take minutes and must not race the bounded wait for the agent's ubus object.

A missing dongle fails setup with the restart block every failure needs, netifd retrying immediately and without backoff otherwise. The USB hotplug handler brings such interfaces up again when a device binds, keyed on the recorded RCP_NOT_FOUND error so interfaces an administrator took down on purpose stay down. An explicit radio_url keeps today's behaviour and overrides all of this.

option meaning
rcp '/dev/ttyACM0' fixed serial device, no discovery
rcp '2-1' USB bus position, resolved to whatever serial device it currently exposes
rcp 'any' (default) pick a dongle by its USB product string
uart_baudrate, uart_flow_control appended to the resulting URL
rcp_firmware_update run firmware handler plugins when one recognises the device (none ship with this package)

The wrapper's canonical home is project-chip/matter-openwrt, where its selection invariants are under review in project-chip/matter-openwrt#57; this copy mirrors that state and follows it. The same commit ships in the Turris OS packaging of this package. A LuCI follow-up exposing these options exists and opens once this lands (branch).

Testing

Package builds in the openwrt SDK (x86_64) with the full patch stack; both shell files pass sh -n. The identical commit runs on Turris Omnia hardware via the Turris OS packaging.

Switch from a pinned commit to the 2026.08.0 release tag (the latest
release). Drop the two local patches whose fixes are upstream since
2026.07.0:
- 101-rest-Permit-to-externally-provide-cJSON-library.patch
- 102-openwrt-fix-LuCI-icons.patch

Adjust CMAKE_OPTIONS for the proxy rework that arrived with 2026.07.0.
That release added OT core Advertising and Discovery Proxies that default
on whenever OTBR_MDNS is set and are mutually exclusive with the legacy
POSIX proxies, so forcing OTBR_SRP_ADVERTISING_PROXY=ON and
OTBR_DNSSD_DISCOVERY_PROXY=ON now fails configure with "Only one
Advertising Proxy can be enabled." Drop both flags to adopt the OT core
proxies, matching upstream's default build. Also drop OTBR_DUA_ROUTING,
which is no longer a recognized option.

Set OTBR_VENDOR_NAME and OTBR_PRODUCT_NAME. 2026.07.0 removed the
built-in defaults that border_agent.hpp used to supply, so otbr-agent now
exits with "Vendor name must be set." unless they are given at compile time
or on the command line.

They are set to OpenThread and BorderRouter, the values those defaults had,
rather than to anything OpenWrt specific. The pair also forms the MeshCoP
service instance name, as "<vendor> <product>", which is the name shown when
adding the border router in a Thread client and the one already-paired
clients have recorded. Keeping the previous values means upgrading does not
rename anyone's border router. It also leaves OTBR_NAME at
OpenThread_BorderRouter, which is what it defaulted to.

Pass OTBR_VERSION=$(PKG_VERSION). Left alone, otbr-agent --version
reports the upstream CMake project version (0.3.0), which is unrelated
to the version this package is built from, so the generic version check
fails -- as it already does on master, independently of this update.
OTBR_VERSION overrides that string at configure time, so the binary
reports the version it was packaged as and the check passes with no
override script. luci-app-openthread installs no executables, so the
generic checks have nothing to probe there and need no override either.

Add a test.sh as the functional smoke test: it exercises both binaries,
which also covers their runtime library closure. ot-ctl is probed with -h
because it has no version option at this release
(openthread/openthread#13424 adds one, but the bundled openthread
predates it). The segfault on unrecognized long options that earlier made
-h the only safe probe is fixed in the openthread this release bundles
(openthread/openthread#13423).

The mDNS provider is left unchanged here; a follow-up commit switches it
to OpenThread's internal implementation.

Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
Assisted-By: Claude Fable 5
As of the 2026.07.0 update, otbr-agent's REST API defaults to listening
on 127.0.0.1, so remote clients (e.g. Home Assistant on another host) can
no longer reach it. Add rest_listen_address and rest_listen_port proto
options and pass them through to otbr-agent when set; leaving them unset
keeps the secure loopback-only default.

Also drop the leftover unused 'foobar' proto config option.

Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
Assisted-By: Claude Fable 5
Switch OTBR_MDNS from mDNSResponder to openthread, drop the mdnsd and
mDNSResponder dependencies, and remove the proto handler's mdnsd service
check, which would otherwise refuse to start otbr-agent now that mdnsd is
no longer installed.

This follows upstream, which made the internal implementation the default
in openthread/ot-br-posix#2996 and uses it in its own OpenWrt example
package, and it lets otbr-agent share a router with umdns, which is what
advertises the router's procd-registered services (ssh, samba and the
like) and resolves <hostname>.local.

The two can coexist because they never contend for a name: OpenThread's
mDNS names its host after the Thread extended address, while umdns keeps
<hostname>.local. Both bind UDP 5353 with SO_REUSEADDR and each answers
only for its own records. mDNSResponder instead takes its name from
gethostname(), so it and umdns race for the same name, and the loser
either stops announcing without logging anywhere procd captures or, if
neither notices, both keep claiming it. That is the conflict with a
running mdnsd noted in openwrt#29784.

Border router discovery is unaffected: in this mode OpenThread's own
border agent registers the _meshcop._udp service (its
OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE follows
OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE), and OTBR's publisher is disabled
by design, so clients such as Home Assistant still find the border router.

Note that OpenThread's mDNS serves a single interface, the one given by
the backbone_network option, so Thread service records are announced on
that network only.

Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
Assisted-By: Claude Opus 4.8
@openwrt

openwrt Bot commented Aug 14, 2026

Copy link
Copy Markdown

Formality Check: Suggestions Available

We checked this pull request against the contribution guidelines. Here is what needs your attention:

⚠️ STYLISTIC WARNINGS & SUGGESTIONS

Package Release Audit:

  • ⚠️ Package net/openthread-br version updated from '2f3c799c7463c8f674754e65c53f78bc0bbcbd58' to '2026.08.0', but PKG_RELEASE was not reset to 1 (currently: '2')

Something broken? Consider reporting an issue.
Running version 0e15d1c deployed on 2026-08-12 22:36:32 CEST

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the four commits on this branch; the notes below are all on the last one (896a913), since the first three are #30091's. All four commit messages match what their diffs actually do.

Nothing here looks like a merge blocker. The two worth a decision before merge are the rcp_firmware_update default, which is opt-out in the code but documented as opt-in and now reachable from configs that never mentioned an RCP at all, and the eval of otbr-rcp stdout, which hands the documented firmware-handler plugin API a root shell in netifd's proto handler. The uart_flow_control default is a question rather than a finding. The rest are a doc/behaviour mismatch and two nits.

PKG_RELEASE is left to the formality bot.


Generated by Claude Code

Comment thread net/openthread-br/files/openthread-proto.sh Outdated
Comment thread net/openthread-br/files/openthread-proto.sh Outdated
Comment thread net/openthread-br/files/openthread-proto.sh
Comment thread net/openthread-br/README.md Outdated
Comment thread net/openthread-br/README.md Outdated
Comment thread net/openthread-br/files/openthread-proto.sh Outdated
Comment thread net/openthread-br/Makefile
The protocol handler required a hand-written radio_url, so pointing the
border router at its dongle meant knowing which ttyACM the kernel had
picked, and a replug that renumbered the device broke the interface
until someone edited the config.

Bring over the otbr-rcp wrapper from the matter-openwrt packaging: when
no radio_url is set, the handler resolves the dongle by its USB
properties (a cdc_acm interface on a device whose product string names
OpenThread), with an rcp option to pin a bus position or a fixed serial
device, and optional firmware install and update through handler
plugins. Discovery runs in the setup phase rather than under the
launched command, since a flash can take minutes and must not race the
bounded wait for the agent's ubus object.

Firmware install and update are off by default: flashing is an explicit act,
and with the radio no longer required to be named, a configuration that
mentions no RCP at all now reaches this path. The one value the handler needs
is picked out of otbr-rcp's output rather than evaluated, since otbr-rcp
sources every firmware handler plugin and stdout from one of those would
otherwise run as root in the proto handler.

A missing dongle fails setup with the restart block every failure
needs, netifd retrying immediately and without backoff otherwise. The
USB hotplug handler brings such interfaces up again when a device
binds, keyed on the recorded RCP_NOT_FOUND error so interfaces an
administrator took down on purpose stay down. An explicit radio_url
keeps today's behaviour.

Assisted-By: Claude Fable 5
Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
@LorbusChris
LorbusChris force-pushed the openthread-br-rcp-discovery branch from 896a913 to 98a7d04 Compare August 14, 2026 07:21
@LorbusChris
LorbusChris requested a review from openwrt-ai August 15, 2026 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants