From 20d5f21499a9105a6465d3bf3738b0c9f005c679 Mon Sep 17 00:00:00 2001 From: Jerry Johns Date: Wed, 9 Feb 2022 16:55:25 -0800 Subject: [PATCH] Enable CASE Server on a Controller This minimally enables the CASE server on devices that utilize the `DeviceController` and related classes. Specifically, it instantiates the CASEServer as part of initializing the `DeviceControllerFactory`, sets it up to listen for unsolicited messages (Sigma R1) and enables the advertisement of the controller's operational identity on the network to permit discovery and resolution. Testing: Creates two Python REPL instances with matching persistent storage op certs. On the first REPL instance, ran: >> devCtrl2 = fabricAdmins[0].NewController(nodeId=22) On the second REPL instance, ran: >> devCtrl.ResolveNode(22) Confirmed from the logs that CASE was established. --- src/app/server/Dnssd.cpp | 37 +++++++------ src/app/server/Dnssd.h | 21 ++++++++ src/controller/BUILD.gn | 1 + src/controller/CHIPDeviceController.cpp | 11 ++++ src/controller/CHIPDeviceController.h | 8 +++ .../CHIPDeviceControllerFactory.cpp | 52 +++++++++++++++++++ src/controller/CHIPDeviceControllerFactory.h | 17 ++++++ .../CHIPDeviceControllerSystemState.h | 9 +++- .../ChipDeviceController-ScriptBinding.cpp | 7 +-- src/controller/python/OpCredsBinding.cpp | 2 + 10 files changed, 143 insertions(+), 22 deletions(-) diff --git a/src/app/server/Dnssd.cpp b/src/app/server/Dnssd.cpp index 1d079593b1d51d..1af45f0573f791 100644 --- a/src/app/server/Dnssd.cpp +++ b/src/app/server/Dnssd.cpp @@ -41,21 +41,6 @@ namespace chip { namespace app { namespace { -bool HaveOperationalCredentials() -{ - // Look for any fabric info that has a useful operational identity. - for (const FabricInfo & fabricInfo : Server::GetInstance().GetFabricTable()) - { - if (fabricInfo.IsInitialized()) - { - return true; - } - } - - ChipLogProgress(Discovery, "Failed to find a valid admin pairing. Node ID unknown"); - return false; -} - void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event) { if (event->Type == DeviceLayer::DeviceEventType::kDnssdPlatformInitialized @@ -78,6 +63,26 @@ void OnPlatformEventWrapper(const DeviceLayer::ChipDeviceEvent * event, intptr_t constexpr System::Clock::Timestamp DnssdServer::kTimeoutCleared; +DnssdServer::DnssdServer() +{ + mFabricTable = &Server::GetInstance().GetFabricTable(); +} + +bool DnssdServer::HaveOperationalCredentials() +{ + // Look for any fabric info that has a useful operational identity. + for (const FabricInfo & fabricInfo : *mFabricTable) + { + if (fabricInfo.IsInitialized()) + { + return true; + } + } + + ChipLogProgress(Discovery, "Failed to find a valid admin pairing. Node ID unknown"); + return false; +} + #if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY constexpr const char kExtendedDiscoveryTimeoutKeypairStorage[] = "ExtDiscKey"; @@ -250,7 +255,7 @@ CHIP_ERROR DnssdServer::GetCommissionableInstanceName(char * buffer, size_t buff /// Set MDNS operational advertisement CHIP_ERROR DnssdServer::AdvertiseOperational() { - for (const FabricInfo & fabricInfo : Server::GetInstance().GetFabricTable()) + for (const FabricInfo & fabricInfo : *mFabricTable) { if (fabricInfo.IsInitialized()) { diff --git a/src/app/server/Dnssd.h b/src/app/server/Dnssd.h index b92410306690d7..7468ebaa1146da 100644 --- a/src/app/server/Dnssd.h +++ b/src/app/server/Dnssd.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -57,6 +58,16 @@ class DLL_EXPORT DnssdServer /// Gets the factory-new state commissionable node discovery timeout int16_t GetDiscoveryTimeoutSecs() { return mDiscoveryTimeoutSecs; } + // + // Override the referenced fabric table from the default that is present + // in Server::GetInstance().GetFabricTable() to something else. + // + void SetFabricTable(FabricTable * table) + { + VerifyOrDie(table != nullptr); + mFabricTable = table; + } + /// Callback from Discovery Expiration timer /// Checks if discovery has expired and if so, /// kicks off extend discovery (when enabled) @@ -92,6 +103,8 @@ class DLL_EXPORT DnssdServer CHIP_ERROR GetCommissionableInstanceName(char * buffer, size_t bufferLen); private: + DnssdServer(); + /// Overloaded utility method for commissioner and commissionable advertisement /// This method is used for both commissioner discovery and commissionable node discovery since /// they share many fields. @@ -105,6 +118,12 @@ class DLL_EXPORT DnssdServer /// Set MDNS commissionable node advertisement CHIP_ERROR AdvertiseCommissionableNode(chip::Dnssd::CommissioningMode mode); + // + // Check if we have any valid operational credentials present in the fabric table and return true + // if we do. + // + bool HaveOperationalCredentials(); + Time::TimeSource mTimeSource; void ClearTimeouts() @@ -115,6 +134,8 @@ class DLL_EXPORT DnssdServer #endif // CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY } + FabricTable * mFabricTable; + // Helper for StartServer. void StartServer(Optional mode); diff --git a/src/controller/BUILD.gn b/src/controller/BUILD.gn index 4b58532fb46eba..84702a7f0fddb3 100644 --- a/src/controller/BUILD.gn +++ b/src/controller/BUILD.gn @@ -60,6 +60,7 @@ static_library("controller") { public_deps = [ "${chip_root}/src/app", + "${chip_root}/src/app/server", "${chip_root}/src/lib/core", "${chip_root}/src/lib/dnssd", "${chip_root}/src/lib/support", diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 5c62aef675c9c1..7a5a9b2bd048b5 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -45,6 +45,8 @@ #include #endif +#include + #include #include #include @@ -138,6 +140,15 @@ CHIP_ERROR DeviceController::Init(ControllerInitParams params) if (params.operationalKeypair != nullptr || !params.controllerNOC.empty() || !params.controllerRCAC.empty()) { ReturnErrorOnFailure(ProcessControllerNOCChain(params)); + + if (params.enableServerInteractions) + { + // + // Advertise our operational identity on the network to facilitate discovery by clients that look to + // establish CASE with a controller that is also offering server-side capabilities (e.g an OTA provider). + // + app::DnssdServer::Instance().AdvertiseOperational(); + } } DeviceProxyInitParams deviceInitParams = { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 039a281cdfc65d..84bb909d5aede9 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -108,6 +108,14 @@ struct ControllerInitParams ByteSpan controllerICAC; ByteSpan controllerRCAC; + // + // 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; + uint16_t controllerVendorId; }; diff --git a/src/controller/CHIPDeviceControllerFactory.cpp b/src/controller/CHIPDeviceControllerFactory.cpp index 67f125270529fe..080e35bdf83434 100644 --- a/src/controller/CHIPDeviceControllerFactory.cpp +++ b/src/controller/CHIPDeviceControllerFactory.cpp @@ -22,6 +22,7 @@ * that vends Controller objects */ +#include "platform/ConnectivityManager.h" #include #include @@ -32,6 +33,9 @@ #include #endif +#include +#include + using namespace chip::Inet; using namespace chip::System; using namespace chip::Credentials; @@ -116,6 +120,9 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) stateParams.transportMgr = chip::Platform::New(); + // + // The logic below expects IPv6 to be at index 0 of this tuple. Please do not alter that. + // ReturnErrorOnFailure(stateParams.transportMgr->Init(Transport::UdpListenParameters(stateParams.udpEndPointManager) .SetAddressType(Inet::IPAddressType::kIPv6) .SetListenPort(mListenPort) @@ -135,6 +142,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) stateParams.sessionMgr = chip::Platform::New(); stateParams.exchangeMgr = chip::Platform::New(); stateParams.messageCounterManager = chip::Platform::New(); + stateParams.sessionIDAllocator = chip::Platform::New(); ReturnErrorOnFailure(stateParams.fabricTable->Init(mFabricStorage)); ReturnErrorOnFailure( @@ -150,6 +158,36 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) ReturnErrorOnFailure(Dnssd::Resolver::Instance().Init(stateParams.udpEndPointManager)); #endif // CHIP_DEVICE_CONFIG_ENABLE_DNSSD + if (params.enableServerInteractions) + { + stateParams.caseServer = chip::Platform::New(); + + ReturnErrorOnFailure(stateParams.caseServer->ListenForSessionEstablishment( + stateParams.exchangeMgr, stateParams.transportMgr, DeviceLayer::ConnectivityMgr().GetBleLayer(), stateParams.sessionMgr, + stateParams.fabricTable, stateParams.sessionIDAllocator)); + + // + // We need to advertise the port that we're listening to for unsolicited messages over UDP. However, we have both a IPv6 + // and IPv6 endpoint to pick from. Since IPv6 is POR for Matter, let's go ahead and pick that port. + // + app::DnssdServer::Instance().SetSecuredPort(stateParams.transportMgr->GetTransport().GetImplAtIndex<0>().GetBoundPort()); + + // + // TODO: This is a hack to workaround the fact that we have a bi-polar stack that have controller and server modalities that + // are mutually exclusive in terms of initialization of key stack singletons. Consequently, DnssdServer accesses + // Server::GetInstance().GetFabricTable() to access the fabric table, but we don't want to do that when we're initializing + // the controller logic since the factory here has its own fabric table. + // + // Consequently, reach in set the fabric table pointer to point to the right version. + // + app::DnssdServer::Instance().SetFabricTable(stateParams.fabricTable); + + // + // Start up the DNS-SD server + // + chip::app::DnssdServer::Instance().StartServer(chip::Dnssd::CommissioningMode::kDisabled); + } + // store the system state mSystemState = chip::Platform::New(stateParams); ChipLogDetail(Controller, "System State Initialized..."); @@ -170,6 +208,8 @@ void DeviceControllerFactory::PopulateInitParams(ControllerInitParams & controll controllerParams.systemState = mSystemState; controllerParams.controllerVendorId = params.controllerVendorId; + + controllerParams.enableServerInteractions = params.enableServerInteractions; } CHIP_ERROR DeviceControllerFactory::SetupController(SetupParams params, DeviceController & controller) @@ -296,6 +336,18 @@ CHIP_ERROR DeviceControllerSystemState::Shutdown() mFabrics = nullptr; } + if (mCASEServer != nullptr) + { + chip::Platform::Delete(mCASEServer); + mCASEServer = nullptr; + } + + if (mSessionIDAllocator != nullptr) + { + chip::Platform::Delete(mSessionIDAllocator); + mSessionIDAllocator = nullptr; + } + return CHIP_NO_ERROR; } diff --git a/src/controller/CHIPDeviceControllerFactory.h b/src/controller/CHIPDeviceControllerFactory.h index 68de0144909e2e..f4e6831faec75f 100644 --- a/src/controller/CHIPDeviceControllerFactory.h +++ b/src/controller/CHIPDeviceControllerFactory.h @@ -60,6 +60,15 @@ struct SetupParams // The Device Pairing Delegated used to initialize a Commissioner DevicePairingDelegate * pairingDelegate = nullptr; + // + // 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; + Credentials::DeviceAttestationVerifier * deviceAttestationVerifier = nullptr; CommissioningDelegate * defaultCommissioner = nullptr; }; @@ -76,6 +85,14 @@ struct FactoryInitParams Ble::BleLayer * bleLayer = 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; diff --git a/src/controller/CHIPDeviceControllerSystemState.h b/src/controller/CHIPDeviceControllerSystemState.h index 6c2a3e0cfb726c..2aadf83de7e273 100644 --- a/src/controller/CHIPDeviceControllerSystemState.h +++ b/src/controller/CHIPDeviceControllerSystemState.h @@ -30,7 +30,9 @@ #pragma once #include +#include #include + #include #include #if CONFIG_DEVICE_LAYER @@ -72,6 +74,8 @@ struct DeviceControllerSystemStateParams Messaging::ExchangeManager * exchangeMgr = nullptr; secure_channel::MessageCounterManager * messageCounterManager = nullptr; FabricTable * fabricTable = nullptr; + CASEServer * caseServer = nullptr; + SessionIDAllocator * sessionIDAllocator = nullptr; }; // A representation of the internal state maintained by the DeviceControllerFactory @@ -84,7 +88,8 @@ class DeviceControllerSystemState DeviceControllerSystemState(DeviceControllerSystemStateParams params) : mSystemLayer(params.systemLayer), mTCPEndPointManager(params.tcpEndPointManager), mUDPEndPointManager(params.udpEndPointManager), mTransportMgr(params.transportMgr), mSessionMgr(params.sessionMgr), - mExchangeMgr(params.exchangeMgr), mMessageCounterManager(params.messageCounterManager), mFabrics(params.fabricTable) + mExchangeMgr(params.exchangeMgr), mMessageCounterManager(params.messageCounterManager), mFabrics(params.fabricTable), + mCASEServer(params.caseServer), mSessionIDAllocator(params.sessionIDAllocator) { #if CONFIG_NETWORK_LAYER_BLE mBleLayer = params.bleLayer; @@ -145,6 +150,8 @@ class DeviceControllerSystemState Messaging::ExchangeManager * mExchangeMgr = nullptr; secure_channel::MessageCounterManager * mMessageCounterManager = nullptr; FabricTable * mFabrics = nullptr; + CASEServer * mCASEServer = nullptr; + SessionIDAllocator * mSessionIDAllocator = nullptr; std::atomic mRefCount{ 1 }; diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 7a6300522a90d0..63f07944937616 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -224,7 +224,8 @@ ChipError::StorageType pychip_DeviceController_StackInit() VerifyOrReturnError(err == CHIP_NO_ERROR, err.AsInteger()); FactoryInitParams factoryParams; - factoryParams.fabricStorage = &sFabricStorage; + factoryParams.fabricStorage = &sFabricStorage; + factoryParams.enableServerInteractions = true; ReturnErrorOnFailure(DeviceControllerFactory::GetInstance().Init(factoryParams).AsInteger()); @@ -239,10 +240,6 @@ ChipError::StorageType pychip_DeviceController_StackInit() // DeviceControllerFactory::GetInstance().RetainSystemState(); -#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY - chip::app::DnssdServer::Instance().StartServer(chip::Dnssd::CommissioningMode::kDisabled); -#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY - return CHIP_NO_ERROR.AsInteger(); } diff --git a/src/controller/python/OpCredsBinding.cpp b/src/controller/python/OpCredsBinding.cpp index a943673780567a..9b8d57bb0cca5f 100644 --- a/src/controller/python/OpCredsBinding.cpp +++ b/src/controller/python/OpCredsBinding.cpp @@ -173,6 +173,8 @@ ChipError::StorageType pychip_OpCreds_AllocateController(OpCredsContext * contex initParams.controllerRCAC = rcacSpan; initParams.controllerICAC = icacSpan; initParams.controllerNOC = nocSpan; + initParams.enableServerInteractions = true; + if (useTestCommissioner) { initParams.defaultCommissioner = &sTestCommissioner;