Skip to content

Commit edec6a9

Browse files
committed
Add initial feature logic for Terms and Conditions (TC) acknowledgements
This commit introduces the initial logic for handling Terms and Conditions (TC) acknowledgements in the General Commissioning cluster. The logic includes support for setting and checking TC acknowledgements and versions during the commissioning process. Changes include: - Handling TC acknowledgements and TC acknowledgement version in the pairing command. - Logic to read TC attributes and check TC acceptance in the General Commissioning server. - Introduction of classes to manage TC acceptance logic. - Initialization and use of TC providers in the server setup. - Addition of a new commissioning stage for TC acknowledgements in the commissioning flow. The feature logic is currently disabled and will be enabled in an example in a subsequent commit.
1 parent 16d67ed commit edec6a9

20 files changed

+1550
-129
lines changed

examples/chip-tool/commands/pairing/PairingCommand.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 Project CHIP Authors
2+
* Copyright (c) 2020-2024 Project CHIP Authors
33
* All rights reserved.
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -120,6 +120,17 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()
120120
params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value()));
121121
}
122122

123+
// mTCAcknowledgements and mTCAcknowledgementVersion are optional, but related. When one is missing, default the value to 0, to
124+
// increase the test tools ability to test the applications.
125+
if (mTCAcknowledgements.HasValue() || mTCAcknowledgementVersion.HasValue())
126+
{
127+
TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = {
128+
.acceptedTermsAndConditions = mTCAcknowledgements.ValueOr(0),
129+
.acceptedTermsAndConditionsVersion = mTCAcknowledgementVersion.ValueOr(0),
130+
};
131+
params.SetTermsAndConditionsAcknowledgement(termsAndConditionsAcknowledgement);
132+
}
133+
123134
// mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones.
124135
// Since optional Complex arguments are not currently supported via the <chip::Optional> class,
125136
// we will use mTimeZoneList.data() value to determine if the argument was provided.

examples/chip-tool/commands/pairing/PairingCommand.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 Project CHIP Authors
2+
* Copyright (c) 2020-2024 Project CHIP Authors
33
* All rights reserved.
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -182,6 +182,14 @@ class PairingCommand : public CHIPCommand,
182182
AddArgument("dst-offset", &mComplex_DSTOffsets,
183183
"DSTOffset list to use when setting Time Synchronization cluster's DSTOffset attribute",
184184
Argument::kOptional);
185+
186+
AddArgument("tc-acknowledgements", 0, UINT16_MAX, &mTCAcknowledgements,
187+
"Terms and Conditions acknowledgements to use to set the General Commissioning cluster's TC "
188+
"Acknowledgements bit-field");
189+
190+
AddArgument("tc-acknowledgements-version", 0, UINT16_MAX, &mTCAcknowledgementVersion,
191+
"Terms and Conditions acknowledgement version to use to set the General Commissioning cluster's TC "
192+
"Acknowledgement version");
185193
}
186194

187195
AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
@@ -238,6 +246,8 @@ class PairingCommand : public CHIPCommand,
238246
chip::Optional<chip::ByteSpan> mICDSymmetricKey;
239247
chip::Optional<uint64_t> mICDMonitoredSubject;
240248
chip::Optional<uint32_t> mICDStayActiveDurationMsec;
249+
chip::Optional<uint16_t> mTCAcknowledgements;
250+
chip::Optional<uint16_t> mTCAcknowledgementVersion;
241251
chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> mTimeZoneList;
242252
TypedComplexArgument<chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>>
243253
mComplex_TimeZones;

src/app/clusters/general-commissioning-server/general-commissioning-server.cpp

+159-48
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright (c) 2021 Project CHIP Authors
3+
* Copyright (c) 2021-2024 Project CHIP Authors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -27,13 +27,15 @@
2727
#include <app/CommandHandler.h>
2828
#include <app/ConcreteCommandPath.h>
2929
#include <app/server/CommissioningWindowManager.h>
30+
#include <app/server/EnhancedSetupFlowProvider.h>
3031
#include <app/server/Server.h>
3132
#include <app/util/attribute-storage.h>
3233
#include <lib/support/Span.h>
3334
#include <lib/support/logging/CHIPLogging.h>
3435
#include <platform/CHIPDeviceConfig.h>
3536
#include <platform/ConfigurationManager.h>
3637
#include <platform/DeviceControlServer.h>
38+
#include <system/SystemConfig.h>
3739
#include <tracing/macros.h>
3840

3941
using namespace chip;
@@ -57,6 +59,55 @@ using Transport::Session;
5759

5860
namespace {
5961

62+
template <typename T, typename K>
63+
static CHIP_ERROR ReadInternal(const T * const provider, CHIP_ERROR (T::*getter)(K &) const, AttributeValueEncoder & aEncoder)
64+
{
65+
K data;
66+
67+
if (nullptr == provider)
68+
{
69+
return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
70+
}
71+
72+
CHIP_ERROR err = (provider->*getter)(data);
73+
if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE)
74+
{
75+
data = 0;
76+
}
77+
else if (err != CHIP_NO_ERROR)
78+
{
79+
return err;
80+
}
81+
82+
return aEncoder.Encode(data);
83+
}
84+
85+
template <typename Provider, typename T>
86+
static CHIP_ERROR ReadInternal(Provider * provider, CHIP_ERROR (Provider::*getter)(T &), AttributeValueEncoder & aEncoder)
87+
{
88+
const Provider * constProvider = provider;
89+
CHIP_ERROR (Provider::*constGetter)(T &) const = reinterpret_cast<CHIP_ERROR (Provider::*const)(T &) const>(getter);
90+
return ReadInternal(constProvider, constGetter, aEncoder);
91+
}
92+
93+
template <typename T, typename K>
94+
static CHIP_ERROR ReadInternal(const T & provider, CHIP_ERROR (T::*getter)(K &) const, AttributeValueEncoder & aEncoder)
95+
{
96+
return ReadInternal(&provider, getter, aEncoder);
97+
}
98+
99+
template <typename T, typename K>
100+
static CHIP_ERROR ReadInternal(T & provider, CHIP_ERROR (T::*getter)(K &), AttributeValueEncoder & aEncoder)
101+
{
102+
return ReadInternal(&provider, getter, aEncoder);
103+
}
104+
105+
template <typename... Args>
106+
static CHIP_ERROR ReadIfSupported(Args &&... args)
107+
{
108+
return ReadInternal(std::forward<Args>(args)...);
109+
}
110+
60111
class GeneralCommissioningAttrAccess : public AttributeAccessInterface
61112
{
62113
public:
@@ -66,7 +117,6 @@ class GeneralCommissioningAttrAccess : public AttributeAccessInterface
66117
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
67118

68119
private:
69-
CHIP_ERROR ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), AttributeValueEncoder & aEncoder);
70120
CHIP_ERROR ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder);
71121
CHIP_ERROR ReadSupportsConcurrentConnection(AttributeValueEncoder & aEncoder);
72122
};
@@ -84,39 +134,43 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath
84134
switch (aPath.mAttributeId)
85135
{
86136
case RegulatoryConfig::Id: {
87-
return ReadIfSupported(&ConfigurationManager::GetRegulatoryLocation, aEncoder);
137+
return ReadIfSupported(DeviceLayer::ConfigurationMgr(), &ConfigurationManager::GetRegulatoryLocation, aEncoder);
88138
}
89139
case LocationCapability::Id: {
90-
return ReadIfSupported(&ConfigurationManager::GetLocationCapability, aEncoder);
140+
return ReadIfSupported(DeviceLayer::ConfigurationMgr(), &ConfigurationManager::GetLocationCapability, aEncoder);
91141
}
92142
case BasicCommissioningInfo::Id: {
93143
return ReadBasicCommissioningInfo(aEncoder);
94144
}
95145
case SupportsConcurrentConnection::Id: {
96146
return ReadSupportsConcurrentConnection(aEncoder);
97147
}
98-
default: {
99-
break;
148+
#if defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS && defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION
149+
case TCAcceptedVersion::Id: {
150+
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
151+
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion;
152+
return ReadIfSupported(provider, getter, aEncoder);
100153
}
154+
case TCMinRequiredVersion::Id: {
155+
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
156+
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion;
157+
return ReadIfSupported(provider, getter, aEncoder);
101158
}
102-
return CHIP_NO_ERROR;
103-
}
104-
105-
CHIP_ERROR GeneralCommissioningAttrAccess::ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &),
106-
AttributeValueEncoder & aEncoder)
107-
{
108-
uint8_t data;
109-
CHIP_ERROR err = (DeviceLayer::ConfigurationMgr().*getter)(data);
110-
if (err == CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE)
111-
{
112-
data = 0;
159+
case TCAcknowledgements::Id: {
160+
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
161+
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements;
162+
return ReadIfSupported(provider, getter, aEncoder);
113163
}
114-
else if (err != CHIP_NO_ERROR)
115-
{
116-
return err;
164+
case TCAcknowledgementsRequired::Id: {
165+
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
166+
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgements;
167+
return ReadIfSupported(provider, getter, aEncoder);
117168
}
118-
119-
return aEncoder.Encode(data);
169+
#endif
170+
default:
171+
break;
172+
}
173+
return CHIP_NO_ERROR;
120174
}
121175

122176
CHIP_ERROR GeneralCommissioningAttrAccess::ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder)
@@ -214,9 +268,12 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback(
214268
{
215269
MATTER_TRACE_SCOPE("CommissioningComplete", "GeneralCommissioning");
216270

217-
DeviceControlServer * devCtrl = &DeviceLayer::DeviceControlServer::DeviceControlSvr();
218-
auto & failSafe = Server::GetInstance().GetFailSafeContext();
219-
auto & fabricTable = Server::GetInstance().GetFabricTable();
271+
#if defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS && defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION
272+
EnhancedSetupFlowProvider * enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();
273+
#endif
274+
DeviceControlServer * const devCtrl = &DeviceLayer::DeviceControlServer::DeviceControlSvr();
275+
auto & failSafe = Server::GetInstance().GetFailSafeContext();
276+
auto & fabricTable = Server::GetInstance().GetFabricTable();
220277

221278
ChipLogProgress(FailSafe, "GeneralCommissioning: Received CommissioningComplete");
222279

@@ -239,34 +296,64 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback(
239296
}
240297
else
241298
{
242-
if (failSafe.NocCommandHasBeenInvoked())
299+
CHIP_ERROR err;
300+
301+
#if defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS && defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION
302+
303+
uint16_t termsAndConditionsAcceptedAcknowledgements;
304+
bool hasTermsAndConditionsRequiredAcknowledgementsBeenAccepted;
305+
bool hasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted;
306+
307+
err = enhancedSetupFlowProvider->GetTermsAndConditionsAcceptedAcknowledgements(
308+
termsAndConditionsAcceptedAcknowledgements);
309+
CheckSuccess(err, Failure);
310+
311+
err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(
312+
hasTermsAndConditionsRequiredAcknowledgementsBeenAccepted);
313+
CheckSuccess(err, Failure);
314+
315+
err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(
316+
hasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted);
317+
CheckSuccess(err, Failure);
318+
319+
if (!hasTermsAndConditionsRequiredAcknowledgementsBeenAccepted)
243320
{
244-
CHIP_ERROR err = fabricTable.CommitPendingFabricData();
245-
if (err != CHIP_NO_ERROR)
246-
{
247-
// No need to revert on error: CommitPendingFabricData always reverts if not fully successful.
248-
ChipLogError(FailSafe, "GeneralCommissioning: Failed to commit pending fabric data: %" CHIP_ERROR_FORMAT,
249-
err.Format());
250-
}
251-
else
321+
ChipLogError(AppServer, "Required terms and conditions have not been accepted");
322+
Breadcrumb::Set(commandPath.mEndpointId, 0);
323+
response.errorCode = (0 == termsAndConditionsAcceptedAcknowledgements)
324+
? CommissioningErrorEnum::kTCAcknowledgementsNotReceived
325+
: CommissioningErrorEnum::kRequiredTCNotAccepted;
326+
}
327+
328+
else if (!hasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted)
329+
{
330+
ChipLogError(AppServer, "Minimum terms and conditions version has not been accepted");
331+
Breadcrumb::Set(commandPath.mEndpointId, 0);
332+
response.errorCode = CommissioningErrorEnum::kTCMinVersionNotMet;
333+
}
334+
335+
else
336+
#endif
337+
{
338+
if (failSafe.NocCommandHasBeenInvoked())
252339
{
340+
err = fabricTable.CommitPendingFabricData();
341+
CheckSuccess(err, Failure);
253342
ChipLogProgress(FailSafe, "GeneralCommissioning: Successfully commited pending fabric data");
254343
}
255-
CheckSuccess(err, Failure);
256-
}
257344

258-
/*
259-
* Pass fabric of commissioner to DeviceControlSvr.
260-
* This allows device to send messages back to commissioner.
261-
* Once bindings are implemented, this may no longer be needed.
262-
*/
263-
failSafe.DisarmFailSafe();
264-
CheckSuccess(
265-
devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex()),
266-
Failure);
345+
/*
346+
* Pass fabric of commissioner to DeviceControlSvr.
347+
* This allows device to send messages back to commissioner.
348+
* Once bindings are implemented, this may no longer be needed.
349+
*/
350+
failSafe.DisarmFailSafe();
351+
err = devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex());
352+
CheckSuccess(err, Failure);
267353

268-
Breadcrumb::Set(commandPath.mEndpointId, 0);
269-
response.errorCode = CommissioningErrorEnum::kOk;
354+
Breadcrumb::Set(commandPath.mEndpointId, 0);
355+
response.errorCode = CommissioningErrorEnum::kOk;
356+
}
270357
}
271358
}
272359

@@ -328,13 +415,37 @@ bool emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(app::CommandH
328415
return true;
329416
}
330417

418+
bool emberAfGeneralCommissioningClusterSetTCAcknowledgementsCallback(
419+
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
420+
const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgements::DecodableType & commandData)
421+
{
422+
#if defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS && defined CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION
423+
MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning");
424+
Commands::SetTCAcknowledgementsResponse::Type response;
425+
EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();
426+
uint16_t acknowledgements = commandData.TCUserResponse;
427+
uint16_t acknowledgementsVersion = commandData.TCVersion;
428+
CheckSuccess(enhancedSetupFlowProvider->SetTermsAndConditionsAcceptance(acknowledgements, acknowledgementsVersion), Failure);
429+
response.errorCode = CommissioningErrorEnum::kOk;
430+
431+
commandObj->AddResponse(commandPath, response);
432+
#endif
433+
return true;
434+
}
435+
331436
namespace {
332437
void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
333438
{
334-
if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
439+
switch (event->Type)
335440
{
441+
case DeviceLayer::DeviceEventType::kFailSafeTimerExpired: {
336442
// Spec says to reset Breadcrumb attribute to 0.
337443
Breadcrumb::Set(0, 0);
444+
break;
445+
}
446+
default: {
447+
break;
448+
}
338449
}
339450
}
340451

src/app/server/BUILD.gn

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020 Project CHIP Authors
1+
# Copyright (c) 2020-2024 Project CHIP Authors
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -36,14 +36,20 @@ static_library("server") {
3636
"CommissioningWindowManager.h",
3737
"DefaultAclStorage.cpp",
3838
"DefaultAclStorage.h",
39+
"DefaultEnhancedSetupFlowProvider.cpp",
40+
"DefaultEnhancedSetupFlowProvider.h",
41+
"DefaultTermsAndConditionsProvider.cpp",
42+
"DefaultTermsAndConditionsProvider.h",
3943
"Dnssd.cpp",
4044
"Dnssd.h",
4145
"EchoHandler.cpp",
4246
"EchoHandler.h",
47+
"EnhancedSetupFlowProvider.h",
4348
"OnboardingCodesUtil.cpp",
4449
"OnboardingCodesUtil.h",
4550
"Server.cpp",
4651
"Server.h",
52+
"TermsAndConditionsProvider.h",
4753
]
4854

4955
public_configs = [ ":server_config" ]

0 commit comments

Comments
 (0)