Skip to content

Commit be90d4d

Browse files
authored
Draft: Add configurable ep1 ACLs and bindings (#23212)
* Draft: Add configurable ep1 ACLs and bindings * address comments
1 parent b0d92ca commit be90d4d

File tree

7 files changed

+254
-35
lines changed

7 files changed

+254
-35
lines changed

examples/tv-app/android/java/AppImpl.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,19 @@ Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
403403
return Access::Privilege::kOperate;
404404
}
405405

406+
std::list<ClusterId> ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
407+
uint16_t productId)
408+
{
409+
if (endpointId == kLocalVideoPlayerEndpointId)
410+
{
411+
return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id,
412+
chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id,
413+
chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id,
414+
chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id };
415+
}
416+
return {};
417+
}
418+
406419
} // namespace AppPlatform
407420
} // namespace chip
408421

examples/tv-app/android/java/AppImpl.h

+5
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
163163
// When a vendor has admin privileges, it will get access to all clusters on ep1
164164
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;
165165

166+
// Get the cluster list this vendorId/productId should have on static endpoints such as ep1 for casting video clients.
167+
// When a vendor has admin privileges, it will get access to all clusters on ep1
168+
std::list<ClusterId> GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
169+
uint16_t productId) override;
170+
166171
void AddAdminVendorId(uint16_t vendorId);
167172

168173
void setContentAppAttributeDelegate(ContentAppAttributeDelegate * attributeDelegate);

examples/tv-app/android/java/TVApp-JNI.cpp

+93-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
#include <lib/support/CHIPJNIError.h>
4242
#include <lib/support/JniReferences.h>
4343
#include <lib/support/JniTypeWrappers.h>
44+
#include <zap-generated/CHIPClusters.h>
4445

4546
using namespace chip;
4647
using namespace chip::app;
48+
using namespace chip::app::Clusters;
4749
using namespace chip::AppPlatform;
4850
using namespace chip::Credentials;
4951

@@ -201,9 +203,44 @@ class MyPostCommissioningListener : public PostCommissioningListener
201203
void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
202204
SessionHandle & sessionHandle) override
203205
{
206+
// read current binding list
207+
chip::Controller::BindingCluster cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId);
204208

205-
ContentAppPlatform::GetInstance().ManageClientAccess(
206-
exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse);
209+
cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle);
210+
211+
CHIP_ERROR err =
212+
cluster.ReadAttribute<Binding::Attributes::Binding::TypeInfo>(this, OnReadSuccessResponse, OnReadFailureResponse);
213+
if (err != CHIP_NO_ERROR)
214+
{
215+
ChipLogError(Controller, "Failed in reading binding. Error %s", ErrorStr(err));
216+
clearContext();
217+
}
218+
}
219+
220+
/* Callback when command results in success */
221+
static void
222+
OnReadSuccessResponse(void * context,
223+
const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseData)
224+
{
225+
ChipLogProgress(Controller, "OnReadSuccessResponse - Binding Read Successfully");
226+
227+
MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
228+
listener->finishTargetConfiguration(responseData);
229+
}
230+
231+
/* Callback when command results in failure */
232+
static void OnReadFailureResponse(void * context, CHIP_ERROR error)
233+
{
234+
ChipLogProgress(Controller, "OnReadFailureResponse - Binding Read Failed");
235+
236+
MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
237+
listener->clearContext();
238+
239+
CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController();
240+
if (cdc != nullptr)
241+
{
242+
cdc->PostCommissioningFailed(error);
243+
}
207244
}
208245

209246
/* Callback when command results in success */
@@ -227,6 +264,60 @@ class MyPostCommissioningListener : public PostCommissioningListener
227264
cdc->PostCommissioningFailed(error);
228265
}
229266
}
267+
268+
void
269+
finishTargetConfiguration(const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseList)
270+
{
271+
std::vector<app::Clusters::Binding::Structs::TargetStruct::Type> bindings;
272+
NodeId localNodeId = GetDeviceCommissioner()->GetNodeId();
273+
274+
auto iter = responseList.begin();
275+
while (iter.Next())
276+
{
277+
auto & binding = iter.GetValue();
278+
ChipLogProgress(Controller, "Binding found nodeId=0x" ChipLogFormatX64 " my nodeId=0x" ChipLogFormatX64,
279+
ChipLogValueX64(binding.node.ValueOr(0)), ChipLogValueX64(localNodeId));
280+
if (binding.node.ValueOr(0) != localNodeId)
281+
{
282+
ChipLogProgress(Controller, "Found a binding for a different node, preserving");
283+
bindings.push_back(binding);
284+
}
285+
else
286+
{
287+
ChipLogProgress(Controller, "Found a binding for a matching node, dropping");
288+
}
289+
}
290+
291+
Optional<SessionHandle> opt = mSecureSession.Get();
292+
SessionHandle & sessionHandle = opt.Value();
293+
ContentAppPlatform::GetInstance().ManageClientAccess(*mExchangeMgr, sessionHandle, mVendorId, mProductId, localNodeId,
294+
bindings, OnSuccessResponse, OnFailureResponse);
295+
clearContext();
296+
}
297+
298+
void cacheContext(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
299+
SessionHandle & sessionHandle)
300+
{
301+
mVendorId = vendorId;
302+
mProductId = productId;
303+
mNodeId = nodeId;
304+
mExchangeMgr = &exchangeMgr;
305+
mSecureSession.ShiftToSession(sessionHandle);
306+
}
307+
308+
void clearContext()
309+
{
310+
mVendorId = 0;
311+
mProductId = 0;
312+
mNodeId = 0;
313+
mExchangeMgr = nullptr;
314+
mSecureSession.SessionReleased();
315+
}
316+
uint16_t mVendorId = 0;
317+
uint16_t mProductId = 0;
318+
NodeId mNodeId = 0;
319+
Messaging::ExchangeManager * mExchangeMgr = nullptr;
320+
SessionHolder mSecureSession;
230321
};
231322

232323
MyPostCommissioningListener gMyPostCommissioningListener;

examples/tv-app/linux/AppImpl.cpp

+106-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@
4242
#include <lib/support/CodeUtils.h>
4343
#include <lib/support/ZclString.h>
4444
#include <platform/CHIPDeviceLayer.h>
45+
#include <zap-generated/CHIPClusters.h>
4546

4647
using namespace chip;
4748
using namespace chip::AppPlatform;
49+
using namespace chip::app::Clusters;
4850

4951
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
5052
class MyUserPrompter : public UserPrompter
@@ -89,9 +91,44 @@ class MyPostCommissioningListener : public PostCommissioningListener
8991
void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
9092
SessionHandle & sessionHandle) override
9193
{
94+
// read current binding list
95+
chip::Controller::BindingCluster cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId);
9296

93-
ContentAppPlatform::GetInstance().ManageClientAccess(
94-
exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse);
97+
cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle);
98+
99+
CHIP_ERROR err =
100+
cluster.ReadAttribute<Binding::Attributes::Binding::TypeInfo>(this, OnReadSuccessResponse, OnReadFailureResponse);
101+
if (err != CHIP_NO_ERROR)
102+
{
103+
ChipLogError(Controller, "Failed in reading binding. Error %s", ErrorStr(err));
104+
clearContext();
105+
}
106+
}
107+
108+
/* Callback when command results in success */
109+
static void
110+
OnReadSuccessResponse(void * context,
111+
const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseData)
112+
{
113+
ChipLogProgress(Controller, "OnReadSuccessResponse - Binding Read Successfully");
114+
115+
MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
116+
listener->finishTargetConfiguration(responseData);
117+
}
118+
119+
/* Callback when command results in failure */
120+
static void OnReadFailureResponse(void * context, CHIP_ERROR error)
121+
{
122+
ChipLogProgress(Controller, "OnReadFailureResponse - Binding Read Failed");
123+
124+
MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
125+
listener->clearContext();
126+
127+
CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController();
128+
if (cdc != nullptr)
129+
{
130+
cdc->PostCommissioningFailed(error);
131+
}
95132
}
96133

97134
/* Callback when command results in success */
@@ -115,6 +152,60 @@ class MyPostCommissioningListener : public PostCommissioningListener
115152
cdc->PostCommissioningFailed(error);
116153
}
117154
}
155+
156+
void
157+
finishTargetConfiguration(const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseList)
158+
{
159+
std::vector<app::Clusters::Binding::Structs::TargetStruct::Type> bindings;
160+
NodeId localNodeId = GetDeviceCommissioner()->GetNodeId();
161+
162+
auto iter = responseList.begin();
163+
while (iter.Next())
164+
{
165+
auto & binding = iter.GetValue();
166+
ChipLogProgress(Controller, "Binding found nodeId=0x" ChipLogFormatX64 " my nodeId=0x" ChipLogFormatX64,
167+
ChipLogValueX64(binding.node.ValueOr(0)), ChipLogValueX64(localNodeId));
168+
if (binding.node.ValueOr(0) != localNodeId)
169+
{
170+
ChipLogProgress(Controller, "Found a binding for a different node, preserving");
171+
bindings.push_back(binding);
172+
}
173+
else
174+
{
175+
ChipLogProgress(Controller, "Found a binding for a matching node, dropping");
176+
}
177+
}
178+
179+
Optional<SessionHandle> opt = mSecureSession.Get();
180+
SessionHandle & sessionHandle = opt.Value();
181+
ContentAppPlatform::GetInstance().ManageClientAccess(*mExchangeMgr, sessionHandle, mVendorId, mProductId, localNodeId,
182+
bindings, OnSuccessResponse, OnFailureResponse);
183+
clearContext();
184+
}
185+
186+
void cacheContext(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
187+
SessionHandle & sessionHandle)
188+
{
189+
mVendorId = vendorId;
190+
mProductId = productId;
191+
mNodeId = nodeId;
192+
mExchangeMgr = &exchangeMgr;
193+
mSecureSession.ShiftToSession(sessionHandle);
194+
}
195+
196+
void clearContext()
197+
{
198+
mVendorId = 0;
199+
mProductId = 0;
200+
mNodeId = 0;
201+
mExchangeMgr = nullptr;
202+
mSecureSession.SessionReleased();
203+
}
204+
uint16_t mVendorId = 0;
205+
uint16_t mProductId = 0;
206+
NodeId mNodeId = 0;
207+
Messaging::ExchangeManager * mExchangeMgr = nullptr;
208+
SessionHolder mSecureSession;
118209
};
119210

120211
MyPostCommissioningListener gMyPostCommissioningListener;
@@ -407,6 +498,19 @@ Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
407498
return Access::Privilege::kOperate;
408499
}
409500

501+
std::list<ClusterId> ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
502+
uint16_t productId)
503+
{
504+
if (endpointId == kLocalVideoPlayerEndpointId)
505+
{
506+
return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id,
507+
chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id,
508+
chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id,
509+
chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id };
510+
}
511+
return {};
512+
}
513+
410514
} // namespace AppPlatform
411515
} // namespace chip
412516

examples/tv-app/linux/AppImpl.h

+5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
131131
// When a vendor has admin privileges, it will get access to all clusters on ep1
132132
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;
133133

134+
// Get the cluster list this vendorId/productId should have on static endpoints such as ep1 for casting video clients.
135+
// When a vendor has admin privileges, it will get access to all clusters on ep1
136+
std::list<ClusterId> GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
137+
uint16_t productId) override;
138+
134139
void AddAdminVendorId(uint16_t vendorId);
135140

136141
protected:

src/app/app-platform/ContentAppPlatform.cpp

+18-30
Original file line numberDiff line numberDiff line change
@@ -510,27 +510,11 @@ CHIP_ERROR ContentAppPlatform::GetACLEntryIndex(size_t * foundIndex, FabricIndex
510510
return CHIP_ERROR_NOT_FOUND;
511511
}
512512

513-
constexpr EndpointId kTargetBindingClusterEndpointId = 0;
514-
constexpr EndpointId kLocalVideoPlayerEndpointId = 1;
515-
constexpr EndpointId kLocalSpeakerEndpointId = 2;
516-
constexpr ClusterId kClusterIdDescriptor = 0x001d;
517-
constexpr ClusterId kClusterIdOnOff = 0x0006;
518-
constexpr ClusterId kClusterIdWakeOnLAN = 0x0503;
519-
// constexpr ClusterId kClusterIdChannel = 0x0504;
520-
// constexpr ClusterId kClusterIdTargetNavigator = 0x0505;
521-
constexpr ClusterId kClusterIdMediaPlayback = 0x0506;
522-
// constexpr ClusterId kClusterIdMediaInput = 0x0507;
523-
constexpr ClusterId kClusterIdLowPower = 0x0508;
524-
constexpr ClusterId kClusterIdKeypadInput = 0x0509;
525-
constexpr ClusterId kClusterIdContentLauncher = 0x050a;
526-
constexpr ClusterId kClusterIdAudioOutput = 0x050b;
527-
// constexpr ClusterId kClusterIdApplicationLauncher = 0x050c;
528-
// constexpr ClusterId kClusterIdAccountLogin = 0x050e;
529-
530513
// Add ACLs on this device for the given client,
531514
// and create bindings on the given client so that it knows what it has access to.
532515
CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & exchangeMgr, SessionHandle & sessionHandle,
533-
uint16_t targetVendorId, NodeId localNodeId,
516+
uint16_t targetVendorId, uint16_t targetProductId, NodeId localNodeId,
517+
std::vector<Binding::Structs::TargetStruct::Type> bindings,
534518
Controller::WriteResponseSuccessCallback successCb,
535519
Controller::WriteResponseFailureCallback failureCb)
536520
{
@@ -564,8 +548,6 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e
564548
ReturnErrorOnFailure(entry.SetPrivilege(vendorPrivilege));
565549
ReturnErrorOnFailure(entry.AddSubject(nullptr, subjectNodeId));
566550

567-
std::vector<Binding::Structs::TargetStruct::Type> bindings;
568-
569551
/**
570552
* Here we are creating a single ACL entry containing:
571553
* a) selection of clusters on video player endpoint (8 targets)
@@ -588,21 +570,22 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e
588570

589571
ChipLogProgress(Controller, "Create video player endpoint ACL and binding");
590572
{
573+
bool hasClusterAccess = false;
591574
if (vendorPrivilege == Access::Privilege::kAdminister)
592575
{
593576
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess Admin privilege granted");
594577
// a vendor with admin privilege gets access to all clusters on ep1
595578
Access::AccessControl::Entry::Target target = { .flags = Access::AccessControl::Entry::Target::kEndpoint,
596579
.endpoint = kLocalVideoPlayerEndpointId };
597580
ReturnErrorOnFailure(entry.AddTarget(nullptr, target));
581+
hasClusterAccess = true;
598582
}
599583
else
600584
{
601585
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess non-Admin privilege granted");
602586
// a vendor with non-admin privilege gets access to select clusters on ep1
603-
std::list<ClusterId> allowedClusterList = { kClusterIdDescriptor, kClusterIdOnOff, kClusterIdWakeOnLAN,
604-
kClusterIdMediaPlayback, kClusterIdLowPower, kClusterIdKeypadInput,
605-
kClusterIdContentLauncher, kClusterIdAudioOutput };
587+
std::list<ClusterId> allowedClusterList = mContentAppFactory->GetAllowedClusterListForStaticEndpoint(
588+
kLocalVideoPlayerEndpointId, targetVendorId, targetProductId);
606589

607590
for (const auto & clusterId : allowedClusterList)
608591
{
@@ -611,16 +594,21 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e
611594
.cluster = clusterId,
612595
.endpoint = kLocalVideoPlayerEndpointId };
613596
ReturnErrorOnFailure(entry.AddTarget(nullptr, target));
597+
hasClusterAccess = true;
614598
}
615599
}
616600

617-
bindings.push_back(Binding::Structs::TargetStruct::Type{
618-
.node = MakeOptional(localNodeId),
619-
.group = NullOptional,
620-
.endpoint = MakeOptional(kLocalVideoPlayerEndpointId),
621-
.cluster = NullOptional,
622-
.fabricIndex = kUndefinedFabricIndex,
623-
});
601+
if (hasClusterAccess)
602+
{
603+
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess adding a binding on ep1");
604+
bindings.push_back(Binding::Structs::TargetStruct::Type{
605+
.node = MakeOptional(localNodeId),
606+
.group = NullOptional,
607+
.endpoint = MakeOptional(kLocalVideoPlayerEndpointId),
608+
.cluster = NullOptional,
609+
.fabricIndex = kUndefinedFabricIndex,
610+
});
611+
}
624612
}
625613

626614
ChipLogProgress(Controller, "Create speaker endpoint ACL and binding");

0 commit comments

Comments
 (0)