Skip to content

Commit

Permalink
Add initial feature logic for Terms and Conditions (TC) acknowledgements
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
swan-amazon committed Aug 12, 2024
1 parent e994cbf commit 99dcfe9
Show file tree
Hide file tree
Showing 16 changed files with 1,427 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2024 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.
Expand All @@ -27,6 +27,9 @@
#include <app/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <app/server/CommissioningWindowManager.h>
#if CHIP_CONFIG_TC_REQUIRED
#include <app/server/EnhancedSetupFlowProvider.h>
#endif
#include <app/server/Server.h>
#include <app/util/attribute-storage.h>
#include <lib/support/Span.h>
Expand Down Expand Up @@ -69,6 +72,12 @@ class GeneralCommissioningAttrAccess : public AttributeAccessInterface
CHIP_ERROR ReadIfSupported(CHIP_ERROR (ConfigurationManager::*getter)(uint8_t &), AttributeValueEncoder & aEncoder);
CHIP_ERROR ReadBasicCommissioningInfo(AttributeValueEncoder & aEncoder);
CHIP_ERROR ReadSupportsConcurrentConnection(AttributeValueEncoder & aEncoder);
template <typename Provider, typename T>
CHIP_ERROR ReadEnhancedSetupFlowProvider(Provider * const provider, CHIP_ERROR (Provider::*const nonConstGetter)(T &),
AttributeValueEncoder & aEncoder);
template <typename Provider, typename T>
CHIP_ERROR ReadEnhancedSetupFlowProvider(Provider * const provider, CHIP_ERROR (Provider::*const getter)(T &) const,
AttributeValueEncoder & aEncoder);
};

GeneralCommissioningAttrAccess gAttrAccess;
Expand All @@ -95,6 +104,28 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath
case SupportsConcurrentConnection::Id: {
return ReadSupportsConcurrentConnection(aEncoder);
}
#if CHIP_CONFIG_TC_REQUIRED
case TCAcceptedVersion::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgementsVersion;
return ReadEnhancedSetupFlowProvider(provider, getter, aEncoder);
}
case TCMinRequiredVersion::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsRequiredAcknowledgementsVersion;
return ReadEnhancedSetupFlowProvider(provider, getter, aEncoder);
}
case TCAcknowledgements::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::GetTermsAndConditionsAcceptedAcknowledgements;
return ReadEnhancedSetupFlowProvider(provider, getter, aEncoder);
}
case TCAcknowledgementsRequired::Id: {
auto provider = Server::GetInstance().GetEnhancedSetupFlowProvider();
auto getter = &EnhancedSetupFlowProvider::IsTermsAndConditionsAcceptanceRequired;
return ReadEnhancedSetupFlowProvider(provider, getter, aEncoder);
}
#endif
default: {
break;
}
Expand Down Expand Up @@ -144,6 +175,100 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadSupportsConcurrentConnection(Attr
return aEncoder.Encode(supportsConcurrentConnection);
}

template <typename Provider, typename T>
CHIP_ERROR GeneralCommissioningAttrAccess::ReadEnhancedSetupFlowProvider(Provider * const provider,
CHIP_ERROR (Provider::*const nonConstGetter)(T &),
AttributeValueEncoder & aEncoder)
{
if (nullptr == provider)
{
return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
}

T value;
CHIP_ERROR err = (provider->*nonConstGetter)(value);
if (err != CHIP_NO_ERROR)
{
return err;
}

return aEncoder.Encode(value);
}

template <typename Provider, typename T>
CHIP_ERROR GeneralCommissioningAttrAccess::ReadEnhancedSetupFlowProvider(Provider * const provider,
CHIP_ERROR (Provider::*const getter)(T &) const,
AttributeValueEncoder & aEncoder)
{
// Removing the const qualifier from the getter function pointer because there are a handful of getter functions that are not
// correctly marked as const.
using NonConstGetter = CHIP_ERROR (Provider::*)(T &);
NonConstGetter nonConstGetter = reinterpret_cast<NonConstGetter>(getter);
return ReadEnhancedSetupFlowProvider(provider, nonConstGetter, aEncoder);
}

} // anonymous namespace
namespace {

#if CHIP_CONFIG_TC_REQUIRED
CHIP_ERROR checkTermsAndConditionsAcknowledgementsState(CommissioningErrorEnum & errorCode)
{
EnhancedSetupFlowProvider * enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();

CHIP_ERROR err;

uint16_t termsAndConditionsAcceptedAcknowledgements;
bool hasRequiredTermAccepted;
bool hasRequiredTermVersionAccepted;

err = enhancedSetupFlowProvider->GetTermsAndConditionsAcceptedAcknowledgements(termsAndConditionsAcceptedAcknowledgements);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to GetTermsAndConditionsAcceptedAcknowledgements");
return err;
}

err = enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted(hasRequiredTermAccepted);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsBeenAccepted");
return err;
}

err =
enhancedSetupFlowProvider->HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted(hasRequiredTermVersionAccepted);
if (!::chip::ChipError::IsSuccess(err))
{
ChipLogError(AppServer, "Failed to HasTermsAndConditionsRequiredAcknowledgementsVersionBeenAccepted");
return err;
}

if (!hasRequiredTermAccepted)
{
uint16_t requiredAcknowledgements = 0;
(void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgements(requiredAcknowledgements);

ChipLogProgress(AppServer, "Required terms and conditions, 0x%04x,have not been accepted", requiredAcknowledgements);
errorCode = (0 == termsAndConditionsAcceptedAcknowledgements) ? CommissioningErrorEnum::kTCAcknowledgementsNotReceived
: CommissioningErrorEnum::kRequiredTCNotAccepted;
return CHIP_NO_ERROR;
}

if (!hasRequiredTermVersionAccepted)
{
uint16_t requiredAcknowledgementsVersion = 0;
(void) enhancedSetupFlowProvider->GetTermsAndConditionsRequiredAcknowledgementsVersion(requiredAcknowledgementsVersion);
ChipLogProgress(AppServer, "Minimum terms and conditions version, 0x%04x, has not been accepted",
requiredAcknowledgementsVersion);
errorCode = CommissioningErrorEnum::kTCMinVersionNotMet;
return CHIP_NO_ERROR;
}

errorCode = CommissioningErrorEnum::kOk;
return CHIP_NO_ERROR;
}
#endif

} // anonymous namespace

bool emberAfGeneralCommissioningClusterArmFailSafeCallback(app::CommandHandler * commandObj,
Expand Down Expand Up @@ -239,6 +364,10 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback(
}
else
{
#if CHIP_CONFIG_TC_REQUIRED
CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure);
#endif

if (failSafe.NocCommandHasBeenInvoked())
{
CHIP_ERROR err = fabricTable.CommitPendingFabricData();
Expand Down Expand Up @@ -328,13 +457,39 @@ bool emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(app::CommandH
return true;
}

bool emberAfGeneralCommissioningClusterSetTCAcknowledgementsCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgements::DecodableType & commandData)
{
#if !CHIP_CONFIG_TC_REQUIRED
return false;

#else
MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning");
Commands::SetTCAcknowledgementsResponse::Type response;
EnhancedSetupFlowProvider * const enhancedSetupFlowProvider = Server::GetInstance().GetEnhancedSetupFlowProvider();
uint16_t acknowledgements = commandData.TCUserResponse;
uint16_t acknowledgementsVersion = commandData.TCVersion;
CheckSuccess(enhancedSetupFlowProvider->SetTermsAndConditionsAcceptance(acknowledgements, acknowledgementsVersion), Failure);
CheckSuccess(checkTermsAndConditionsAcknowledgementsState(response.errorCode), Failure);
commandObj->AddResponse(commandPath, response);
return true;

#endif
}

namespace {
void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
if (event->Type == DeviceLayer::DeviceEventType::kFailSafeTimerExpired)
{
// Spec says to reset Breadcrumb attribute to 0.
Breadcrumb::Set(0, 0);

#if CHIP_CONFIG_TC_REQUIRED
// Clear terms and conditions acceptance on failsafe timer expiration
Server::GetInstance().GetEnhancedSetupFlowProvider()->ClearTermsAndConditionsAcceptance();
#endif
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/app/common_flags.gni
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ declare_args() {
chip_enable_read_client = true
chip_build_controller_dynamic_server = false

chip_config_tc_required = false
chip_config_tc_required_acknowledgements = 0
chip_config_tc_required_acknowledgements_version = 0

# Flag that controls whether the time-to-wait from BUSY responses is
# communicated to OperationalSessionSetup API consumers.
chip_enable_busy_handling_for_operational_session_setup = true
Expand Down
42 changes: 41 additions & 1 deletion src/app/server/BUILD.gn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020 Project CHIP Authors
# Copyright (c) 2020-2024 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.
Expand All @@ -24,6 +24,41 @@ config("server_config") {
}
}

config("enhanced_setup_flow_config") {
defines = []
if (chip_config_tc_required) {
defines += [
"CHIP_CONFIG_TC_REQUIRED=1",
"CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS=${chip_config_tc_required_acknowledgements}",
"CHIP_CONFIG_TC_REQUIRED_ACKNOWLEDGEMENTS_VERSION=${chip_config_tc_required_acknowledgements_version}",
]
} else {
defines += [ "CHIP_CONFIG_TC_REQUIRED=0" ]
}
}

source_set("enhanced_setup_flow_interface") {
sources = [
"DefaultEnhancedSetupFlowProvider.h",
"DefaultTermsAndConditionsProvider.h",
"EnhancedSetupFlowProvider.h",
"TermsAndConditionsProvider.h",
]

public_configs = [ ":enhanced_setup_flow_config" ]

public_deps = [ "${chip_root}/src/lib/core" ]
}

source_set("enhanced_setup_flow") {
sources = [
"DefaultEnhancedSetupFlowProvider.cpp",
"DefaultTermsAndConditionsProvider.cpp",
]

deps = [ ":enhanced_setup_flow_interface" ]
}

static_library("server") {
output_name = "libCHIPAppServer"

Expand Down Expand Up @@ -51,6 +86,7 @@ static_library("server") {
cflags = [ "-Wconversion" ]

public_deps = [
":enhanced_setup_flow_interface",
"${chip_root}/src/app",
"${chip_root}/src/app:test-event-trigger",
"${chip_root}/src/app/icd/server:check-in-back-off",
Expand Down Expand Up @@ -79,4 +115,8 @@ static_library("server") {
[ "${chip_root}/src/app/icd/server:default-check-in-back-off" ]
}
}

if (chip_config_tc_required) {
public_deps += [ ":enhanced_setup_flow" ]
}
}
Loading

0 comments on commit 99dcfe9

Please sign in to comment.