| /* |
| * |
| * 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 |