blob: 0efe4518337929e158088c368b6836b231b3fc63 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* 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.
*/
/**
* @file
* DeviceControllerFactory is a singleton utility class that manages the
* runtime DeviceControllerSystemState and provides APIs to setup DeviceControllers
* and DeviceCommissioners.
*
* Together with the SystemState this class implicitly manages the lifecycle of the underlying
* CHIP stack. It lazily initializes the CHIPStack when setting up Controllers if the SystemState
* was previously shutdown.
*/
#pragma once
#include <controller/CHIPDeviceController.h>
#include <controller/CHIPDeviceControllerSystemState.h>
#include <credentials/GroupDataProvider.h>
#include <credentials/OperationalCertificateStore.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <protocols/secure_channel/SessionResumptionStorage.h>
namespace chip {
namespace Controller {
struct SetupParams
{
OperationalCredentialsDelegate * operationalCredentialsDelegate = nullptr;
/* The following keypair must correspond to the public key used for generating
controllerNOC. It's used by controller to establish CASE sessions with devices */
Crypto::P256Keypair * operationalKeypair = nullptr;
/**
* Controls whether or not the operationalKeypair should be owned by the
* caller. By default, this is false, but if the keypair cannot be
* serialized, then setting this to true will allow the caller to manage
* this keypair's lifecycle.
*/
bool hasExternallyOwnedOperationalKeypair = false;
/* The following certificates must be in x509 DER format */
ByteSpan controllerNOC;
ByteSpan controllerICAC;
ByteSpan controllerRCAC;
//
// This must be set to a valid, operational VendorId value associated with
// the controller/commissioner.
//
chip::VendorId controllerVendorId = VendorId::Unspecified;
// The Device Pairing Delegated used to initialize a Commissioner
DevicePairingDelegate * pairingDelegate = nullptr;
/**
* Controls whether we permit multiple DeviceController instances to exist
* on the same logical fabric (identified by the tuple of the fabric's
* root public key + fabric id).
*
* Each controller instance will be associated with its own FabricIndex.
* This pivots the FabricTable to tracking identities instead of fabrics,
* represented by FabricInfo instances that can have colliding logical fabrics.
*
*/
bool permitMultiControllerFabrics = false;
//
// Controls enabling server cluster interactions on a controller. This in turn
// causes the following to get enabled:
//
// - CASEServer to listen for unsolicited Sigma1 messages.
// - Advertisement of active controller operational identities.
//
bool enableServerInteractions = false;
/**
* Controls whether shutdown of the controller removes the corresponding
* entry from the in-memory fabric table, but NOT from storage.
*
* Note that this means that after controller shutdown the storage and
* in-memory versions of the fabric table will be out of sync.
* For compatibility reasons this is the default behavior.
*
* @see deleteFromFabricTableOnShutdown
*/
bool removeFromFabricTableOnShutdown = true;
/**
* Controls whether shutdown of the controller deletes the corresponding
* entry from the fabric table (both in-memory and storage).
*
* If both `removeFromFabricTableOnShutdown` and this setting are true,
* this setting will take precedence.
*
* @see removeFromFabricTableOnShutdown
*/
bool deleteFromFabricTableOnShutdown = false;
/**
* Specifies whether to utilize the fabric table entry for the given FabricIndex
* for initialization. If provided and neither the operational key pair nor the NOC
* chain are provided, then attempt to locate a fabric corresponding to the given FabricIndex.
*/
chip::Optional<FabricIndex> fabricIndex;
Credentials::DeviceAttestationVerifier * deviceAttestationVerifier = nullptr;
CommissioningDelegate * defaultCommissioner = nullptr;
};
// TODO everything other than the fabric storage, group data provider, OperationalKeystore,
// OperationalCertificateStore, SessionKeystore, and SessionResumptionStorage here should
// be removed. We're blocked because of the need to support !CHIP_DEVICE_LAYER
struct FactoryInitParams
{
System::Layer * systemLayer = nullptr;
PersistentStorageDelegate * fabricIndependentStorage = nullptr;
Credentials::CertificateValidityPolicy * certificateValidityPolicy = nullptr;
Credentials::GroupDataProvider * groupDataProvider = nullptr;
app::reporting::ReportScheduler::TimerDelegate * timerDelegate = nullptr;
Crypto::SessionKeystore * sessionKeystore = nullptr;
Inet::EndPointManager<Inet::TCPEndPoint> * tcpEndPointManager = nullptr;
Inet::EndPointManager<Inet::UDPEndPoint> * udpEndPointManager = nullptr;
FabricTable * fabricTable = nullptr;
Crypto::OperationalKeystore * operationalKeystore = nullptr;
Credentials::OperationalCertificateStore * opCertStore = nullptr;
SessionResumptionStorage * sessionResumptionStorage = nullptr;
#if CONFIG_NETWORK_LAYER_BLE
Ble::BleLayer * bleLayer = nullptr;
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
Transport::WiFiPAFLayer * wifipaf_layer = nullptr;
#endif
//
// Controls enabling server cluster interactions on a controller. This in turn
// causes the following to get enabled:
//
// - Advertisement of active controller operational identities.
//
bool enableServerInteractions = false;
/* The port used for operational communication to listen for and send messages over UDP/TCP.
* The default value of `0` will pick any available port. */
uint16_t listenPort = 0;
// MUST NOT be null during initialization: every application must define the
// data model it wants to use. Backwards-compatibility can use `CodegenDataModelProviderInstance`
// for ember/zap-generated models.
chip::app::DataModel::Provider * dataModelProvider = nullptr;
};
class DeviceControllerFactory
{
public:
static DeviceControllerFactory & GetInstance()
{
static DeviceControllerFactory instance;
return instance;
}
CHIP_ERROR Init(FactoryInitParams params);
// Shuts down matter and frees the system state.
//
// Must not be called while any controllers are alive, or while any calls
// to RetainSystemState or EnsureAndRetainSystemState have not been balanced
// by a call to ReleaseSystemState.
void Shutdown();
CHIP_ERROR SetupController(SetupParams params, DeviceController & controller);
CHIP_ERROR SetupCommissioner(SetupParams params, DeviceCommissioner & commissioner);
// ----- IO -----
/**
* @brief
* Start the event loop task within the CHIP stack
* @return CHIP_ERROR The return status
*/
CHIP_ERROR ServiceEvents();
~DeviceControllerFactory();
DeviceControllerFactory(DeviceControllerFactory const &) = delete;
void operator=(DeviceControllerFactory const &) = delete;
//
// Some clients do not prefer a complete shutdown of the stack being initiated if
// all device controllers have ceased to exist. To avoid that, this method has been
// created to permit retention of the underlying system state.
//
// Calls to this method must be balanced by calling ReleaseSystemState before Shutdown.
//
void RetainSystemState();
//
// To initiate shutdown of the stack upon termination of all resident controllers in the
// system, invoke this method to decrement the refcount on the system state and consequently,
// shut-down the stack.
//
// This should only be invoked if a matching call to RetainSystemState() was called prior.
//
// Returns true if stack was shut down in response to this call, or false otherwise.
//
bool ReleaseSystemState();
// Like RetainSystemState(), but will re-initialize the system state first if necessary.
// Calls to this method must be balanced by calling ReleaseSystemState before Shutdown.
CHIP_ERROR EnsureAndRetainSystemState();
//
// Retrieve a read-only pointer to the system state object that contains pointers to key stack
// singletons. If the pointer is null, it indicates that the DeviceControllerFactory has yet to
// be initialized properly, or has already been shut-down.
//
// This pointer ceases to be valid after a call to Shutdown has been made, or if all active
// DeviceController instances have gone to 0. Consequently, care has to be taken to correctly
// sequence the shutting down of active controllers with any entity that interacts with objects
// present in the system state object. If de-coupling is desired, RetainSystemState and
// ReleaseSystemState can be used to avoid this.
//
const DeviceControllerSystemState * GetSystemState() const { return mSystemState; }
class ControllerFabricDelegate final : public chip::FabricTable::Delegate
{
public:
CHIP_ERROR Init(SessionResumptionStorage * sessionResumptionStorage, Credentials::GroupDataProvider * groupDataProvider)
{
VerifyOrReturnError(sessionResumptionStorage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(groupDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
mSessionResumptionStorage = sessionResumptionStorage;
mGroupDataProvider = groupDataProvider;
return CHIP_NO_ERROR;
};
void OnFabricRemoved(const chip::FabricTable & fabricTable, FabricIndex fabricIndex) override
{
(void) fabricTable;
if (mGroupDataProvider != nullptr)
{
mGroupDataProvider->RemoveFabric(fabricIndex);
}
ClearCASEResumptionStateOnFabricChange(fabricIndex);
};
void OnFabricUpdated(const chip::FabricTable & fabricTable, chip::FabricIndex fabricIndex) override
{
(void) fabricTable;
ClearCASEResumptionStateOnFabricChange(fabricIndex);
}
private:
void ClearCASEResumptionStateOnFabricChange(chip::FabricIndex fabricIndex)
{
VerifyOrReturn(mSessionResumptionStorage != nullptr);
CHIP_ERROR err = mSessionResumptionStorage->DeleteAll(fabricIndex);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller,
"Warning, failed to delete session resumption state for fabric index 0x%x: %" CHIP_ERROR_FORMAT,
static_cast<unsigned>(fabricIndex), err.Format());
}
}
Credentials::GroupDataProvider * mGroupDataProvider = nullptr;
SessionResumptionStorage * mSessionResumptionStorage = nullptr;
};
private:
DeviceControllerFactory() {}
void PopulateInitParams(ControllerInitParams & controllerParams, const SetupParams & params);
CHIP_ERROR InitSystemState(FactoryInitParams params);
CHIP_ERROR ReinitSystemStateIfNecessary();
void ControllerInitialized(const DeviceController & controller);
uint16_t mListenPort;
DeviceControllerSystemState * mSystemState = nullptr;
PersistentStorageDelegate * mFabricIndependentStorage = nullptr;
Crypto::OperationalKeystore * mOperationalKeystore = nullptr;
Credentials::OperationalCertificateStore * mOpCertStore = nullptr;
Credentials::CertificateValidityPolicy * mCertificateValidityPolicy = nullptr;
SessionResumptionStorage * mSessionResumptionStorage = nullptr;
bool mEnableServerInteractions = false;
};
} // namespace Controller
} // namespace chip