Skip to content

Commit

Permalink
Enable CASE Server on a Controller
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mrjerryjohns committed Feb 10, 2022
1 parent 14eb3f5 commit 20d5f21
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 22 deletions.
37 changes: 21 additions & 16 deletions src/app/server/Dnssd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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";
Expand Down Expand Up @@ -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())
{
Expand Down
21 changes: 21 additions & 0 deletions src/app/server/Dnssd.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#pragma once

#include <credentials/FabricTable.h>
#include <lib/core/CHIPError.h>
#include <lib/core/Optional.h>
#include <lib/dnssd/Advertiser.h>
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand All @@ -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<Time::Source::kSystem> mTimeSource;

void ClearTimeouts()
Expand All @@ -115,6 +134,8 @@ class DLL_EXPORT DnssdServer
#endif // CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY
}

FabricTable * mFabricTable;

// Helper for StartServer.
void StartServer(Optional<Dnssd::CommissioningMode> mode);

Expand Down
1 change: 1 addition & 0 deletions src/controller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 11 additions & 0 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#include <platform/ConfigurationManager.h>
#endif

#include <app/server/Dnssd.h>

#include <app/InteractionModelEngine.h>
#include <app/OperationalDeviceProxy.h>
#include <app/util/error-mapping.h>
Expand Down Expand Up @@ -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 = {
Expand Down
8 changes: 8 additions & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
52 changes: 52 additions & 0 deletions src/controller/CHIPDeviceControllerFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* that vends Controller objects
*/

#include "platform/ConnectivityManager.h"
#include <controller/CHIPDeviceControllerFactory.h>

#include <app/util/DataModelHandler.h>
Expand All @@ -32,6 +33,9 @@
#include <platform/ConfigurationManager.h>
#endif

#include <app/server/Dnssd.h>
#include <protocols/secure_channel/CASEServer.h>

using namespace chip::Inet;
using namespace chip::System;
using namespace chip::Credentials;
Expand Down Expand Up @@ -116,6 +120,9 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params)

stateParams.transportMgr = chip::Platform::New<DeviceTransportMgr>();

//
// 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)
Expand All @@ -135,6 +142,7 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params)
stateParams.sessionMgr = chip::Platform::New<SessionManager>();
stateParams.exchangeMgr = chip::Platform::New<Messaging::ExchangeManager>();
stateParams.messageCounterManager = chip::Platform::New<secure_channel::MessageCounterManager>();
stateParams.sessionIDAllocator = chip::Platform::New<SessionIDAllocator>();

ReturnErrorOnFailure(stateParams.fabricTable->Init(mFabricStorage));
ReturnErrorOnFailure(
Expand All @@ -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<CASEServer>();

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<DeviceControllerSystemState>(stateParams);
ChipLogDetail(Controller, "System State Initialized...");
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down
17 changes: 17 additions & 0 deletions src/controller/CHIPDeviceControllerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion src/controller/CHIPDeviceControllerSystemState.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
#pragma once

#include <credentials/FabricTable.h>
#include <protocols/secure_channel/CASEServer.h>
#include <protocols/secure_channel/MessageCounterManager.h>

#include <transport/TransportMgr.h>
#include <transport/raw/UDP.h>
#if CONFIG_DEVICE_LAYER
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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<uint32_t> mRefCount{ 1 };

Expand Down
7 changes: 2 additions & 5 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand All @@ -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();
}

Expand Down
2 changes: 2 additions & 0 deletions src/controller/python/OpCredsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 20d5f21

Please sign in to comment.