diff --git a/examples/all-clusters-app/linux/.kvs b/examples/all-clusters-app/linux/.kvs deleted file mode 100644 index 9976ff5b8b7caf..00000000000000 --- a/examples/all-clusters-app/linux/.kvs +++ /dev/null @@ -1,28 +0,0 @@ -[DEFAULT] -f/1/ac/0/0=FSQBBSQCAjYDBmm2AQAYNAQY -f/1/g=FSQBACQCACQDACQEACQFACQGASQHABg= -f/1/i=FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEE3KqJqpPwju/MeqShRDFpusi544wfWj6+gYRG/nor4oHRLfTRz4+zihd9ONWqQ9zwA/CQomn+sjmIvbcRYIYh2DcKNQEpARgkAmAwBBQPVaSOYFdX6pOarWj2mXieOQsSJzAFFGx6kZSTgFw3YQDgKHYjei851xbkGDALQPRuk4wx/ZAQXSmais4GD0JyZl9Jwxq1MM8TUdUQ1nCQ0Q/VuHZqy0pR9HxjgLUDPy2b4YFJIT1rIf8ZYHAeaCMY -f/1/k/0=FSQBACQCATYDFScEUAIAAOx/AAAlBVRMMAYQ7QtLfz7zOjEY6QUsagDDPRgVJAQAJAUAMAYQAAAAAAAAAAAAAAAAAAAAABgVJAQAJAUAMAYQAAAAAAAAAAAAAAAAAAAAABgYJQf//xg= -f/1/m=FSUA8f8sAQAY -f/1/n=FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVASYRIUM0EhgkBwEkCAEwCUEE7R7vwTlybDjtGBspWXkUMSnID4um6q91pa7EQdCSIioP+AgPAA3zqzXyYunmoZbVijM9UbzOUhvacYvA+2xanzcKNQEoARgkAgE2AwQCBAEYMAQUi5rGWgAt12jH/3fxeswo+bhw+YcwBRQPVaSOYFdX6pOarWj2mXieOQsSJxgwC0AtXja1zqi99vqxUOcDooFbR7g3dR6FHR/DjYJOy2QgtY0m1Krqo9Whb9A//TtnLTpsXj+DKnl4cBJ6Zb1WGdhrGA== -f/1/o=FSQAATABYQTtHu/BOXJsOO0YGylZeRQxKcgPi6bqr3WlrsRB0JIiKg/4CA8ADfOrNfJi6eahltWKMz1RvM5SG9pxi8D7bFqftpuGwM3zJ0gq/ZXqozNld3ZK32h4PWWNKTlq3zM9wUEY -f/1/r=FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEECT5tju37pQzMYxhc2pumcwtyKq7elKv8mcWFxDqluOWVK6RJYxiytMv4NQA+JFg/rN8AVPzfz2txBhBJKEF0UDcKNQEpARgkAmAwBBRsepGUk4BcN2EA4Ch2I3ovOdcW5DAFFGx6kZSTgFw3YQDgKHYjei851xbkGDALQBPAPvpTcPaJ51tb6/5sPfKuU6QWe2ClszX+T9fCPL4ZSeJZq0ukzeGMqOgnlAh3MVzkugI2IKdO9e/lcAib04QY -f/1/s/000000000001B669=FTADEO0xJXt8dKE+RAjHrjhJCREwBCAkLjwW/9P1MAh7PKST7kCABWTyP5W6JnAccoRVc8JXPDAFDAAAAAAAAAAAAAAAABg= -g/a/0/2b/0=BWVuLVVT -g/a/1/102/7=Gw== -g/a/1/300/4001=Ag== -g/a/1/300/7=AAA= -g/a/1/8/0=/g== -g/fidx=FSQAAjYBBAEYGA== -g/gcc=E0Y8Aw== -g/gdc=PtW/BQ== -g/gfl=FSQBASQCARg= -g/im/ec=AAABAAAAAAA= -g/lkgt=FSYAgwxNLBg= -g/s/7TEle3x0oT5ECMeuOEkJEQ\x3d\x3d=FSQBASYCabYBABg= -g/sri=FhUkAQEmAmm2AQAYGA== -g/sum=MAA= -g/ts/tz=FhUgAAAkAQAsAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGBg= -wifi-pass= -wifi-ssid= - diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index 14ad098965f5e5..d291d8154d421f 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -303,6 +303,9 @@ Status CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommandElem if (CommandIsFabricScoped(concretePath.mClusterId, concretePath.mCommandId)) { + // SPEC: Else if the command in the path is fabric-scoped and there is no accessing fabric, + // a CommandStatusIB SHALL be generated with the UNSUPPORTED_ACCESS Status Code. + // Fabric-scoped commands are not allowed before a specific accessing fabric is available. // This is mostly just during a PASE session before AddNOC. if (GetAccessingFabricIndex() == kUndefinedFabricIndex) @@ -470,8 +473,7 @@ CHIP_ERROR CommandHandler::AddStatus(const ConcreteCommandPath & aCommandPath, c return AddStatusInternal(aCommandPath, StatusIB(aStatus)); } -CHIP_ERROR CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Status aStatus, - const char * aMessage) +void CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Status aStatus, const char * aMessage) { if (aStatus != Status::Success) { @@ -482,7 +484,15 @@ CHIP_ERROR CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath & ChipLogValueIMStatus(aStatus), aMessage); } - return AddStatus(aCommandPath, aStatus); + CHIP_ERROR err = AddStatus(aCommandPath, aStatus); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DataManagement, + "Failed to set status on Endpoint=%u Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI + ": %" CHIP_ERROR_FORMAT, + aCommandPath.mEndpointId, ChipLogValueMEI(aCommandPath.mClusterId), ChipLogValueMEI(aCommandPath.mCommandId), + err.Format()); + } } CHIP_ERROR CommandHandler::AddClusterSpecificSuccess(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus) diff --git a/src/app/CommandHandler.h b/src/app/CommandHandler.h index e2d2f4a6f75e1e..bc96583abd7597 100644 --- a/src/app/CommandHandler.h +++ b/src/app/CommandHandler.h @@ -173,9 +173,10 @@ class CommandHandler : public Messaging::ExchangeDelegate CHIP_ERROR AddStatus(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus); // Same as AddStatus, but logs that the command represented by aCommandPath failed with the given - // error status and error message, if aStatus is an error. - CHIP_ERROR AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus, - const char * aMessage); + // error status and error message, if aStatus is an error. Errors on AddStatus are just logged + // (since the caller likely can only log and not further add a status). + void AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus, + const char * aMessage); CHIP_ERROR AddClusterSpecificSuccess(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus); diff --git a/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp b/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp index 9ff43d9a2ef834..fcd0dfa1353516 100644 --- a/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp +++ b/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp @@ -401,7 +401,34 @@ ValidateKeySetWriteArguments(const chip::app::Clusters::GroupKeyManagement::Comm return Status::Success; } -constexpr uint16_t GroupKeyManagementAttributeAccess::kClusterRevision; +bool GetProviderAndFabric(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + Credentials::GroupDataProvider ** outGroupDataProvider, const FabricInfo ** outFabricInfo) +{ + VerifyOrDie(commandObj != nullptr); + VerifyOrDie(outGroupDataProvider != nullptr); + VerifyOrDie(outFabricInfo != nullptr); + + // Internal failures on internal inconsistencies. + auto provider = GetGroupDataProvider(); + auto fabric = Server::GetInstance().GetFabricTable().FindFabricWithIndex(commandObj->GetAccessingFabricIndex()); + + if (nullptr == provider) + { + commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on provider!"); + return false; + } + + if (nullptr == fabric) + { + commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on access fabric!"); + return false; + } + + *outGroupDataProvider = provider; + *outFabricInfo = fabric; + + return true; +} GroupKeyManagementAttributeAccess gAttribute; @@ -420,12 +447,12 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::GroupKeyManagement::Commands::KeySetWrite::DecodableType & commandData) { - auto provider = GetGroupDataProvider(); - auto fabric = Server::GetInstance().GetFabricTable().FindFabricWithIndex(commandObj->GetAccessingFabricIndex()); + Credentials::GroupDataProvider * provider = nullptr; + const FabricInfo * fabric = nullptr; - if (nullptr == provider || nullptr == fabric) + if (!GetProviderAndFabric(commandObj, commandPath, &provider, &fabric)) { - commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on provider/fabric"); + // Command will already have status populated from validation. return true; } @@ -516,11 +543,7 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback( } // Send response - err = commandObj->AddStatus(commandPath, StatusIB(err).mStatus); - if (CHIP_NO_ERROR != err) - { - ChipLogDetail(Zcl, "GroupKeyManagementCluster: KeySetWrite failed: %" CHIP_ERROR_FORMAT, err.Format()); - } + commandObj->AddStatus(commandPath, StatusIB(err).mStatus); return true; } @@ -528,20 +551,21 @@ bool emberAfGroupKeyManagementClusterKeySetReadCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::GroupKeyManagement::Commands::KeySetRead::DecodableType & commandData) { - auto fabric = commandObj->GetAccessingFabricIndex(); - auto * provider = GetGroupDataProvider(); + Credentials::GroupDataProvider * provider = nullptr; + const FabricInfo * fabric = nullptr; - if (nullptr == provider) + if (!GetProviderAndFabric(commandObj, commandPath, &provider, &fabric)) { - commandObj->AddStatus(commandPath, Status::Failure); + // Command will already have status populated from validation. return true; } + FabricIndex fabricIndex = fabric->GetFabricIndex(); GroupDataProvider::KeySet keyset; - if (CHIP_NO_ERROR != provider->GetKeySet(fabric, commandData.groupKeySetID, keyset)) + if (CHIP_NO_ERROR != provider->GetKeySet(fabricIndex, commandData.groupKeySetID, keyset)) { // KeySet ID not found - commandObj->AddStatus(commandPath, Status::NotFound); + commandObj->AddStatusAndLogIfFailure(commandPath, Status::NotFound, "Keyset ID not found in KeySetRead"); return true; } @@ -592,30 +616,40 @@ bool emberAfGroupKeyManagementClusterKeySetRemoveCallback( const chip::app::Clusters::GroupKeyManagement::Commands::KeySetRemove::DecodableType & commandData) { - auto fabric = commandObj->GetAccessingFabricIndex(); - auto * provider = GetGroupDataProvider(); - Status status = Status::Failure; + Credentials::GroupDataProvider * provider = nullptr; + const FabricInfo * fabric = nullptr; - if (nullptr != provider) + if (!GetProviderAndFabric(commandObj, commandPath, &provider, &fabric)) { - // Remove keyset - CHIP_ERROR err = provider->RemoveKeySet(fabric, commandData.groupKeySetID); - if (CHIP_ERROR_KEY_NOT_FOUND == err) - { - status = Status::NotFound; - } - else if (CHIP_NO_ERROR == err) - { - status = Status::Success; - } + // Command will already have status populated from validation. + return true; } - // Send response - CHIP_ERROR send_err = commandObj->AddStatus(commandPath, status); - if (CHIP_NO_ERROR != send_err) + if (commandData.groupKeySetID == GroupDataProvider::kIdentityProtectionKeySetId) + { + // SPEC: This command SHALL fail with an INVALID_COMMAND status code back to the initiator if the GroupKeySetID being + // removed is 0, which is the Key Set associated with the Identity Protection Key (IPK). + commandObj->AddStatusAndLogIfFailure(commandPath, Status::InvalidCommand, + "Attempted to KeySetRemove the identity protection key!"); + return true; + } + + // Remove keyset + FabricIndex fabricIndex = fabric->GetFabricIndex(); + CHIP_ERROR err = provider->RemoveKeySet(fabricIndex, commandData.groupKeySetID); + + Status status = Status::Success; + if (CHIP_ERROR_KEY_NOT_FOUND == err) + { + status = Status::NotFound; + } + else if (CHIP_NO_ERROR != err) { - ChipLogDetail(Zcl, "GroupKeyManagementCluster: KeySetRemove failed: %" CHIP_ERROR_FORMAT, send_err.Format()); + status = Status::Failure; } + + // Send status response. + commandObj->AddStatusAndLogIfFailure(commandPath, status, "KeySetRemove failed"); return true; } @@ -654,19 +688,20 @@ bool emberAfGroupKeyManagementClusterKeySetReadAllIndicesCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::GroupKeyManagement::Commands::KeySetReadAllIndices::DecodableType & commandData) { - auto fabric = commandObj->GetAccessingFabricIndex(); - auto * provider = GetGroupDataProvider(); + Credentials::GroupDataProvider * provider = nullptr; + const FabricInfo * fabric = nullptr; - if (nullptr == provider) + if (!GetProviderAndFabric(commandObj, commandPath, &provider, &fabric)) { - commandObj->AddStatus(commandPath, Status::Failure); + // Command will already have status populated from validation. return true; } - auto keysIt = provider->IterateKeySets(fabric); + FabricIndex fabricIndex = fabric->GetFabricIndex(); + auto keysIt = provider->IterateKeySets(fabricIndex); if (nullptr == keysIt) { - commandObj->AddStatus(commandPath, Status::Failure); + commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Failed iteration of key set indices!"); return true; } diff --git a/src/app/clusters/mode-base-server/mode-base-server.cpp b/src/app/clusters/mode-base-server/mode-base-server.cpp index cb55bc214c8676..2b9cc232f87e8d 100644 --- a/src/app/clusters/mode-base-server/mode-base-server.cpp +++ b/src/app/clusters/mode-base-server/mode-base-server.cpp @@ -368,6 +368,11 @@ void Instance::HandleChangeToMode(HandlerContext & ctx, const Commands::ChangeTo Commands::ChangeToModeResponse::Type response; + // If the NewMode field doesn't match the Mode field of any entry of the SupportedModes list, + // the ChangeToModeResponse command's Status field SHALL indicate UnsupportedMode and + // the StatusText field SHALL be included and MAY be used to indicate the issue, with a human readable string, + // or include an empty string. + // We are leaving the StatusText empty since the Status is descriptive enough. if (!IsSupportedMode(newMode)) { ChipLogError(Zcl, "ModeBase: Failed to find the option with mode %u", newMode); @@ -376,6 +381,17 @@ void Instance::HandleChangeToMode(HandlerContext & ctx, const Commands::ChangeTo return; } + // If the NewMode field is the same as the value of the CurrentMode attribute + // the ChangeToModeResponse command SHALL have the Status field set to Success and + // the StatusText field MAY be supplied with a human readable string or include an empty string. + // We are leaving the StatusText empty since the Status is descriptive enough. + if (newMode == GetCurrentMode()) + { + response.status = to_underlying(ModeBase::StatusCode::kSuccess); + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); + return; + } + mDelegate->HandleChangeToMode(newMode, response); if (response.status == to_underlying(StatusCode::kSuccess)) diff --git a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml index 11d190c78738d6..82e10bc2120374 100644 --- a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml +++ b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml @@ -556,6 +556,15 @@ tests: response: error: RESOURCE_EXHAUSTED + - label: "Try to remove KeySet index 0 should fail" + command: "KeySetRemove" + arguments: + values: + - name: "GroupKeySetID" + value: 0 + response: + error: INVALID_COMMAND + - label: "Write Group Keys (invalid)" command: "writeAttribute" attribute: "GroupKeyMap" diff --git a/src/credentials/FabricTable.cpp b/src/credentials/FabricTable.cpp index 8ec4691f9f80fa..f9b7503a7bad9e 100644 --- a/src/credentials/FabricTable.cpp +++ b/src/credentials/FabricTable.cpp @@ -510,6 +510,11 @@ FabricInfo * FabricTable::GetMutableFabricByIndex(FabricIndex fabricIndex) const FabricInfo * FabricTable::FindFabricWithIndex(FabricIndex fabricIndex) const { + if (fabricIndex == kUndefinedFabricIndex) + { + return nullptr; + } + // Try to match pending fabric first if available if (HasPendingFabricUpdate() && (mPendingFabric.GetFabricIndex() == fabricIndex)) { diff --git a/src/credentials/tests/TestFabricTable.cpp b/src/credentials/tests/TestFabricTable.cpp index 96ed242a684310..0ed6db832f3b17 100644 --- a/src/credentials/tests/TestFabricTable.cpp +++ b/src/credentials/tests/TestFabricTable.cpp @@ -2391,6 +2391,11 @@ void TestFabricLookup(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, fabricInfo->GetFabricIndex() == 2); NL_TEST_ASSERT(inSuite, !fabricInfo->ShouldAdvertiseIdentity()); } + + // Attempt lookup of FabricIndex 0 --> should always fail. + { + NL_TEST_ASSERT(inSuite, fabricTable.FindFabricWithIndex(0) == nullptr); + } } void TestFetchCATs(nlTestSuite * inSuite, void * inContext) diff --git a/src/platform/ESP32/ConnectivityManagerImpl.h b/src/platform/ESP32/ConnectivityManagerImpl.h index 97d07b894cb9c2..0add13da49886c 100644 --- a/src/platform/ESP32/ConnectivityManagerImpl.h +++ b/src/platform/ESP32/ConnectivityManagerImpl.h @@ -167,6 +167,12 @@ class ConnectivityManagerImpl final : public ConnectivityManager, void OnStationIPv6AddressAvailable(const ip_event_got_ip6_t & got_ip); #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI +#if CHIP_DEVICE_CONFIG_ENABLE_ETHERNET + void OnEthernetIPv4AddressAvailable(const ip_event_got_ip_t & got_ip); + void OnEthernetIPv4AddressLost(void); + void OnEthernetIPv6AddressAvailable(const ip_event_got_ip6_t & got_ip); +#endif // CHIP_DEVICE_CONFIG_ENABLE_ETHERNET + // ===== Members for internal use by the following friends. friend ConnectivityManager & ConnectivityMgr(void); diff --git a/src/platform/ESP32/ConnectivityManagerImpl_Ethernet.cpp b/src/platform/ESP32/ConnectivityManagerImpl_Ethernet.cpp index ec8d729d417d85..d8f7137047ebac 100644 --- a/src/platform/ESP32/ConnectivityManagerImpl_Ethernet.cpp +++ b/src/platform/ESP32/ConnectivityManagerImpl_Ethernet.cpp @@ -55,15 +55,52 @@ CHIP_ERROR ConnectivityManagerImpl::InitEthernet() return CHIP_NO_ERROR; } +void ConnectivityManagerImpl::OnEthernetIPv4AddressAvailable(const ip_event_got_ip_t & got_ip) +{ + ChipLogProgress(DeviceLayer, "IPv4 address available on Ethernet interface: " IPSTR "/" IPSTR " gateway " IPSTR, + IP2STR(&got_ip.ip_info.ip), IP2STR(&got_ip.ip_info.netmask), IP2STR(&got_ip.ip_info.gw)); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kInterfaceIpAddressChanged; + event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV4_Assigned; + PlatformMgr().PostEventOrDie(&event); +} + +void ConnectivityManagerImpl::OnEthernetIPv4AddressLost(void) +{ + ChipLogProgress(DeviceLayer, "IPv4 address lost on Ethernet interface"); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kInterfaceIpAddressChanged; + event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV4_Lost; + PlatformMgr().PostEventOrDie(&event); +} + +void ConnectivityManagerImpl::OnEthernetIPv6AddressAvailable(const ip_event_got_ip6_t & got_ip) +{ + ChipLogProgress(DeviceLayer, "IPv6 address available on Ethernet interface: " IPV6STR, IPV62STR(got_ip.ip6_info.ip)); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kInterfaceIpAddressChanged; + event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV6_Assigned; + PlatformMgr().PostEventOrDie(&event); +} + void ConnectivityManagerImpl::OnEthernetPlatformEvent(const ChipDeviceEvent * event) { switch (event->Platform.ESPSystemEvent.Id) { case IP_EVENT_ETH_GOT_IP: - ChipLogProgress(DeviceLayer, "Ethernet Link Up"); + OnEthernetIPv4AddressAvailable(event->Platform.ESPSystemEvent.Data.IpGotIp); break; case IP_EVENT_ETH_LOST_IP: - ChipLogProgress(DeviceLayer, "Ethernet Link Down"); + OnEthernetIPv4AddressLost(); + break; + case IP_EVENT_GOT_IP6: + if (strcmp(esp_netif_get_ifkey(event->Platform.ESPSystemEvent.Data.IpGotIp6.esp_netif), "ETH_DEF") == 0) + { + OnEthernetIPv6AddressAvailable(event->Platform.ESPSystemEvent.Data.IpGotIp6); + } break; case ETHERNET_EVENT_START: ChipLogProgress(DeviceLayer, "Ethernet Started");