Skip to content

Commit

Permalink
Use multi-endpoint wildcard to simplify commissioning
Browse files Browse the repository at this point in the history
  • Loading branch information
cecille committed Jan 29, 2022
1 parent 420142b commit fa799d9
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 250 deletions.
1 change: 1 addition & 0 deletions src/app/AttributeCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ class AttributeCache : protected ReadClient::Callback
}
}
}
return CHIP_NO_ERROR;
}

/*
Expand Down
129 changes: 27 additions & 102 deletions src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,30 +96,13 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
return CHIP_NO_ERROR;
}

bool AutoCommissioner::NetworkClusterUseable()
{
return (mNetworkTechnology.Has(app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kWiFiNetworkInterface) &&
mParams.GetWiFiCredentials().HasValue()) ||
(mNetworkTechnology.Has(app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface) &&
mParams.GetThreadOperationalDataset().HasValue());
}

CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStage currentStage, CHIP_ERROR & lastErr)
{
if (lastErr != CHIP_NO_ERROR)
{
return CommissioningStage::kCleanup;
}

bool checkNetworkTechnology = false;
if (currentStage == CommissioningStage::kCheckEndpointIsCommissionable && mNeedsNetworkSetup && mNetworkEndpoint == mEndpoint)
{
// We found a networking cluster on the current endpoint, but have not yet checked the feature map to
// see what network technologies are supported.
checkNetworkTechnology = true;
}

mEndpoint = 0;
switch (currentStage)
{
case CommissioningStage::kSecurePairing:
Expand All @@ -129,38 +112,15 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
case CommissioningStage::kReadProductId:
return CommissioningStage::kReadSoftwareVersion;
case CommissioningStage::kReadSoftwareVersion:
return CommissioningStage::kGetPartsList;
case CommissioningStage::kGetPartsList:
return CommissioningStage::kCheckEndpointIsCommissionable;
case CommissioningStage::kCheckEndpointIsCommissionable:
if (checkNetworkTechnology)
{
if(mNeedsNetworkSetup) {
return CommissioningStage::kGetNetworkTechnology;
}
else
{
return CommissioningStage::kArmFailsafe;
}
case CommissioningStage::kGetNetworkTechnology:
if (mNeedsNetworkSetup && !NetworkClusterUseable())
{
if (mAllEndpoints.numEndpoints > 0)
{
// Cycle through the list of endpoints from the end, checking for network cluster.
mEndpoint = mAllEndpoints.endpoints[--mAllEndpoints.numEndpoints];
return CommissioningStage::kCheckEndpointIsCommissionable;
}
else
{
ChipLogError(Controller, "Unable to find a suitable network commissioning cluster for the given parameters");
lastErr = CHIP_ERROR_INVALID_ARGUMENT;
return CommissioningStage::kCleanup;
}
}
else
{
return CommissioningStage::kArmFailsafe;
}
return CommissioningStage::kArmFailsafe;
case CommissioningStage::kArmFailsafe:
return CommissioningStage::kConfigRegulatory;
case CommissioningStage::kConfigRegulatory:
Expand All @@ -185,16 +145,11 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
// operational network because the provisioning of certificates will trigger the device to start operational advertising.
if (mNeedsNetworkSetup)
{
mEndpoint = mNetworkEndpoint;
if (mParams.GetWiFiCredentials().HasValue() &&
mNetworkTechnology.Has(
chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kWiFiNetworkInterface))
if (mParams.GetWiFiCredentials().HasValue() && mNetworkEndpoints.wifi != kInvalidEndpointId)
{
return CommissioningStage::kWiFiNetworkSetup;
}
else if (mParams.GetThreadOperationalDataset().HasValue() &&
mNetworkTechnology.Has(
chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface))
else if (mParams.GetThreadOperationalDataset().HasValue() && mNetworkEndpoints.thread != kInvalidEndpointId)
{
return CommissioningStage::kThreadNetworkSetup;
}
Expand All @@ -215,9 +170,7 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
#endif
}
case CommissioningStage::kWiFiNetworkSetup:
mEndpoint = mNetworkEndpoint;
if (mParams.GetThreadOperationalDataset().HasValue() &&
mNetworkTechnology.Has(chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface))
if (mParams.GetThreadOperationalDataset().HasValue() && mNetworkEndpoints.thread != kInvalidEndpointId)
{
return CommissioningStage::kThreadNetworkSetup;
}
Expand All @@ -226,9 +179,7 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
return CommissioningStage::kWiFiNetworkEnable;
}
case CommissioningStage::kThreadNetworkSetup:
mEndpoint = mNetworkEndpoint;
if (mParams.GetWiFiCredentials().HasValue() &&
mNetworkTechnology.Has(chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kWiFiNetworkInterface))
if (mParams.GetWiFiCredentials().HasValue() && mNetworkEndpoints.wifi != kInvalidEndpointId)
{
return CommissioningStage::kWiFiNetworkEnable;
}
Expand All @@ -238,9 +189,7 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
}

case CommissioningStage::kWiFiNetworkEnable:
mEndpoint = mNetworkEndpoint;
if (mParams.GetThreadOperationalDataset().HasValue() &&
mNetworkTechnology.Has(chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface))
if (mParams.GetThreadOperationalDataset().HasValue() && mNetworkEndpoints.thread != kInvalidEndpointId)
{
return CommissioningStage::kThreadNetworkEnable;
}
Expand All @@ -249,7 +198,6 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
return CommissioningStage::kFindOperational;
}
case CommissioningStage::kThreadNetworkEnable:
mEndpoint = mNetworkEndpoint;
// TODO: I dont think this is to spec - not sure where we'd have a commissioner that doesn't have dnssd.
#if CHIP_DEVICE_CONFIG_ENABLE_DNSSD
return CommissioningStage::kFindOperational;
Expand All @@ -272,6 +220,21 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
return CommissioningStage::kError;
}

EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) {
switch(stage) {
case CommissioningStage::kWiFiNetworkSetup:
case CommissioningStage::kWiFiNetworkEnable:
return mNetworkEndpoints.wifi;
case CommissioningStage::kThreadNetworkSetup:
case CommissioningStage::kThreadNetworkEnable:
return mNetworkEndpoints.thread;
case CommissioningStage::kGetNetworkTechnology:
return kInvalidEndpointId;
default:
return 0;
}
}

void AutoCommissioner::StartCommissioning(CommissioneeDeviceProxy * proxy)
{
// TODO: check that there is no commissioning in progress currently.
Expand All @@ -287,7 +250,7 @@ void AutoCommissioner::StartCommissioning(CommissioneeDeviceProxy * proxy)
Transport::Type::kBle;
CHIP_ERROR err = CHIP_NO_ERROR;
CommissioningStage nextStage = GetNextCommissioningStage(CommissioningStage::kSecurePairing, err);
mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, 0, GetCommandTimeout(nextStage));
mCommissioner->PerformCommissioningStep(mCommissioneeDeviceProxy, nextStage, mParams, this, GetEndpoint(nextStage), GetCommandTimeout(nextStage));
}

Optional<System::Clock::Timeout> AutoCommissioner::GetCommandTimeout(CommissioningStage stage)
Expand Down Expand Up @@ -340,15 +303,7 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
{
if (err != CHIP_NO_ERROR)
{
if (report.stageCompleted == CommissioningStage::kCheckEndpointIsCommissionable && mEndpoint != 0)
{
ChipLogError(Controller, "No descriptor cluster found for endpoint %u, ignoring", mEndpoint);
err = CHIP_NO_ERROR;
}
else
{
ChipLogError(Controller, "Failed to perform commissioning step %d", static_cast<int>(report.stageCompleted));
}
ChipLogError(Controller, "Failed to perform commissioning step %d", static_cast<int>(report.stageCompleted));
}
else
{
Expand All @@ -363,37 +318,8 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
case CommissioningStage::kReadSoftwareVersion:
mSoftwareVersion = report.Get<BasicSoftware>().softwareVersion;
break;
case CommissioningStage::kGetPartsList:
mAllEndpoints = report.Get<EndpointParts>();
break;
case CommissioningStage::kCheckEndpointIsCommissionable:
if (mEndpoint == 0 && !report.Get<EndpointCommissioningInfo>().isCommissionable)
{
ChipLogError(Controller, "Device endpoint is not commissionable");
return CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR;
}
if (report.Get<EndpointCommissioningInfo>().hasNetworkCluster)
{
mNetworkEndpoint = mEndpoint;
}
break;
case CommissioningStage::kGetNetworkTechnology:
mNetworkTechnology.SetRaw(report.Get<FeatureMap>().features);
// Only one of these features can be set at a time.
if (!mNetworkTechnology.HasOnly(
chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kWiFiNetworkInterface) &&
!mNetworkTechnology.HasOnly(
chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface) &&
mNetworkTechnology.HasOnly(
chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kEthernetNetworkInterface))
{
ChipLogError(
Controller,
"Network Commissioning cluster is malformed - more than one network technology is specified (0x%" PRIX32 ")",
report.Get<FeatureMap>().features);
err = CHIP_ERROR_INTEGRITY_CHECK_FAILED;
break;
}
mNetworkEndpoints = report.Get<NetworkClusters>();
break;
case CommissioningStage::kSendPAICertificateRequest:
SetPAI(report.Get<RequestedCertificate>().certificate);
Expand Down Expand Up @@ -435,8 +361,7 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
mCommissioneeDeviceProxy = nullptr;
mOperationalDeviceProxy = nullptr;
mParams = CommissioningParameters();
mAllEndpoints = EndpointParts();
mNetworkEndpoint = 0;
mNetworkEndpoints = NetworkClusters();
return CHIP_NO_ERROR;
default:
break;
Expand Down Expand Up @@ -464,7 +389,7 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio

mParams.SetCompletionStatus(err);
// TODO: Get real endpoint
mCommissioner->PerformCommissioningStep(proxy, nextStage, mParams, this, mEndpoint, GetCommandTimeout(nextStage));
mCommissioner->PerformCommissioningStep(proxy, nextStage, mParams, this, GetEndpoint(nextStage), GetCommandTimeout(nextStage));
return CHIP_NO_ERROR;
}

Expand Down
10 changes: 2 additions & 8 deletions src/controller/AutoCommissioner.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,13 @@ class AutoCommissioner : public CommissioningDelegate

CHIP_ERROR NOCChainGenerated(ByteSpan noc, ByteSpan icac, ByteSpan rcac, AesCcm128KeySpan ipk, NodeId adminSubject);
Optional<System::Clock::Timeout> GetCommandTimeout(CommissioningStage stage);
bool NetworkClusterUseable();
EndpointId GetEndpoint(const CommissioningStage & stage);

DeviceCommissioner * mCommissioner;
CommissioneeDeviceProxy * mCommissioneeDeviceProxy = nullptr;
OperationalDeviceProxy * mOperationalDeviceProxy = nullptr;
OperationalCredentialsDelegate * mOperationalCredentialsDelegate = nullptr;
CommissioningParameters mParams = CommissioningParameters();
EndpointParts mAllEndpoints;
EndpointId mEndpoint;
VendorId mVendorId;
uint16_t mProductId;
uint32_t mSoftwareVersion;
Expand All @@ -68,12 +66,8 @@ class AutoCommissioner : public CommissioningDelegate
uint8_t mCredentials[CommissioningParameters::kMaxCredentialsLen];
uint8_t mThreadOperationalDataset[CommissioningParameters::kMaxThreadDatasetLen];

// We only commission one network endpoint even if the device and the parameters are capable of setting up > 1.
// This is sufficient to get the device onto the network. Additional network setup can be done after commissioning
// if required.
bool mNeedsNetworkSetup = false;
BitFlags<chip::app::Clusters::NetworkCommissioning::NetworkCommissioningFeature> mNetworkTechnology;
EndpointId mNetworkEndpoint = 0xFFFF;
NetworkClusters mNetworkEndpoints;

// TODO: Why were the nonces statically allocated, but the certs dynamically allocated?
uint8_t * mDAC = nullptr;
Expand Down
Loading

0 comments on commit fa799d9

Please sign in to comment.