Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions service/matter-netman/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ TARGET_CFLAGS+=\
-DCHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING=\"$(PKG_VERSION)@$(OS_VERSION)\" \
-DCHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING=\"-\" \
-DCHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME=\"$(VERSION_DIST)\" \
-DCHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME=\"\" \
-DCHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER=\"\"

# https://github.com/openwrt/openwrt/issues/13016
Expand All @@ -149,18 +148,21 @@ define Build/Compile
endef

define Package/matter-netman/default/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/matter $(1)/etc/init.d $(1)/usr/share/acl.d
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/matter $(1)/etc/init.d $(1)/usr/share/acl.d $(1)/etc/hotplug.d/iface $(1)/etc/config
$(INSTALL_BIN) $(OUT_DIR)/matter-network-manager-app $(1)/usr/sbin
$(INSTALL_DATA) ./files/bootstrap.sh $(1)/usr/share/matter/
$(INSTALL_DATA) ./files/matter_acl.json $(1)/usr/share/acl.d
$(INSTALL_BIN) ./files/matter.init $(1)/etc/init.d/matter
$(INSTALL_CONF) ./files/matter.config $(1)/etc/config/matter
Comment thread
LorbusChris marked this conversation as resolved.
$(INSTALL_BIN) ./files/matter.iface-hotplug $(1)/etc/hotplug.d/iface/99-matter
endef

Package/matter-netman-mbedtls/install=$(Package/matter-netman/default/install)
Package/matter-netman-openssl/install=$(Package/matter-netman/default/install)

define Package/matter-netman/default/conffiles
$(CONF_DIR)/
/etc/config/matter
endef

Package/matter-netman-mbedtls/conffiles=$(Package/matter-netman/default/conffiles)
Expand Down
22 changes: 22 additions & 0 deletions service/matter-netman/files/matter.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
config matter 'settings'
# Share the LAN access point credentials over the Matter Wi-Fi
# Network Management cluster. Set to 0 to share nothing.
option wifi_share '1'
# The netifd network whose access point credentials are shared.
option wifi_network 'lan'
# Pin a specific wifi-iface section instead of the automatic choice.
# option wifi_iface 'default_radio0'
# The interface this device is reachable on. It is reported first in
# the network diagnostics, so a controller asking which interface the
# device uses gets this one, and it names the network the Ethernet
# diagnostics describe.
# option primary_interface 'br-lan'
# The manufacturer reported in Basic Information. Unset, the one the
# firmware states in /etc/os-release is used.
# option vendor_name 'CZ.NIC'
# Interface state and traffic counters are readable by every paired
# controller. Set to 0 to report none of them.
# option ethernet_diagnostics '1'
# Take the Ethernet diagnostics from this interface instead of the
# primary one, to report the state of a port rather than a bridge.
# option diagnostics_interface 'eth1'
26 changes: 26 additions & 0 deletions service/matter-netman/files/matter.iface-hotplug
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh
# The daemon's mDNS sockets do not survive the interface they are bound to
# bouncing, which leaves the node undiscoverable and unreachable for CASE
# until the daemon restarts. netifd runs these hooks on every interface
# state change; restart the daemon when a backbone interface of a Thread
# border router comes back up.

[ "$ACTION" = "ifup" ] || exit 0
/etc/init.d/matter running || exit 0

. /lib/functions.sh

is_backbone=0
check_iface() {
local proto backbone
config_get proto "$1" proto
[ "$proto" = "thread" ] || return 0
config_get backbone "$1" backbone_network
[ -n "$backbone" ] && [ "$backbone" = "$INTERFACE" ] && is_backbone=1
}
config_load network
config_foreach check_iface interface
[ "$is_backbone" = 1 ] || exit 0

logger -t matter "backbone interface $INTERFACE came up, restarting the Matter daemon to rebind mDNS"
/etc/init.d/matter restart
97 changes: 95 additions & 2 deletions service/matter-netman/files/matter.init
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,102 @@ start_service() {
. /usr/share/matter/bootstrap.sh

procd_open_instance
procd_set_param command /bin/sh -c 'umask 027; exec "$@"' - "$PROG"
procd_set_param command /bin/sh -c 'umask 027; exec "$@"' - "$PROG" $(matter_args)
local vendor_name
config_load matter
config_get vendor_name settings vendor_name ""
# Appended separately so a multi-word name stays one argument.
[ -n "$vendor_name" ] && procd_append_param command --vendor-name "$vendor_name"
procd_set_param user matter
procd_set_param group matter
procd_set_param respawn
# Retry indefinitely: a start that loses a port race with a dying
# predecessor must not strand the service in procd's crash-loop state.
procd_set_param respawn 3600 5 0
procd_close_instance
}

restart() {
# procd's stop is asynchronous, and the daemon needs a moment to tear
# the Matter server down; starting over it loses the port race and
# dies with "Address in use". Wait for the old instance to be gone.
stop "$@"
local i=0
while pidof matter-network-manager-app >/dev/null && [ "$i" -lt 30 ]; do
sleep 1
i=$((i + 1))
done
start "$@"
}

service_triggers() {
procd_add_reload_trigger "matter" "wireless" "network"
}

wifi_args() {
local wifi_share wifi_network wifi_iface

config_load matter
config_get_bool wifi_share settings wifi_share 1
config_get wifi_network settings wifi_network "lan"
config_get wifi_iface settings wifi_iface ""
if [ "$wifi_share" = 0 ]; then
echo -n "--no-wifi-share"
return
fi

echo -n "--wifi-network $wifi_network"
[ -n "$wifi_iface" ] && echo -n " --wifi-iface $wifi_iface"
}

interface_args() {
local primary diag eth_diag

config_load matter
config_get primary settings primary_interface "br-lan"
config_get diag settings diagnostics_interface ""
config_get_bool eth_diag settings ethernet_diagnostics 1
echo -n "--primary-interface $primary"
[ -z "$diag" ] || echo -n " --diagnostics-interface $diag"
[ "$eth_diag" = 1 ] || echo -n " --no-ethernet-diagnostics"
}

thread_args() {
# Without the border router there is no Thread network to manage.
[ -x /usr/sbin/otbr-agent ] || echo -n "--no-thread"
}

matter_args() {
local args thread

args="$(wifi_args) $(interface_args)"
thread="$(thread_args)"
[ -n "$thread" ] && args="$args $thread"
echo -n "$args"
}

reload_service() {
local pid running

# Which access point to share is a command line argument, so a changed
# configuration needs a restart; a changed wireless configuration only
# needs the daemon to re-read the credentials of the same access point,
# which keeps the Matter sessions up.
pid="$(pidof matter-network-manager-app)"
# First PID only, and never read /proc//cmdline (the kernel command
# line) when the daemon is not running at all.
pid="${pid%% *}"
running=""
[ -n "$pid" ] && running="$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null)"
local vendor_name
config_load matter
config_get vendor_name settings vendor_name ""
# Compare the whole command line, not a substring: an option that was
# removed leaves the expected arguments a prefix of the running ones,
# which must count as a change. echo collapses the whitespace.
# shellcheck disable=SC2086 # word splitting collapses the whitespace
if [ "$(set -f; echo $running)" = "$(set -f; echo "$PROG" $(matter_args)${vendor_name:+ --vendor-name $vendor_name})" ]; then
ubus call matter reload_wifi
else
restart
fi
Comment thread
LorbusChris marked this conversation as resolved.
}
20 changes: 17 additions & 3 deletions service/matter-netman/files/matter_acl.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,23 @@
"user": "matter",
"access": {
"otbr": {
"methods": ["*"]
"methods": [
"*"
]
},
"network.wireless": {
"methods": [
"status"
]
}
},
"subscribe": [ "otbr" ],
"listen": [ "ubus.object.*" ]
"subscribe": [
"otbr"
],
"listen": [
"ubus.object.*"
],
"publish": [
"matter"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
The network-manager-app enables the Matter 1.4 Access Restriction List, which
on Linux is backed by ExampleAccessRestrictionProvider from examples/platform.
That provider is a demonstration: its review handler drops every restriction on
the fabric that asked for one. Shipping it means the restriction mechanism is
defeated by invoking the command it exists to gate.

Patch 010 already removes the ReviewFabricRestrictions commands from the data
model so a controller cannot ask. Turn the feature off in the build as well, so
the example provider is not compiled in and the Access Control cluster drops
the restriction handling behind it. The two belong together: 010 stops the
device advertising the commands, this stops it implementing them with example
code. Advertising without implementing, or implementing with a stub, are both
worse than not offering the feature.

A real implementation would need an owner review surface. On a router that is
the web interface, which is the out-of-band path the specification assumes.

diff --git a/examples/network-manager-app/linux/args.gni b/examples/network-manager-app/linux/args.gni
index 2213f8fb38..16826f7395 100644
--- a/examples/network-manager-app/linux/args.gni
+++ b/examples/network-manager-app/linux/args.gni
@@ -27,5 +27,5 @@ chip_config_network_layer_ble = false
chip_enable_wifi = false
chip_enable_thread = false

-chip_enable_access_restrictions = true
+chip_enable_access_restrictions = false
matter_enable_tracing_support = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
From 1b2269948ee34935b55ecf2dc8945cdbb6191363 Mon Sep 17 00:00:00 2001
From: Christian Glombek <c.glombek@cosa.systems>
Date: Mon, 27 Jul 2026 07:34:19 +0200
Subject: [PATCH 1/2] [network-manager] implement RevertActiveDataset in the
fake delegate

The fake border router returned NOT_IMPLEMENTED, so fail-safe rollback
could not be exercised without real hardware.

SetActiveDataset is only accepted when no dataset is configured, so
reverting means returning to the unconfigured state rather than restoring
a previous dataset. Clear it and report the timestamp change.

Assisted-By: Claude Opus 5
---
examples/network-manager-app/linux/ThreadBRFake.h | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/examples/network-manager-app/linux/ThreadBRFake.h b/examples/network-manager-app/linux/ThreadBRFake.h
index 86a92c7c54..4ac56e9455 100644
--- a/examples/network-manager-app/linux/ThreadBRFake.h
+++ b/examples/network-manager-app/linux/ThreadBRFake.h
@@ -92,7 +92,16 @@ class FakeBorderRouterDelegate final : public app::Clusters::ThreadBorderRouterM
}

CHIP_ERROR CommitActiveDataset() override { return CHIP_NO_ERROR; }
- CHIP_ERROR RevertActiveDataset() override { return CHIP_ERROR_NOT_IMPLEMENTED; }
+
+ CHIP_ERROR RevertActiveDataset() override
+ {
+ // SetActiveDataset is only accepted when no dataset is configured, so
+ // reverting it means returning to the unconfigured state.
+ mActiveDataset.Clear();
+ mAttributeChangeCallback->ReportAttributeChanged(
+ app::Clusters::ThreadBorderRouterManagement::Attributes::ActiveDatasetTimestamp::Id);
+ return CHIP_NO_ERROR;
+ }

CHIP_ERROR SetPendingDataset(const Thread::OperationalDataset & pendingDataset) override
{
Loading