diff --git a/src/app/clusters/network-commissioning/network-commissioning.cpp b/src/app/clusters/network-commissioning/network-commissioning.cpp index 8d51e8791871da..2b7a856aac8259 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.cpp +++ b/src/app/clusters/network-commissioning/network-commissioning.cpp @@ -333,11 +333,27 @@ void FillDebugTextAndNetworkIndex(Commands::NetworkConfigResponse::Type & respon } } +bool CheckFailSafeArmed(CommandHandlerInterface::HandlerContext & ctx) +{ + DeviceLayer::FailSafeContext & failSafeContext = DeviceLayer::DeviceControlServer::DeviceControlSvr().GetFailSafeContext(); + + if (failSafeContext.IsFailSafeArmed(ctx.mCommandHandler.GetAccessingFabricIndex())) + { + return true; + } + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::UnsupportedAccess); + return false; +} + } // namespace void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands::AddOrUpdateWiFiNetwork::DecodableType & req) { MATTER_TRACE_EVENT_SCOPE("HandleAddOrUpdateWiFiNetwork", "NetworkCommissioning"); + + VerifyOrReturn(CheckFailSafeArmed(ctx)); + Commands::NetworkConfigResponse::Type response; MutableCharSpan debugText; #if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE @@ -354,6 +370,9 @@ void Instance::HandleAddOrUpdateWiFiNetwork(HandlerContext & ctx, const Commands void Instance::HandleAddOrUpdateThreadNetwork(HandlerContext & ctx, const Commands::AddOrUpdateThreadNetwork::DecodableType & req) { MATTER_TRACE_EVENT_SCOPE("HandleAddOrUpdateThreadNetwork", "NetworkCommissioning"); + + VerifyOrReturn(CheckFailSafeArmed(ctx)); + Commands::NetworkConfigResponse::Type response; MutableCharSpan debugText; #if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE @@ -370,6 +389,9 @@ void Instance::HandleAddOrUpdateThreadNetwork(HandlerContext & ctx, const Comman void Instance::HandleRemoveNetwork(HandlerContext & ctx, const Commands::RemoveNetwork::DecodableType & req) { MATTER_TRACE_EVENT_SCOPE("HandleRemoveNetwork", "NetworkCommissioning"); + + VerifyOrReturn(CheckFailSafeArmed(ctx)); + Commands::NetworkConfigResponse::Type response; MutableCharSpan debugText; #if CHIP_CONFIG_NETWORK_COMMISSIONING_DEBUG_TEXT_BUFFER_SIZE @@ -391,6 +413,8 @@ void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::Connec return; } + VerifyOrReturn(CheckFailSafeArmed(ctx)); + mConnectingNetworkIDLen = static_cast(req.networkID.size()); memcpy(mConnectingNetworkID, req.networkID.data(), mConnectingNetworkIDLen); diff --git a/src/controller/python/test/test_scripts/network_commissioning.py b/src/controller/python/test/test_scripts/network_commissioning.py index a9115e0ee3bfd2..0870f27d626e11 100644 --- a/src/controller/python/test/test_scripts/network_commissioning.py +++ b/src/controller/python/test/test_scripts/network_commissioning.py @@ -119,6 +119,12 @@ async def test_wifi(self, endpointId): if res.networkingStatus != Clusters.NetworkCommissioning.Enums.NetworkCommissioningStatus.kSuccess: raise AssertionError(f"Unexpected result: {res.networkingStatus}") + # Arm the failsafe before making network config changes + logger.info(f"Arming the failsafe") + req = Clusters.GeneralCommissioning.Commands.ArmFailSafe(expiryLengthSeconds=900) + res = await self._devCtrl.SendCommand(nodeid=self._nodeid, endpoint=endpointId, payload=req) + logger.info(f"Received response: {res}") + # Remove existing network logger.info(f"Check network list") res = await self._devCtrl.ReadAttribute(nodeid=self._nodeid, attributes=[(endpointId, Clusters.NetworkCommissioning.Attributes.Networks)], returnClusterObject=True) @@ -166,6 +172,12 @@ async def test_wifi(self, endpointId): raise AssertionError(f"Unexpected result: {res.networkingStatus}") logger.info(f"Device connected to a network.") + # Disarm the failsafe + logger.info(f"Disarming the failsafe") + req = Clusters.GeneralCommissioning.Commands.CommissioningComplete() + res = await self._devCtrl.SendCommand(nodeid=self._nodeid, endpoint=endpointId, payload=req) + logger.info(f"Received response: {res}") + # Note: On Linux, when connecting to a connected network, it will return immediately, however, it will try a reconnect. This will make the below attribute read return false negative values. await asyncio.sleep(5) @@ -220,6 +232,12 @@ async def test_thread(self, endpointId): if res.networkingStatus != Clusters.NetworkCommissioning.Enums.NetworkCommissioningStatus.kSuccess: raise AssertionError(f"Unexpected result: {res.networkingStatus}") + # Arm the failsafe before making network config changes + logger.info(f"Arming the failsafe") + req = Clusters.GeneralCommissioning.Commands.ArmFailSafe(expiryLengthSeconds=900) + res = await self._devCtrl.SendCommand(nodeid=self._nodeid, endpoint=endpointId, payload=req) + logger.info(f"Received response: {res}") + # Remove existing network logger.info(f"Check network list") res = await self._devCtrl.ReadAttribute(nodeid=self._nodeid, attributes=[(endpointId, Clusters.NetworkCommissioning.Attributes.Networks)], returnClusterObject=True) @@ -267,6 +285,12 @@ async def test_thread(self, endpointId): raise AssertionError(f"Unexpected result: {res.networkingStatus}") logger.info(f"Device connected to a network.") + # Disarm the failsafe + logger.info(f"Disarming the failsafe") + req = Clusters.GeneralCommissioning.Commands.CommissioningComplete() + res = await self._devCtrl.SendCommand(nodeid=self._nodeid, endpoint=endpointId, payload=req) + logger.info(f"Received response: {res}") + # Verify Last* attributes logger.info(f"Read Last* attributes") res = await self.readLastNetworkingStateAttributes(endpointId=endpointId)