Skip to content

Commit 130ffc6

Browse files
DejinChenaustina-csa
authored andcommitted
Auto-commissioner: support secondary network interface commissioning (project-chip#33801)
* Auto-commissioner: support secondary network interface commissioning * Fix code-wifi-thread command and reset trying secondary network flag * Revert server-side changes * Added write request cancel function
1 parent ed1e3b9 commit 130ffc6

10 files changed

+151
-24
lines changed

examples/chip-tool/commands/pairing/Commands.h

+9
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ class PairCodeThread : public PairingCommand
6969
{}
7070
};
7171

72+
class PairCodeWiFiThread : public PairingCommand
73+
{
74+
public:
75+
PairCodeWiFiThread(CredentialIssuerCommands * credsIssuerConfig) :
76+
PairingCommand("code-wifi-thread", PairingMode::Code, PairingNetworkType::WiFiOrThread, credsIssuerConfig)
77+
{}
78+
};
79+
7280
class PairOnNetwork : public PairingCommand
7381
{
7482
public:
@@ -231,6 +239,7 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre
231239
make_unique<PairCodePase>(credsIssuerConfig),
232240
make_unique<PairCodeWifi>(credsIssuerConfig),
233241
make_unique<PairCodeThread>(credsIssuerConfig),
242+
make_unique<PairCodeWiFiThread>(credsIssuerConfig),
234243
make_unique<PairBleWiFi>(credsIssuerConfig),
235244
make_unique<PairBleThread>(credsIssuerConfig),
236245
make_unique<PairSoftAP>(credsIssuerConfig),

examples/chip-tool/commands/pairing/PairingCommand.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()
111111
case PairingNetworkType::Thread:
112112
params.SetThreadOperationalDataset(mOperationalDataset);
113113
break;
114+
case PairingNetworkType::WiFiOrThread:
115+
params.SetWiFiCredentials(Controller::WiFiCredentials(mSSID, mPassword));
116+
params.SetThreadOperationalDataset(mOperationalDataset);
117+
break;
114118
case PairingNetworkType::None:
115119
break;
116120
}

examples/chip-tool/commands/pairing/PairingCommand.h

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum class PairingNetworkType
4444
None,
4545
WiFi,
4646
Thread,
47+
WiFiOrThread,
4748
};
4849

4950
class PairingCommand : public CHIPCommand,
@@ -85,6 +86,11 @@ class PairingCommand : public CHIPCommand,
8586
case PairingNetworkType::Thread:
8687
AddArgument("operationalDataset", &mOperationalDataset);
8788
break;
89+
case PairingNetworkType::WiFiOrThread:
90+
AddArgument("ssid", &mSSID);
91+
AddArgument("password", &mPassword);
92+
AddArgument("operationalDataset", &mOperationalDataset);
93+
break;
8894
}
8995

9096
switch (mode)

src/controller/AutoCommissioner.cpp

+36-23
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,19 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
298298

299299
CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup(CommissioningStage currentStage, CHIP_ERROR & lastErr)
300300
{
301+
if (IsSecondaryNetworkSupported())
302+
{
303+
if (TryingSecondaryNetwork())
304+
{
305+
// Try secondary network interface.
306+
return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kThreadNetworkSetup
307+
: CommissioningStage::kWiFiNetworkSetup;
308+
}
309+
// Try primary network interface
310+
return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kWiFiNetworkSetup
311+
: CommissioningStage::kThreadNetworkSetup;
312+
}
313+
301314
if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
302315
{
303316
return CommissioningStage::kWiFiNetworkSetup;
@@ -455,35 +468,15 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
455468
case CommissioningStage::kNeedsNetworkCreds:
456469
return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
457470
case CommissioningStage::kWiFiNetworkSetup:
458-
if (mParams.GetThreadOperationalDataset().HasValue() &&
459-
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
460-
{
461-
return CommissioningStage::kThreadNetworkSetup;
462-
}
463-
else
464-
{
465-
return CommissioningStage::kFailsafeBeforeWiFiEnable;
466-
}
471+
return CommissioningStage::kFailsafeBeforeWiFiEnable;
467472
case CommissioningStage::kThreadNetworkSetup:
468-
if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
469-
{
470-
return CommissioningStage::kFailsafeBeforeWiFiEnable;
471-
}
472-
else
473-
{
474-
return CommissioningStage::kFailsafeBeforeThreadEnable;
475-
}
473+
return CommissioningStage::kFailsafeBeforeThreadEnable;
476474
case CommissioningStage::kFailsafeBeforeWiFiEnable:
477475
return CommissioningStage::kWiFiNetworkEnable;
478476
case CommissioningStage::kFailsafeBeforeThreadEnable:
479477
return CommissioningStage::kThreadNetworkEnable;
480478
case CommissioningStage::kWiFiNetworkEnable:
481-
if (mParams.GetThreadOperationalDataset().HasValue() &&
482-
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
483-
{
484-
return CommissioningStage::kThreadNetworkEnable;
485-
}
486-
else if (mParams.GetSkipCommissioningComplete().ValueOr(false))
479+
if (mParams.GetSkipCommissioningComplete().ValueOr(false))
487480
{
488481
SetCASEFailsafeTimerIfNeeded();
489482
return CommissioningStage::kCleanup;
@@ -502,6 +495,10 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
502495
return CommissioningStage::kEvictPreviousCaseSessions;
503496
case CommissioningStage::kEvictPreviousCaseSessions:
504497
return CommissioningStage::kFindOperationalForStayActive;
498+
case CommissioningStage::kPrimaryOperationalNetworkFailed:
499+
return CommissioningStage::kDisablePrimaryNetworkInterface;
500+
case CommissioningStage::kDisablePrimaryNetworkInterface:
501+
return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
505502
case CommissioningStage::kFindOperationalForStayActive:
506503
return CommissioningStage::kICDSendStayActive;
507504
case CommissioningStage::kICDSendStayActive:
@@ -564,6 +561,8 @@ EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) const
564561
case CommissioningStage::kThreadNetworkSetup:
565562
case CommissioningStage::kThreadNetworkEnable:
566563
return mDeviceCommissioningInfo.network.thread.endpoint;
564+
case CommissioningStage::kDisablePrimaryNetworkInterface:
565+
return kRootEndpointId;
567566
default:
568567
return kRootEndpointId;
569568
}
@@ -729,6 +728,16 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
729728
report.stageCompleted = CommissioningStage::kScanNetworks;
730729
}
731730
}
731+
732+
if (err != CHIP_NO_ERROR && IsSecondaryNetworkSupported() && !TryingSecondaryNetwork() &&
733+
completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup &&
734+
completionStatus.failedStage.Value() <= kICDSendStayActive)
735+
{
736+
// Primary network failed, disable primary network interface and try secondary network interface.
737+
TrySecondaryNetwork();
738+
err = CHIP_NO_ERROR;
739+
report.stageCompleted = CommissioningStage::kPrimaryOperationalNetworkFailed;
740+
}
732741
}
733742
else
734743
{
@@ -847,6 +856,10 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
847856
mOperationalDeviceProxy = report.Get<OperationalNodeFoundData>().operationalProxy;
848857
break;
849858
case CommissioningStage::kCleanup:
859+
if (IsSecondaryNetworkSupported() && TryingSecondaryNetwork())
860+
{
861+
ResetTryingSecondaryNetwork();
862+
}
850863
ReleasePAI();
851864
ReleaseDAC();
852865
mCommissioneeDeviceProxy = nullptr;

src/controller/AutoCommissioner.h

+16
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ class AutoCommissioner : public CommissioningDelegate
9494
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId));
9595
};
9696

97+
// Helper function to Determine whether secondary network interface is supported.
98+
// Only true if information is provided for both networks, and the target has endpoint
99+
// for wifi and thread.
100+
bool IsSecondaryNetworkSupported() const
101+
{
102+
return ((mParams.GetSupportsConcurrentConnection().ValueOr(false) && mParams.GetWiFiCredentials().HasValue() &&
103+
mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) &&
104+
mParams.GetThreadOperationalDataset().HasValue() &&
105+
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId);
106+
}
107+
108+
void TrySecondaryNetwork() { mTryingSecondaryNetwork = true; }
109+
bool TryingSecondaryNetwork() const { return mTryingSecondaryNetwork; }
110+
void ResetTryingSecondaryNetwork() { mTryingSecondaryNetwork = false; }
111+
bool mTryingSecondaryNetwork = false;
112+
97113
bool mStopCommissioning = false;
98114

99115
DeviceCommissioner * mCommissioner = nullptr;

src/controller/CHIPDeviceController.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <app/server/Dnssd.h>
3737
#include <controller/CurrentFabricRemover.h>
3838
#include <controller/InvokeInteraction.h>
39+
#include <controller/WriteInteraction.h>
3940
#include <credentials/CHIPCert.h>
4041
#include <credentials/DeviceAttestationCredsProvider.h>
4142
#include <crypto/CHIPCryptoPAL.h>
@@ -1028,6 +1029,12 @@ void DeviceCommissioner::CancelCommissioningInteractions()
10281029
mInvokeCancelFn();
10291030
mInvokeCancelFn = nullptr;
10301031
}
1032+
if (mWriteCancelFn)
1033+
{
1034+
ChipLogDetail(Controller, "Cancelling write request for step '%s'", StageToString(mCommissioningStage));
1035+
mWriteCancelFn();
1036+
mWriteCancelFn = nullptr;
1037+
}
10311038
if (mOnDeviceConnectedCallback.IsRegistered())
10321039
{
10331040
ChipLogDetail(Controller, "Cancelling CASE setup for step '%s'", StageToString(mCommissioningStage));
@@ -1800,6 +1807,12 @@ void DeviceCommissioner::OnBasicSuccess(void * context, const chip::app::DataMod
18001807
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
18011808
}
18021809

1810+
void DeviceCommissioner::OnInterfaceEnableWriteSuccessResponse(void * context)
1811+
{
1812+
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1813+
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
1814+
}
1815+
18031816
void DeviceCommissioner::OnBasicFailure(void * context, CHIP_ERROR error)
18041817
{
18051818
ChipLogProgress(Controller, "Received failure response %s\n", chip::ErrorStr(error));
@@ -1971,6 +1984,7 @@ void DeviceCommissioner::CommissioningStageComplete(CHIP_ERROR err, Commissionin
19711984
DeviceProxy * proxy = mDeviceBeingCommissioned;
19721985
mDeviceBeingCommissioned = nullptr;
19731986
mInvokeCancelFn = nullptr;
1987+
mWriteCancelFn = nullptr;
19741988

19751989
if (mPairingDelegate != nullptr)
19761990
{
@@ -2739,6 +2753,20 @@ DeviceCommissioner::SendCommissioningCommand(DeviceProxy * device, const Request
27392753
onFailureCb, NullOptional, timeout, (!fireAndForget) ? &mInvokeCancelFn : nullptr);
27402754
}
27412755

2756+
template <typename AttrType>
2757+
CHIP_ERROR DeviceCommissioner::SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster,
2758+
AttributeId attribute, const AttrType & requestData,
2759+
WriteResponseSuccessCallback successCb,
2760+
WriteResponseFailureCallback failureCb)
2761+
{
2762+
VerifyOrDie(!mWriteCancelFn); // we don't make parallel (cancellable) calls
2763+
auto onSuccessCb = [this, successCb](const app::ConcreteAttributePath & aPath) { successCb(this); };
2764+
auto onFailureCb = [this, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) { failureCb(this, aError); };
2765+
return WriteAttribute(device->GetSecureSession().Value(), endpoint, cluster, attribute, requestData, onSuccessCb, onFailureCb,
2766+
/* aTimedWriteTimeoutMs = */ NullOptional, /* onDoneCb = */ nullptr, /* aDataVersion = */ NullOptional,
2767+
/* outCancelFn = */ &mWriteCancelFn);
2768+
}
2769+
27422770
void DeviceCommissioner::SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
27432771
app::AttributePathParams * readPaths, size_t readPathsSize)
27442772
{
@@ -3423,6 +3451,25 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
34233451
);
34243452
}
34253453
break;
3454+
case CommissioningStage::kPrimaryOperationalNetworkFailed: {
3455+
// nothing to do. This stage indicates that the primary operational network failed and the network interface should be
3456+
// disabled later.
3457+
break;
3458+
}
3459+
case CommissioningStage::kDisablePrimaryNetworkInterface: {
3460+
NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::Type request = false;
3461+
CHIP_ERROR err = SendCommissioningWriteRequest(proxy, endpoint, NetworkCommissioning::Id,
3462+
NetworkCommissioning::Attributes::InterfaceEnabled::Id, request,
3463+
OnInterfaceEnableWriteSuccessResponse, OnBasicFailure);
3464+
if (err != CHIP_NO_ERROR)
3465+
{
3466+
// We won't get any async callbacks here, so just complete our stage.
3467+
ChipLogError(Controller, "Failed to send InterfaceEnabled write request: %" CHIP_ERROR_FORMAT, err.Format());
3468+
CommissioningStageComplete(err);
3469+
return;
3470+
}
3471+
break;
3472+
}
34263473
case CommissioningStage::kICDSendStayActive: {
34273474
if (!(params.GetICDStayActiveDurationMsec().HasValue()))
34283475
{

src/controller/CHIPDeviceController.h

+7
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
830830
CommissioningStage mCommissioningStage = CommissioningStage::kSecurePairing;
831831
bool mRunCommissioningAfterConnection = false;
832832
Internal::InvokeCancelFn mInvokeCancelFn;
833+
Internal::WriteCancelFn mWriteCancelFn;
833834

834835
ObjectPool<CommissioneeDeviceProxy, kNumMaxActiveDevices> mCommissioneeDevicePool;
835836

@@ -973,6 +974,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
973974
OnICDManagementStayActiveResponse(void * context,
974975
const app::Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType & data);
975976

977+
static void OnInterfaceEnableWriteSuccessResponse(void * context);
978+
976979
/**
977980
* @brief
978981
* This function processes the CSR sent by the device.
@@ -1025,6 +1028,10 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
10251028
Optional<System::Clock::Timeout> timeout = NullOptional, bool fireAndForget = false);
10261029
void SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
10271030
app::AttributePathParams * readPaths, size_t readPathsSize);
1031+
template <typename AttrType>
1032+
CHIP_ERROR SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster, AttributeId attribute,
1033+
const AttrType & requestData, WriteResponseSuccessCallback successCb,
1034+
WriteResponseFailureCallback failureCb);
10281035
void CancelCommissioningInteractions();
10291036
void CancelCASECallbacks();
10301037

src/controller/CommissioningDelegate.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ const char * StageToString(CommissioningStage stage)
136136
case kNeedsNetworkCreds:
137137
return "NeedsNetworkCreds";
138138

139+
case kPrimaryOperationalNetworkFailed:
140+
return "PrimaryOperationalNetworkFailed";
141+
142+
case kDisablePrimaryNetworkInterface:
143+
return "DisablePrimaryNetworkInterface";
144+
139145
default:
140146
return "???";
141147
}

src/controller/CommissioningDelegate.h

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ enum CommissioningStage : uint8_t
7979
/// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with
8080
/// network credentials to use in kWiFiNetworkSetup or kThreadNetworkSetup steps.
8181
kNeedsNetworkCreds,
82+
kPrimaryOperationalNetworkFailed, ///< Indicate that the primary operational network (on root endpoint) failed, should disable
83+
///< the primary network interface later.
84+
kDisablePrimaryNetworkInterface, ///< Send InterfaceEnabled write request to the device to disable network interface.
8285
};
8386

8487
enum class ICDRegistrationStrategy : uint8_t

src/controller/WriteInteraction.h

+17-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@
2323
#include <app/WriteClient.h>
2424
#include <controller/CommandSenderAllocator.h>
2525
#include <controller/TypedCommandCallback.h>
26+
#include <functional>
2627
#include <lib/core/Optional.h>
2728

2829
namespace chip {
2930
namespace Controller {
3031

32+
namespace Internal {
33+
// WriteCancelFn functions on WriteAttribute() are for internal use only.
34+
typedef std::function<void()> WriteCancelFn;
35+
} // namespace Internal
36+
3137
/*
3238
* An adapter callback that permits applications to provide std::function callbacks for success, error and on done.
3339
* This permits a slightly more flexible programming model that allows applications to pass in lambdas and bound member functions
@@ -130,7 +136,8 @@ CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId
130136
AttributeId attributeId, const AttrType & requestData, WriteCallback::OnSuccessCallbackType onSuccessCb,
131137
WriteCallback::OnErrorCallbackType onErrorCb, const Optional<uint16_t> & aTimedWriteTimeoutMs,
132138
WriteCallback::OnDoneCallbackType onDoneCb = nullptr,
133-
const Optional<DataVersion> & aDataVersion = NullOptional)
139+
const Optional<DataVersion> & aDataVersion = NullOptional,
140+
Internal::WriteCancelFn * outCancelFn = nullptr)
134141
{
135142
auto callback = Platform::MakeUnique<WriteCallback>(onSuccessCb, onErrorCb, onDoneCb, sessionHandle->IsGroupSession());
136143
VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY);
@@ -151,6 +158,15 @@ CHIP_ERROR WriteAttribute(const SessionHandle & sessionHandle, chip::EndpointId
151158

152159
ReturnErrorOnFailure(client->SendWriteRequest(sessionHandle));
153160

161+
// If requested by the caller, provide a way to cancel the write interaction.
162+
if (outCancelFn != nullptr)
163+
{
164+
*outCancelFn = [rawCallback = callback.get(), rawClient = client.get()]() {
165+
chip::Platform::Delete(rawClient);
166+
chip::Platform::Delete(rawCallback);
167+
};
168+
}
169+
154170
// At this point the handle will ensure our callback's OnDone is always
155171
// called.
156172
client.release();

0 commit comments

Comments
 (0)