Skip to content

Commit

Permalink
ICD Management cluster server. (#26809)
Browse files Browse the repository at this point in the history
  • Loading branch information
rcasallas-silabs authored and pull[bot] committed Jul 26, 2023
1 parent b81c5ac commit 1550556
Show file tree
Hide file tree
Showing 23 changed files with 1,650 additions and 537 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/examples-nrfconnect.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ jobs:
- name: Build example nRF Connect SDK All Clusters App on nRF7002 PDK
timeout-minutes: 20
run: |
scripts/examples/nrfconnect_example.sh all-clusters-app nrf7002dk_nrf5340_cpuapp
scripts/examples/nrfconnect_example.sh all-clusters-app nrf7002dk_nrf5340_cpuapp -DCONF_FILE=prj_release.conf
.environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \
nrfconnect nrf7002dk_nrf5340_cpuapp all-clusters-app \
examples/all-clusters-app/nrfconnect/build/zephyr/zephyr.elf \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5934,7 +5934,7 @@ endpoint 0 {
ram attribute activeModeThreshold default = 300;
callback attribute registeredClients;
ram attribute ICDCounter default = 0;
ram attribute clientsSupportedPerFabric default = 1;
ram attribute clientsSupportedPerFabric default = 2;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute eventList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6432,7 +6432,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "1",
"defaultValue": "2",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down Expand Up @@ -31934,5 +31934,6 @@
"endpointVersion": 1,
"deviceIdentifier": 61442
}
]
],
"log": []
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"include": "../../../../src/app/tests/suites/ciTests.json",
"disable": [
"TestClientMonitoringCluster",
"TestIcdManagementCluster",
"Test_TC_SC_4_2",
"Test_TC_SC_5_2",
"TestClusterComplexTypes",
Expand Down
1 change: 0 additions & 1 deletion scripts/tests/chiptest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ def _GetInDevelopmentTests() -> Set[str]:
"Test_AddNewFabricFromExistingFabric.yaml", # chip-repl does not support GetCommissionerRootCertificate and IssueNocChain command
"TestEqualities.yaml", # chip-repl does not support pseudo-cluster commands that return a value
"TestExampleCluster.yaml", # chip-repl does not load custom pseudo clusters
"TestClientMonitoringCluster.yaml", # Client Monitoring Tests need a rework after the XML update
"Test_TC_TIMESYNC_1_1.yaml", # Time sync SDK is not yet ready
"TestAttributesById.yaml", # chip-repl does not support AnyCommands (06/06/2023)
"TestCommandsById.yaml", # chip-repl does not support AnyCommands (06/06/2023)
Expand Down
4 changes: 1 addition & 3 deletions src/app/chip_data_model.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,7 @@ function(chip_configure_data_model APP_TARGET)
${CHIP_APP_BASE_DIR}/util/attribute-storage.cpp
${CHIP_APP_BASE_DIR}/util/attribute-table.cpp
${CHIP_APP_BASE_DIR}/util/binding-table.cpp
# Disable CM cluster table tests until update is done
# https://github.com/project-chip/connectedhomeip/issues/24425
# ${CHIP_APP_BASE_DIR}/util/ClientMonitoringRegistrationTable.cpp
${CHIP_APP_BASE_DIR}/util/IcdMonitoringTable.cpp
${CHIP_APP_BASE_DIR}/util/DataModelHandler.cpp
${CHIP_APP_BASE_DIR}/util/ember-compatibility-functions.cpp
${CHIP_APP_BASE_DIR}/util/error-mapping.cpp
Expand Down
4 changes: 2 additions & 2 deletions src/app/chip_data_model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ template("chip_data_model") {
"${_app_root}/clusters/scenes-server/SceneTable.h",
"${_app_root}/clusters/scenes-server/SceneTableImpl.h",
"${_app_root}/clusters/scenes-server/scenes-server.h",
"${_app_root}/util/ClientMonitoringRegistrationTable.cpp",
"${_app_root}/util/ClientMonitoringRegistrationTable.h",
"${_app_root}/util/DataModelHandler.cpp",
"${_app_root}/util/IcdMonitoringTable.cpp",
"${_app_root}/util/IcdMonitoringTable.h",
"${_app_root}/util/attribute-size-util.cpp",
"${_app_root}/util/attribute-storage.cpp",
"${_app_root}/util/attribute-table.cpp",
Expand Down
194 changes: 167 additions & 27 deletions src/app/clusters/icd-management-server/icd-management-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
#include "icd-management-server.h"

#include "app/server/Server.h"
#include <access/AccessControl.h>
#include <access/Privilege.h>
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandler.h>
#include <app/ConcreteAttributePath.h>
#include <app/util/IcdMonitoringTable.h>
#include <app/util/af.h>
#include <app/util/attribute-storage.h>

Expand All @@ -32,8 +35,7 @@ using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::IcdManagement;
using namespace Protocols;

//==============================================================================
using namespace chip::Access;

namespace {

Expand Down Expand Up @@ -69,61 +71,199 @@ CHIP_ERROR IcdManagementAttributeAccess::Read(const ConcreteReadAttributePath &

CHIP_ERROR IcdManagementAttributeAccess::ReadRegisteredClients(EndpointId endpoint, AttributeValueEncoder & encoder)
{
return encoder.EncodeEmptyList();
uint16_t supported_clients = 0;
VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS == Attributes::ClientsSupportedPerFabric::Get(endpoint, &supported_clients),
CHIP_ERROR_NOT_FOUND);

return encoder.EncodeList([supported_clients](const auto & subEncoder) -> CHIP_ERROR {
IcdMonitoringEntry e;

const auto & fabricTable = Server::GetInstance().GetFabricTable();
for (const auto & fabricInfo : fabricTable)
{
PersistentStorageDelegate & storage = chip::Server::GetInstance().GetPersistentStorage();
IcdMonitoringTable table(storage, fabricInfo.GetFabricIndex(), supported_clients);
for (uint16_t i = 0; i < table.Limit(); ++i)
{
CHIP_ERROR err = table.Get(i, e);
if (CHIP_ERROR_NOT_FOUND == err)
{
// No more entries in the table
break;
}
ReturnErrorOnFailure(err);
ReturnErrorOnFailure(subEncoder.Encode(e));
}
}
return CHIP_NO_ERROR;
});
}

CHIP_ERROR CheckAdmin(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, bool & is_admin)
{
RequestPath requestPath{ .cluster = commandPath.mClusterId, .endpoint = commandPath.mEndpointId };
CHIP_ERROR err = GetAccessControl().Check(commandObj->GetSubjectDescriptor(), requestPath, Privilege::kAdminister);
if (CHIP_NO_ERROR == err)
{
is_admin = true;
}
else if (CHIP_ERROR_ACCESS_DENIED == err)
{
is_admin = false;
err = CHIP_NO_ERROR;
}
return err;
}

class IcdManagementFabricDelegate : public chip::FabricTable::Delegate
{
void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override
{
uint16_t supported_clients = 0;
if (EMBER_ZCL_STATUS_SUCCESS != Attributes::ClientsSupportedPerFabric::Get(kRootEndpointId, &supported_clients))
{
// Fallback to maximum, the remove function will loop until no more entries are found.
supported_clients = UINT16_MAX;
}
IcdMonitoringTable table(chip::Server::GetInstance().GetPersistentStorage(), fabricIndex, supported_clients);
table.RemoveAll();
}
};

IcdManagementFabricDelegate gFabricDelegate;
IcdManagementAttributeAccess gAttribute;

} // namespace

//==============================================================================

InteractionModel::Status
IcdManagementServer::RegisterClient(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::IcdManagement::Commands::RegisterClient::DecodableType & commandData)
InteractionModel::Status IcdManagementServer::RegisterClient(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const Commands::RegisterClient::DecodableType & commandData)
{
// TODO: Implementent logic for end device
return InteractionModel::Status::UnsupportedCommand;
uint16_t supported_clients = 0;
VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS ==
Attributes::ClientsSupportedPerFabric::Get(commandPath.mEndpointId, &supported_clients),
InteractionModel::Status::Failure);
IcdMonitoringTable table(chip::Server::GetInstance().GetPersistentStorage(), commandObj->GetAccessingFabricIndex(),
supported_clients);

// Get current entry, if exists
IcdMonitoringEntry entry;
CHIP_ERROR err = table.Find(commandData.checkInNodeID, entry);
if (CHIP_NO_ERROR == err)
{
// Existing entry: Validate Key if, and only if, the ISD has NOT administrator permissions
bool is_admin = false;
err = CheckAdmin(commandObj, commandPath, is_admin);
VerifyOrReturnError(CHIP_NO_ERROR == err, InteractionModel::Status::Failure);
if (!is_admin)
{
VerifyOrReturnError(commandData.verificationKey.HasValue(), InteractionModel::Status::Failure);
VerifyOrReturnError(commandData.verificationKey.Value().data_equal(entry.key), InteractionModel::Status::Failure);
}
}
else if (CHIP_ERROR_NOT_FOUND == err)
{
// New entry
VerifyOrReturnError(entry.index < table.Limit(), InteractionModel::Status::ResourceExhausted);
}
else
{
// Error
return InteractionModel::Status::Failure;
}

// Save
entry.checkInNodeID = commandData.checkInNodeID;
entry.monitoredSubject = commandData.monitoredSubject;
entry.key = commandData.key;
err = table.Set(entry.index, entry);
VerifyOrReturnError(CHIP_ERROR_INVALID_ARGUMENT != err, InteractionModel::Status::ConstraintError);
VerifyOrReturnError(CHIP_NO_ERROR == err, InteractionModel::Status::Failure);

return InteractionModel::Status::Success;
}

InteractionModel::Status IcdManagementServer::UnregisterClient(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::IcdManagement::Commands::UnregisterClient::DecodableType & commandData)
InteractionModel::Status IcdManagementServer::UnregisterClient(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const Commands::UnregisterClient::DecodableType & commandData)
{
// TODO: Implementent logic for end device
return InteractionModel::Status::UnsupportedCommand;
uint16_t supported_clients = 0;
VerifyOrReturnError(EMBER_ZCL_STATUS_SUCCESS ==
Attributes::ClientsSupportedPerFabric::Get(commandPath.mEndpointId, &supported_clients),
InteractionModel::Status::Failure);
IcdMonitoringTable table(chip::Server::GetInstance().GetPersistentStorage(), commandObj->GetAccessingFabricIndex(),
supported_clients);

// Get current entry, if exists
IcdMonitoringEntry entry;
CHIP_ERROR err = table.Find(commandData.checkInNodeID, entry);
VerifyOrReturnError(CHIP_ERROR_NOT_FOUND != err, InteractionModel::Status::NotFound);
VerifyOrReturnError(CHIP_NO_ERROR == err, InteractionModel::Status::Failure);

// Existing entry: Validate Key if, and only if, the ISD has NOT administrator permissions
bool is_admin = false;
err = CheckAdmin(commandObj, commandPath, is_admin);
VerifyOrReturnError(CHIP_NO_ERROR == err, InteractionModel::Status::Failure);

if (!is_admin)
{
VerifyOrReturnError(commandData.key.HasValue(), InteractionModel::Status::Failure);
VerifyOrReturnError(commandData.key.Value().data_equal(entry.key), InteractionModel::Status::Failure);
}

err = table.Remove(entry.index);
VerifyOrReturnError(CHIP_NO_ERROR == err, InteractionModel::Status::Failure);

return InteractionModel::Status::Success;
}

InteractionModel::Status IcdManagementServer::StayActiveRequest(const chip::app::ConcreteCommandPath & commandPath)
{
// TODO: Implementent logic for end device

// TODO: Implementent stay awake logic for end device
return InteractionModel::Status::UnsupportedCommand;
}

//==============================================================================
void emberAfIcdManagementClusterInitCallback()
{
Server::GetInstance().GetFabricTable().AddFabricDelegate(&gFabricDelegate);
}

/**
* @brief ICD Management Cluster RegisterClient Command callback (from client)
*
*/
bool emberAfIcdManagementClusterRegisterClientCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::IcdManagement::Commands::RegisterClient::DecodableType & commandData)
bool emberAfIcdManagementClusterRegisterClientCallback(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const Commands::RegisterClient::DecodableType & commandData)
{
IcdManagementServer server;

InteractionModel::Status status = server.RegisterClient(commandObj, commandPath, commandData);
if (InteractionModel::Status::Success == status)
{
// Response
IcdManagement::Commands::RegisterClientResponse::Type response;
if (EMBER_ZCL_STATUS_SUCCESS == Attributes::ICDCounter::Get(commandPath.mEndpointId, &response.ICDCounter))
{
commandObj->AddResponse(commandPath, response);
return true;
}
status = InteractionModel::Status::Failure;
}

// Error
commandObj->AddStatus(commandPath, status);
return true;
}

/**
* @brief ICD Management Cluster UnregisterClient Command callback (from client)
* @brief ICD Management Cluster UregisterClient Command callback (from client)
*
*/
bool emberAfIcdManagementClusterUnregisterClientCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::IcdManagement::Commands::UnregisterClient::DecodableType & commandData)
bool emberAfIcdManagementClusterUnregisterClientCallback(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const Commands::UnregisterClient::DecodableType & commandData)
{
IcdManagementServer server;
InteractionModel::Status status = server.UnregisterClient(commandObj, commandPath, commandData);
Expand All @@ -135,9 +275,9 @@ bool emberAfIcdManagementClusterUnregisterClientCallback(
/**
* @brief ICD Management Cluster StayActiveRequest Command callback (from client)
*/
bool emberAfIcdManagementClusterStayActiveRequestCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::DecodableType & commandData)
bool emberAfIcdManagementClusterStayActiveRequestCallback(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const Commands::StayActiveRequest::DecodableType & commandData)
{
IcdManagementServer server;
InteractionModel::Status status = server.StayActiveRequest(commandPath);
Expand Down
32 changes: 13 additions & 19 deletions src/app/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ source_set("binding-test-srcs") {
]
}

# source_set("client-monitoring-test-srcs") {
# sources = [
# "${chip_root}/src/app/util/ClientMonitoringRegistrationTable.cpp",
# "${chip_root}/src/app/util/ClientMonitoringRegistrationTable.h",
# ]

# public_deps = [
# "${chip_root}/src/app/common:cluster-objects",
# "${chip_root}/src/lib/core",
# ]
# }
source_set("icd-management-test-srcs") {
sources = [
"${chip_root}/src/app/util/IcdMonitoringTable.cpp",
"${chip_root}/src/app/util/IcdMonitoringTable.h",
]

public_deps = [
"${chip_root}/src/app/common:cluster-objects",
"${chip_root}/src/lib/core",
]
}

source_set("ota-requestor-test-srcs") {
sources = [
Expand Down Expand Up @@ -107,10 +107,6 @@ chip_test_suite("tests") {
"TestAttributeValueEncoder.cpp",
"TestBindingTable.cpp",
"TestBuilderParser.cpp",

# Disable CM cluster table tests until update is done
# https://github.com/project-chip/connectedhomeip/issues/24425
# "TestClientMonitoringRegistrationTable.cpp",
"TestClusterInfo.cpp",
"TestCommandInteraction.cpp",
"TestCommandPathParams.cpp",
Expand All @@ -122,6 +118,7 @@ chip_test_suite("tests") {
"TestExtensionFieldSets.cpp",
"TestFabricScopedEventLogging.cpp",
"TestICDManager.cpp",
"TestIcdMonitoringTable.cpp",
"TestInteractionModelEngine.cpp",
"TestMessageDef.cpp",
"TestNumericAttributeTraits.cpp",
Expand Down Expand Up @@ -163,10 +160,7 @@ chip_test_suite("tests") {

public_deps = [
":binding-test-srcs",

# Disable CM cluster table tests until update is done
#https://github.com/project-chip/connectedhomeip/issues/24425
# ":client-monitoring-test-srcs",
":icd-management-test-srcs",
":ota-requestor-test-srcs",
":scenes-table-test-srcs",
"${chip_root}/src/app",
Expand Down
Loading

0 comments on commit 1550556

Please sign in to comment.