blob: c110e6e72a9edcf9f2f0125a22e50767d00e79dc [file]
/**
*
* Copyright (c) 2022-2025 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 <app/icd/server/ICDConfigurationData.h>
#include <app/server-cluster/DefaultServerCluster.h>
#include <app/server-cluster/OptionalAttributeSet.h>
#include <app/util/basic-types.h>
#include <clusters/IcdManagement/Commands.h>
#include <clusters/IcdManagement/Metadata.h>
#include <lib/core/Optional.h>
#include <lib/support/Span.h>
#include <app/icd/server/ICDServerConfig.h>
#if CHIP_CONFIG_ENABLE_ICD_CIP
#include <credentials/FabricTable.h>
#include <crypto/SessionKeystore.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
#include <app/icd/server/ICDStateObserver.h>
namespace chip {
namespace Crypto {
using SymmetricKeystore = Crypto::SessionKeystore;
} // namespace Crypto
namespace app {
namespace Clusters {
namespace IcdManagement {
enum class OptionalCommands : uint8_t
{
kStayActive = 0x01,
};
constexpr size_t kUserActiveModeTriggerInstructionMaxLength = 128;
} // namespace IcdManagement
/**
* @brief ICD Management Cluster
*
* This class provides the core ICD Management functionality. When CIP (Check-In Protocol)
* features are needed, use ICDManagementClusterWithCIP which extends this class.
*/
class ICDManagementCluster : public DefaultServerCluster, public chip::app::ICDStateObserver
{
public:
using OptionalAttributeSet = app::OptionalAttributeSet<IcdManagement::Attributes::UserActiveModeTriggerInstruction::Id>;
// TODO: The interaction between enabledCommands and feature flags (particularly LITS) needs clarification.
// According to spec, LITS implies StayActiveRequest support. Options:
// 1. Document that kStayActive bit in enabledCommands is ignored when LITS feature is set
// 2. Add Startup() validation to fail if enabledCommands and feature flags are inconsistent,
// and simplify AcceptedCommands/GeneratedCommands to only check mEnabledCommands
/**
* @brief Constructor for ICDManagementCluster
*
* @param userActiveModeTriggerInstruction The instruction string is copied into an internal buffer
* during construction. The caller does not need to maintain the lifetime of the CharSpan
* or its underlying data after the constructor returns. If the instruction exceeds
* kUserActiveModeTriggerInstructionMaxLength (128 bytes), it will be truncated.
*/
ICDManagementCluster(EndpointId endpointId, Crypto::SymmetricKeystore & symmetricKeystore, FabricTable & fabricTable,
ICDConfigurationData & icdConfigurationData, OptionalAttributeSet optionalAttributeSet,
BitMask<IcdManagement::OptionalCommands> enabledCommands,
BitMask<IcdManagement::UserActiveModeTriggerBitmap> userActiveModeTriggerBitmap,
CharSpan userActiveModeTriggerInstruction);
CHIP_ERROR Startup(ServerClusterContext & context) override;
void Shutdown(ClusterShutdownType type) override;
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & aEncoder) override;
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
std::optional<DataModel::ActionReturnStatus> InvokeCommand(const DataModel::InvokeRequest & request,
TLV::TLVReader & input_arguments, CommandHandler * handler) override;
CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path,
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) override;
CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<CommandId> & builder) override;
private:
void OnEnterActiveMode() override{};
void OnEnterIdleMode() override{};
void OnTransitionToIdle() override{};
void OnICDModeChange() override;
protected:
#if CHIP_CONFIG_ENABLE_ICD_LIT
CHIP_ERROR ReadOperatingMode(AttributeValueEncoder & encoder);
#endif // CHIP_CONFIG_ENABLE_ICD_LIT
Crypto::SymmetricKeystore & mSymmetricKeystore;
FabricTable & mFabricTable;
ICDConfigurationData & mICDConfigurationData;
const OptionalAttributeSet mOptionalAttributeSet;
const BitMask<IcdManagement::UserActiveModeTriggerBitmap> mUserActiveModeTriggerBitmap;
const BitMask<IcdManagement::OptionalCommands> mEnabledCommands;
uint8_t mUserActiveModeTriggerInstructionLength;
char mUserActiveModeTriggerInstruction[IcdManagement::kUserActiveModeTriggerInstructionMaxLength];
};
#if CHIP_CONFIG_ENABLE_ICD_CIP
/**
* @brief Implementation of Fabric Delegate for ICD Management cluster
*/
class ICDManagementFabricDelegate : public FabricTable::Delegate
{
public:
void Init(PersistentStorageDelegate & storage, Crypto::SymmetricKeystore * symmetricKeystore,
ICDConfigurationData & icdConfigurationData);
void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override;
private:
PersistentStorageDelegate * mStorage = nullptr;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
ICDConfigurationData * mICDConfigurationData = nullptr;
};
/**
* @brief ICD Management Cluster with CIP (Check-In Protocol) support
*
* This subclass extends ICDManagementCluster with CIP functionality,
* including client registration/unregistration and fabric delegate management.
* The fabric delegate is automatically registered/unregistered in Startup/Shutdown.
*
* @param userActiveModeTriggerInstruction The instruction string is copied into an internal buffer
* during construction (by the base class). The caller does not need to maintain the lifetime
* of the CharSpan or its underlying data after the constructor returns.
*/
class ICDManagementClusterWithCIP : public ICDManagementCluster
{
public:
ICDManagementClusterWithCIP(EndpointId endpointId, Crypto::SymmetricKeystore & symmetricKeystore, FabricTable & fabricTable,
ICDConfigurationData & icdConfigurationData, OptionalAttributeSet optionalAttributeSet,
BitMask<IcdManagement::OptionalCommands> enabledCommands,
BitMask<IcdManagement::UserActiveModeTriggerBitmap> userActiveModeTriggerBitmap,
CharSpan userActiveModeTriggerInstruction);
CHIP_ERROR Startup(ServerClusterContext & context) override;
void Shutdown(ClusterShutdownType shutdownType) override;
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & aEncoder) override;
CHIP_ERROR Attributes(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) override;
std::optional<DataModel::ActionReturnStatus> InvokeCommand(const DataModel::InvokeRequest & request,
TLV::TLVReader & input_arguments, CommandHandler * handler) override;
CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path,
ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) override;
CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, ReadOnlyBufferBuilder<CommandId> & builder) override;
private:
void MarkRegisteredClientsListChanged();
CHIP_ERROR ReadRegisteredClients(AttributeValueEncoder & encoder);
/**
* @brief Triggers table update events to notify subscribers that an entry was added or removed
* from the ICDMonitoringTable.
*/
void TriggerICDMTableUpdatedEvent();
/**
* @brief Function that executes the business logic of the RegisterClient Command
*
* @param[out] icdCounter If function succeeds, icdCounter will have the current value of the ICDCounter stored in the
* ICDConfigurationData If function fails, icdCounter will be unchanged
* @return Status
*/
Protocols::InteractionModel::Status RegisterClient(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
const IcdManagement::Commands::RegisterClient::DecodableType & commandData,
uint32_t & icdCounter);
Protocols::InteractionModel::Status
UnregisterClient(CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
const IcdManagement::Commands::UnregisterClient::DecodableType & commandData);
ICDManagementFabricDelegate mFabricDelegate;
};
#endif // CHIP_CONFIG_ENABLE_ICD_CIP
} // namespace Clusters
} // namespace app
} // namespace chip