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

Add zap gen for Matter access privilege definitions #16327

Merged
merged 21 commits into from
Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
116 changes: 13 additions & 103 deletions src/app/RequiredPrivilege.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,120 +18,30 @@

#include "RequiredPrivilege.h"

#include <app-common/zap-generated/cluster-objects.h>

namespace {

using namespace chip;
using namespace chip::app;
using namespace chip::Access;

// Privilege override entries are stored in a table per operation (read attribute,
// write attribute, invoke command, read entry). Cluster cannot be invalid, but
// endpoint and field can be invalid, which means wildcard. For each cluster,
// more specific entries should be before less specific entries, so they take effect.
struct PrivilegeOverride
{
ClusterId mCluster;
EndpointId mEndpoint;
Privilege mPrivilege; // NOTE: here so packing is tighter
FieldId mField;

constexpr PrivilegeOverride(ClusterId cluster, EndpointId endpoint, FieldId field, Privilege privilege) :
mCluster(cluster), mEndpoint(endpoint), mPrivilege(privilege), mField(field)
{}

static_assert(sizeof(FieldId) >= sizeof(AttributeId), "FieldId must be able to hold AttributeId");
static_assert(sizeof(FieldId) >= sizeof(CommandId), "FieldId must be able to hold CommandId");
static_assert(sizeof(FieldId) >= sizeof(EventId), "FieldId must be able to hold EventId");
};

// WARNING: for each cluster, put more specific entries before less specific entries
constexpr PrivilegeOverride kPrivilegeOverrideForReadAttribute[] = {
PrivilegeOverride(Clusters::AccessControl::Id, kInvalidEndpointId, kInvalidFieldId, Privilege::kAdminister),
};

// WARNING: for each cluster, put more specific entries before less specific entries
constexpr PrivilegeOverride kPrivilegeOverrideForWriteAttribute[] = {
PrivilegeOverride(Clusters::AccessControl::Id, kInvalidEndpointId, kInvalidFieldId, Privilege::kAdminister),
};

// WARNING: for each cluster, put more specific entries before less specific entries
constexpr PrivilegeOverride kPrivilegeOverrideForInvokeCommand[] = {
PrivilegeOverride(Clusters::AccessControl::Id, kInvalidEndpointId, kInvalidFieldId, Privilege::kAdminister),
};

// WARNING: for each cluster, put more specific entries before less specific entries
constexpr PrivilegeOverride kPrivilegeOverrideForReadEvent[] = {
PrivilegeOverride(Clusters::AccessControl::Id, kInvalidEndpointId, kInvalidFieldId, Privilege::kAdminister),
};

enum class Operation
{
kReadAttribute = 0,
kWriteAttribute = 1,
kInvokeCommand = 2,
kReadEvent = 3
};

constexpr Privilege kDefaultPrivilege[] = {
Privilege::kView, // for read attribute
Privilege::kOperate, // for write attribute
Privilege::kOperate, // for invoke command
Privilege::kView // for read event
};

const PrivilegeOverride * const kPrivilegeOverride[] = { kPrivilegeOverrideForReadAttribute, kPrivilegeOverrideForWriteAttribute,
kPrivilegeOverrideForInvokeCommand, kPrivilegeOverrideForReadEvent };

constexpr size_t kNumPrivilegeOverride[] = { ArraySize(kPrivilegeOverrideForReadAttribute),
ArraySize(kPrivilegeOverrideForWriteAttribute),
ArraySize(kPrivilegeOverrideForInvokeCommand),
ArraySize(kPrivilegeOverrideForReadEvent) };

Privilege GetRequiredPrivilege(Operation operation, ClusterId cluster, EndpointId endpoint, FieldId field)
{
VerifyOrDie(cluster != kInvalidClusterId && endpoint != kInvalidEndpointId && field != kInvalidFieldId);

const auto * const pStart = kPrivilegeOverride[static_cast<int>(operation)];
const auto * const pEnd = pStart + kNumPrivilegeOverride[static_cast<int>(operation)];

for (const auto * p = pStart; p < pEnd; ++p)
{
if (p->mCluster == cluster && (p->mEndpoint == endpoint || p->mEndpoint == kInvalidEndpointId) &&
(p->mField == field || p->mField == kInvalidFieldId))
{
return p->mPrivilege;
}
}

return kDefaultPrivilege[static_cast<int>(operation)];
}

} // namespace

namespace chip {
namespace app {

Privilege RequiredPrivilege::ForReadAttribute(const ConcreteAttributePath & path)
constexpr Access::Privilege RequiredPrivilege::kPrivilegeMapper[];

} // namespace app
} // namespace chip

int __attribute__((weak)) MatterGetAccessPrivilegeForReadAttribute(chip::ClusterId cluster, chip::AttributeId attribute)
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved
{
return GetRequiredPrivilege(Operation::kReadAttribute, path.mClusterId, path.mEndpointId, path.mAttributeId);
return kMatterAccessPrivilegeView;
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved
}

Privilege RequiredPrivilege::ForWriteAttribute(const ConcreteAttributePath & path)
int __attribute__((weak)) MatterGetAccessPrivilegeForWriteAttribute(chip::ClusterId cluster, chip::AttributeId attribute)
{
return GetRequiredPrivilege(Operation::kWriteAttribute, path.mClusterId, path.mEndpointId, path.mAttributeId);
return kMatterAccessPrivilegeOperate;
}

Privilege RequiredPrivilege::ForInvokeCommand(const ConcreteCommandPath & path)
int __attribute__((weak)) MatterGetAccessPrivilegeForInvokeCommand(chip::ClusterId cluster, chip::CommandId command)
{
return GetRequiredPrivilege(Operation::kInvokeCommand, path.mClusterId, path.mEndpointId, path.mCommandId);
return kMatterAccessPrivilegeOperate;
}

Privilege RequiredPrivilege::ForReadEvent(const ConcreteEventPath & path)
int __attribute__((weak)) MatterGetAccessPrivilegeForReadEvent(chip::ClusterId cluster, chip::EventId event)
{
return GetRequiredPrivilege(Operation::kReadEvent, path.mClusterId, path.mEndpointId, path.mEventId);
return kMatterAccessPrivilegeView;
}

} // namespace app
} // namespace chip
44 changes: 38 additions & 6 deletions src/app/RequiredPrivilege.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "ConcreteCommandPath.h"
#include "ConcreteEventPath.h"

#include <app/util/privilege-storage.h>

#include <access/Privilege.h>

#include <lib/core/CHIPCore.h>
Expand All @@ -30,17 +32,47 @@
namespace chip {
namespace app {

// This functionality is intended to come from Ember, but until Ember supports it,
// this class will provide a workable alternative.
class RequiredPrivilege
{
using Privilege = Access::Privilege;

static constexpr Privilege kPrivilegeMapper[] = { Privilege::kView, Privilege::kOperate, Privilege::kManage,
Privilege::kAdminister };

static_assert(ArraySize(kPrivilegeMapper) > kMatterAccessPrivilegeView &&
kPrivilegeMapper[kMatterAccessPrivilegeView] == Privilege::kView,
"Must map privilege correctly");
static_assert(ArraySize(kPrivilegeMapper) > kMatterAccessPrivilegeOperate &&
kPrivilegeMapper[kMatterAccessPrivilegeOperate] == Privilege::kOperate,
"Must map privilege correctly");
static_assert(ArraySize(kPrivilegeMapper) > kMatterAccessPrivilegeManage &&
kPrivilegeMapper[kMatterAccessPrivilegeManage] == Privilege::kManage,
"Must map privilege correctly");
static_assert(ArraySize(kPrivilegeMapper) > kMatterAccessPrivilegeAdminister &&
kPrivilegeMapper[kMatterAccessPrivilegeAdminister] == Privilege::kAdminister,
"Must map privilege correctly");
static_assert(ArraySize(kPrivilegeMapper) > kMatterAccessPrivilegeMaxValue, "Must map all privileges");

public:
static Privilege ForReadAttribute(const ConcreteAttributePath & path);
static Privilege ForWriteAttribute(const ConcreteAttributePath & path);
static Privilege ForInvokeCommand(const ConcreteCommandPath & path);
static Privilege ForReadEvent(const ConcreteEventPath & path);
static Privilege ForReadAttribute(const ConcreteAttributePath & path)
{
return kPrivilegeMapper[MatterGetAccessPrivilegeForReadAttribute(path.mClusterId, path.mAttributeId)];
}

static Privilege ForWriteAttribute(const ConcreteAttributePath & path)
{
return kPrivilegeMapper[MatterGetAccessPrivilegeForWriteAttribute(path.mClusterId, path.mAttributeId)];
}

static Privilege ForInvokeCommand(const ConcreteCommandPath & path)
{
return kPrivilegeMapper[MatterGetAccessPrivilegeForInvokeCommand(path.mClusterId, path.mCommandId)];
}

static Privilege ForReadEvent(const ConcreteEventPath & path)
{
return kPrivilegeMapper[MatterGetAccessPrivilegeForReadEvent(path.mClusterId, path.mEventId)];
}
};

} // namespace app
Expand Down
1 change: 1 addition & 0 deletions src/app/chip_data_model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ template("chip_data_model") {
"${_app_root}/util/ember-print.cpp",
"${_app_root}/util/error-mapping.cpp",
"${_app_root}/util/message.cpp",
"${_app_root}/util/privilege-storage.cpp",
"${_app_root}/util/util.cpp",
"${chip_root}/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp",
]
Expand Down
142 changes: 142 additions & 0 deletions src/app/util/privilege-storage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "privilege-storage.h"

#include <zap-generated/access.h>

#include <lib/support/CodeUtils.h>

#include <cstdint>

using chip::AttributeId;
using chip::ClusterId;
using chip::CommandId;
using chip::EventId;

namespace {

static_assert(GENERATED_ACCESS_PRIVILEGE__VIEW == kMatterAccessPrivilegeView,
"Generated privilege value must match privilege value in code");
static_assert(GENERATED_ACCESS_PRIVILEGE__OPERATE == kMatterAccessPrivilegeOperate,
"Generated privilege value must match privilege value in code");
static_assert(GENERATED_ACCESS_PRIVILEGE__MANAGE == kMatterAccessPrivilegeManage,
"Generated privilege value must match privilege value in code");
static_assert(GENERATED_ACCESS_PRIVILEGE__ADMINISTER == kMatterAccessPrivilegeAdminister,
"Generated privilege value must match privilege value in code");
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved

#ifdef GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER
namespace GeneratedAccessReadAttribute {
constexpr ClusterId kCluster[] = GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER;
constexpr AttributeId kAttribute[] = GENERATED_ACCESS_READ_ATTRIBUTE__ATTRIBUTE;
constexpr uint8_t kPrivilege[] = GENERATED_ACCESS_READ_ATTRIBUTE__PRIVILEGE;
static_assert(ArraySize(kCluster) == ArraySize(kAttribute) && ArraySize(kAttribute) == ArraySize(kPrivilege),
"Generated parallel arrays must be same size");
} // namespace GeneratedAccessReadAttribute
#endif

#ifdef GENERATED_ACCESS_WRITE_ATTRIBUTE__CLUSTER
namespace GeneratedAccessWriteAttribute {
constexpr ClusterId kCluster[] = GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER;
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved
constexpr AttributeId kAttribute[] = GENERATED_ACCESS_READ_ATTRIBUTE__ATTRIBUTE;
constexpr uint8_t kPrivilege[] = GENERATED_ACCESS_READ_ATTRIBUTE__PRIVILEGE;
static_assert(ArraySize(kCluster) == ArraySize(kAttribute) && ArraySize(kAttribute) == ArraySize(kPrivilege),
"Generated parallel arrays must be same size");
} // namespace GeneratedAccessWriteAttribute
#endif

#ifdef GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER
namespace GeneratedAccessInvokeCommand {
constexpr ClusterId kCluster[] = GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER;
constexpr CommandId kCommand[] = GENERATED_ACCESS_INVOKE_COMMAND__COMMAND;
constexpr uint8_t kPrivilege[] = GENERATED_ACCESS_INVOKE_COMMAND__PRIVILEGE;
static_assert(ArraySize(kCluster) == ArraySize(kCommand) && ArraySize(kCommand) == ArraySize(kPrivilege),
"Generated parallel arrays must be same size");
} // namespace GeneratedAccessInvokeCommand
#endif

#ifdef GENERATED_ACCESS_READ_EVENT__CLUSTER
namespace GeneratedAccessReadEvent {
constexpr ClusterId kCluster[] = GENERATED_ACCESS_READ_EVENT__CLUSTER;
constexpr EventId kEvent[] = GENERATED_ACCESS_READ_EVENT__EVENT;
constexpr uint8_t kPrivilege[] = GENERATED_ACCESS_READ_EVENT__PRIVILEGE;
static_assert(ArraySize(kCluster) == ArraySize(kEvent) && ArraySize(kEvent) == ArraySize(kPrivilege),
"Generated parallel arrays must be same size");
} // namespace GeneratedAccessReadEvent
#endif

} // anonymous namespace

int MatterGetAccessPrivilegeForReadAttribute(ClusterId cluster, AttributeId attribute)
{
#ifdef GENERATED_ACCESS_READ_ATTRIBUTE__CLUSTER
using namespace GeneratedAccessReadAttribute;
for (size_t i = 0; i < ArraySize(kCluster); ++i)
{
if (kCluster[i] == cluster && kAttribute[i] == attribute)
{
return kPrivilege[i];
}
}
#endif
return GENERATED_ACCESS_PRIVILEGE__VIEW;
}

int MatterGetAccessPrivilegeForWriteAttribute(ClusterId cluster, AttributeId attribute)
{
#ifdef GENERATED_ACCESS_WRITE_ATTRIBUTE__CLUSTER
using namespace GeneratedAccessWriteAttribute;
for (size_t i = 0; i < ArraySize(kCluster); ++i)
{
if (kCluster[i] == cluster && kAttribute[i] == attribute)
{
return kPrivilege[i];
}
}
#endif
return GENERATED_ACCESS_PRIVILEGE__OPERATE;
}

int MatterGetAccessPrivilegeForInvokeCommand(ClusterId cluster, CommandId command)
{
#ifdef GENERATED_ACCESS_INVOKE_COMMAND__CLUSTER
using namespace GeneratedAccessInvokeCommand;
for (size_t i = 0; i < ArraySize(kCluster); ++i)
{
if (kCluster[i] == cluster && kCommand[i] == command)
{
return kPrivilege[i];
}
}
#endif
return GENERATED_ACCESS_PRIVILEGE__OPERATE;
}

int MatterGetAccessPrivilegeForReadEvent(ClusterId cluster, EventId event)
{
#ifdef GENERATED_ACCESS_READ_EVENT__CLUSTER
using namespace GeneratedAccessReadEvent;
for (size_t i = 0; i < ArraySize(kCluster); ++i)
{
if (kCluster[i] == cluster && kEvent[i] == event)
{
return kPrivilege[i];
}
}
#endif
return GENERATED_ACCESS_PRIVILEGE__VIEW;
}
30 changes: 30 additions & 0 deletions src/app/util/privilege-storage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <lib/core/DataModelTypes.h>

constexpr int kMatterAccessPrivilegeView = 0;
constexpr int kMatterAccessPrivilegeOperate = 1;
constexpr int kMatterAccessPrivilegeManage = 2;
constexpr int kMatterAccessPrivilegeAdminister = 3;
constexpr int kMatterAccessPrivilegeMaxValue = kMatterAccessPrivilegeAdminister;

int MatterGetAccessPrivilegeForReadAttribute(chip::ClusterId cluster, chip::AttributeId attribute);
int MatterGetAccessPrivilegeForWriteAttribute(chip::ClusterId cluster, chip::AttributeId attribute);
int MatterGetAccessPrivilegeForInvokeCommand(chip::ClusterId cluster, chip::CommandId command);
int MatterGetAccessPrivilegeForReadEvent(chip::ClusterId cluster, chip::EventId event);
5 changes: 5 additions & 0 deletions src/app/zap-templates/app-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@
"path": "templates/app/MatterIDL.zapt",
"name": "Human-readable Matter IDL",
"output": "Clusters.matter"
},
{
"path": "templates/app/access.zapt",
"name": "Matter access definitions",
"output": "access.h"
}
]
}
Loading