Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Group] Add GroupDataProvider to Group command processing #13833

Merged
Merged
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
11 changes: 8 additions & 3 deletions examples/chip-tool/commands/common/CommandInvoker.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ class CommandInvoker final : public ResponseReceiver<typename RequestType::Respo
return CHIP_NO_ERROR;
}

CHIP_ERROR InvokeGroupCommand(Messaging::ExchangeManager * exchangeManager, GroupId groupId, const RequestType & aRequestData)
CHIP_ERROR InvokeGroupCommand(Messaging::ExchangeManager * exchangeManager, FabricIndex fabric, GroupId groupId,
const RequestType & aRequestData)
{
app::CommandPathParams commandPath = { 0 /* endpoint */, groupId, RequestType::GetClusterId(), RequestType::GetCommandId(),
(app::CommandPathFlags::kGroupIdValid) };
Expand All @@ -116,7 +117,7 @@ class CommandInvoker final : public ResponseReceiver<typename RequestType::Respo

ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, aRequestData));

Optional<SessionHandle> session = exchangeManager->GetSessionManager()->CreateGroupSession(groupId);
Optional<SessionHandle> session = exchangeManager->GetSessionManager()->CreateGroupSession(groupId, fabric);
if (!session.HasValue())
{
return CHIP_ERROR_NO_MEMORY;
Expand Down Expand Up @@ -231,7 +232,11 @@ CHIP_ERROR InvokeGroupCommand(DeviceProxy * aDevice, void * aContext,

// invoker will be deleted by the onDone call before the return of InvokeGroupCommand
// invoker should not be used after the InvokeGroupCommand call
ReturnErrorOnFailure(invoker->InvokeGroupCommand(aDevice->GetExchangeManager(), groupId, aRequestData));
//
// We assume the aDevice already has a Case session which is way we can use he established Secure Session
ReturnErrorOnFailure(invoker->InvokeGroupCommand(aDevice->GetExchangeManager(),
aDevice->GetSecureSession().Value()->AsSecureSession()->GetFabricIndex(),
mkardous-silabs marked this conversation as resolved.
Show resolved Hide resolved
groupId, aRequestData));

// invoker is already deleted and is not to be used
invoker.release();
Expand Down
1 change: 1 addition & 0 deletions examples/lighting-app/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ idf_component_register(PRIV_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/user-label-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/wifi-network-diagnostics-server"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ota-requestor"
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server"
PRIV_REQUIRES chip QRCode bt led_strip app_update)

set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
Expand Down
57 changes: 57 additions & 0 deletions examples/lighting-app/lighting-common/lighting-app.matter
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,61 @@ server cluster GeneralDiagnostics = 51 {
readonly global attribute int16u clusterRevision = 65533;
}

server cluster Groups = 4 {
readonly attribute bitmap8 nameSupport = 0;
readonly global attribute int16u clusterRevision = 65533;

request struct AddGroupRequest {
INT16U groupId = 0;
CHAR_STRING groupName = 1;
}

request struct AddGroupIfIdentifyingRequest {
INT16U groupId = 0;
CHAR_STRING groupName = 1;
}

request struct GetGroupMembershipRequest {
INT16U groupList[] = 0;
}

request struct RemoveGroupRequest {
INT16U groupId = 0;
}

request struct ViewGroupRequest {
INT16U groupId = 0;
}

response struct AddGroupResponse {
ENUM8 status = 0;
INT16U groupId = 1;
}

response struct GetGroupMembershipResponse {
INT8U capacity = 0;
INT16U groupList[] = 1;
}

response struct RemoveGroupResponse {
ENUM8 status = 0;
INT16U groupId = 1;
}

response struct ViewGroupResponse {
ENUM8 status = 0;
INT16U groupId = 1;
CHAR_STRING groupName = 2;
}

command AddGroup(AddGroupRequest): AddGroupResponse = 0;
command AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5;
command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2;
command RemoveAllGroups(): DefaultSuccess = 4;
command RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3;
command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1;
}

server cluster Identify = 3 {
enum IdentifyEffectIdentifier : ENUM8 {
kBlink = 0;
Expand Down Expand Up @@ -1424,6 +1479,7 @@ endpoint 0 {
server cluster FixedLabel;
server cluster GeneralCommissioning;
server cluster GeneralDiagnostics;
server cluster Groups;
server cluster LocalizationConfiguration;
server cluster NetworkCommissioning;
binding cluster OtaSoftwareUpdateProvider;
Expand All @@ -1440,6 +1496,7 @@ endpoint 0 {
endpoint 1 {
server cluster ColorControl;
server cluster Descriptor;
server cluster Groups;
server cluster Identify;
server cluster LevelControl;
server cluster OccupancySensing;
Expand Down
24 changes: 22 additions & 2 deletions examples/lighting-app/lighting-common/lighting-app.zap
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@
"mfgCode": null,
"define": "GROUPS_CLUSTER",
"side": "server",
"enabled": 0,
"enabled": 1,
"commands": [
{
"name": "AddGroupResponse",
Expand Down Expand Up @@ -4653,7 +4653,7 @@
"mfgCode": null,
"define": "GROUPS_CLUSTER",
"side": "server",
"enabled": 0,
"enabled": 1,
"commands": [
{
"name": "AddGroupResponse",
Expand Down Expand Up @@ -6734,6 +6734,26 @@
}
]
},
{
"name": "Groups",
"code": 4,
"mfgCode": null,
"define": "GROUPS_CLUSTER",
"side": "client",
"enabled": 0,
"commands": [],
"attributes": []
},
{
"name": "Groups",
"code": 4,
"mfgCode": null,
"define": "GROUPS_CLUSTER",
"side": "server",
"enabled": 0,
"commands": [],
"attributes": []
},
{
"name": "On/Off",
"code": 6,
Expand Down
1 change: 1 addition & 0 deletions examples/lighting-app/mbed/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ target_sources(${APP_TARGET} PRIVATE
${CHIP_ROOT}/src/app/clusters/ota-requestor/ota-requestor-server.cpp
${CHIP_ROOT}/src/app/clusters/ota-requestor/BDXDownloader.cpp
${CHIP_ROOT}/src/app/clusters/ota-requestor/OTARequestor.cpp
${CHIP_ROOT}/src/app/clusters/groups-server/groups-server.cpp
)

target_link_libraries(${APP_TARGET} mbed-os-posix-socket mbed-os mbed-ble mbed-events mbed-netsocket mbed-storage mbed-storage-kv-global-api mbed-mbedtls mbed-emac chip)
Expand Down
1 change: 1 addition & 0 deletions examples/lighting-app/telink/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,5 @@ target_sources(app PRIVATE
${CHIP_ROOT}/src/app/clusters/ota-requestor/ota-requestor-server.cpp
${CHIP_ROOT}/src/app/clusters/ota-requestor/BDXDownloader.cpp
${CHIP_ROOT}/src/app/clusters/ota-requestor/OTARequestor.cpp
${CHIP_ROOT}/src/app/clusters/groups-server/groups-server.cpp
)
143 changes: 120 additions & 23 deletions src/app/CommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <access/AccessControl.h>
#include <app/util/MatterCallbacks.h>
#include <credentials/GroupDataProvider.h>
#include <lib/support/TypeTraits.h>
#include <protocols/secure_channel/Constants.h>

Expand Down Expand Up @@ -127,7 +128,15 @@ CHIP_ERROR CommandHandler::ProcessInvokeRequest(System::PacketBufferHandle && pa
VerifyOrReturnError(TLV::AnonymousTag() == invokeRequestsReader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
CommandDataIB::Parser commandData;
ReturnErrorOnFailure(commandData.Init(invokeRequestsReader));
ReturnErrorOnFailure(ProcessCommandDataIB(commandData));

if (mpExchangeCtx->IsGroupExchangeContext())
{
ReturnErrorOnFailure(ProcessGroupCommandDataIB(commandData));
}
else
{
ReturnErrorOnFailure(ProcessCommandDataIB(commandData));
}
}

// if we have exhausted this container
Expand Down Expand Up @@ -181,21 +190,24 @@ void CommandHandler::DecrementHoldOff()
return;
}

CHIP_ERROR err = CHIP_NO_ERROR;
if (!mpExchangeCtx->IsGroupExchangeContext())
if (mpExchangeCtx->IsGroupExchangeContext())
{
err = SendCommandResponse();
mpExchangeCtx->Close();
}

if (err != CHIP_NO_ERROR)
else
{
ChipLogError(DataManagement, "Failed to send command response: %" CHIP_ERROR_FORMAT, err.Format());
// We marked the exchange as "WillSendMessage", need to shutdown the exchange manually to avoid leaking exchanges.
if (mpExchangeCtx != nullptr)
CHIP_ERROR err = SendCommandResponse();
if (err != CHIP_NO_ERROR)
{
mpExchangeCtx->Close();
ChipLogError(DataManagement, "Failed to send command response: %" CHIP_ERROR_FORMAT, err.Format());
// We marked the exchange as "WillSendMessage", need to shutdown the exchange manually to avoid leaking exchanges.
if (mpExchangeCtx != nullptr)
{
mpExchangeCtx->Close();
}
}
}

Close();
}

Expand Down Expand Up @@ -236,19 +248,7 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand
err = commandPath.GetCommandId(&concretePath.mCommandId);
SuccessOrExit(err);

if (mpExchangeCtx != nullptr && mpExchangeCtx->IsGroupExchangeContext())
{
// TODO retrieve Endpoint ID with GroupDataProvider using GroupId and FabricId
// Issue 11075

// Using endpoint 1 for test purposes
concretePath.mEndpointId = 1;
err = CHIP_NO_ERROR;
}
else
{
err = commandPath.GetEndpointId(&concretePath.mEndpointId);
}
err = commandPath.GetEndpointId(&concretePath.mEndpointId);
SuccessOrExit(err);

VerifyOrExit(mpCallback->CommandExists(concretePath), err = CHIP_ERROR_INVALID_PROFILE_ID);
Expand Down Expand Up @@ -312,6 +312,103 @@ CHIP_ERROR CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommand
return CHIP_NO_ERROR;
}

CHIP_ERROR CommandHandler::ProcessGroupCommandDataIB(CommandDataIB::Parser & aCommandElement)
{
CHIP_ERROR err = CHIP_NO_ERROR;
CommandPathIB::Parser commandPath;
TLV::TLVReader commandDataReader;
ClusterId clusterId;
CommandId commandId;
GroupId groupId;
FabricIndex fabric;

Credentials::GroupDataProvider::GroupEndpoint mapping;
Credentials::GroupDataProvider * groupDataProvider = Credentials::GetGroupDataProvider();
Credentials::GroupDataProvider::EndpointIterator * iterator;

err = aCommandElement.GetPath(&commandPath);
SuccessOrExit(err);

err = commandPath.GetClusterId(&clusterId);
SuccessOrExit(err);

err = commandPath.GetCommandId(&commandId);
SuccessOrExit(err);

groupId = mpExchangeCtx->GetSessionHandle()->AsGroupSession()->GetGroupId();
fabric = GetAccessingFabricIndex();

ChipLogDetail(DataManagement,
"Received group command for Group=%" PRIu16 " Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI, groupId,
ChipLogValueMEI(clusterId), ChipLogValueMEI(commandId));

err = aCommandElement.GetData(&commandDataReader);
if (CHIP_END_OF_TLV == err)
{
ChipLogDetail(DataManagement,
"Received command without data for Group=%" PRIu16 " Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI,
groupId, ChipLogValueMEI(clusterId), ChipLogValueMEI(commandId));
err = CHIP_NO_ERROR;
}
SuccessOrExit(err);

iterator = groupDataProvider->IterateEndpoints(fabric);
VerifyOrExit(iterator != nullptr, err = CHIP_ERROR_NO_MEMORY);

while (iterator->Next(mapping))
{
if (groupId != mapping.group_id)
{
continue;
}

ChipLogDetail(DataManagement,
"Processing group command for Endpoint=%" PRIu16 " Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI,
mapping.endpoint_id, ChipLogValueMEI(clusterId), ChipLogValueMEI(commandId));

const ConcreteCommandPath concretePath(mapping.endpoint_id, clusterId, commandId);

if (!mpCallback->CommandExists(concretePath))
{
ChipLogError(DataManagement, "No Cluster " ChipLogFormatMEI " on Endpoint 0x%" PRIx16, ChipLogValueMEI(clusterId),
mapping.endpoint_id);

continue;
}

{
Access::SubjectDescriptor subjectDescriptor = mpExchangeCtx->GetSessionHandle()->GetSubjectDescriptor();
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId, .endpoint = concretePath.mEndpointId };
Access::Privilege requestPrivilege = Access::Privilege::kOperate; // TODO: get actual request privilege
err = Access::GetAccessControl().Check(subjectDescriptor, requestPath, requestPrivilege);
err = CHIP_NO_ERROR; // TODO: remove override
if (err != CHIP_NO_ERROR)
{
continue;
}
}

if ((err = MatterPreCommandReceivedCallback(concretePath)) == CHIP_NO_ERROR)
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
{
TLV::TLVReader dataReader(commandDataReader);
mpCallback->DispatchCommand(*this, concretePath, dataReader);
MatterPostCommandReceivedCallback(concretePath);
}
else
{
ChipLogError(DataManagement,
"Error when calling MatterPreCommandReceivedCallback for Endpoint=%" PRIu16 " Cluster=" ChipLogFormatMEI
" Command=" ChipLogFormatMEI " : %" CHIP_ERROR_FORMAT,
mapping.endpoint_id, ChipLogValueMEI(clusterId), ChipLogValueMEI(commandId), err.Format());
continue;
}
}
iterator->Release();

exit:
return CHIP_NO_ERROR;
}

CHIP_ERROR CommandHandler::AddStatusInternal(const ConcreteCommandPath & aCommandPath,
const Protocols::InteractionModel::Status aStatus,
const Optional<ClusterStatus> & aClusterStatus)
Expand Down
10 changes: 10 additions & 0 deletions src/app/CommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,17 @@ class CommandHandler
*/
void Close();

/**
* ProcessCommandDataIB is only called when a unicast invoke command request is received
* It requires the endpointId in its command path to be able to dispatch the command
*/
CHIP_ERROR ProcessCommandDataIB(CommandDataIB::Parser & aCommandElement);

/**
* ProcessGroupCommandDataIB is only called when a group invoke command request is received
* It doesn't need the endpointId in it's command path since it uses the GroupId in message metadata to find it
*/
CHIP_ERROR ProcessGroupCommandDataIB(CommandDataIB::Parser & aCommandElement);
CHIP_ERROR SendCommandResponse();
CHIP_ERROR AddStatusInternal(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus,
const Optional<ClusterStatus> & aClusterStatus);
Expand Down
Loading