/* * * 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 #include #include #include #include #include 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; 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 * tcpEndPointManager = nullptr; Inet::EndPointManager * 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; }; 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(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