From 46f17b00f702dddbbf2e666cd264f8b1e04b6c4a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 17 Mar 2022 15:02:18 -0400 Subject: [PATCH] Add a helper class for opening commissioning windows. There's a bunch of state involved in this, and trying to hang it all off the controller leads to too many complications, ranging from the inability to be opening more than one commissioning window at a time to crashes. Fixes https://github.com/project-chip/connectedhomeip/issues/16209 --- .../OpenCommissioningWindowCommand.cpp | 40 +- .../pairing/OpenCommissioningWindowCommand.h | 20 +- src/controller/BUILD.gn | 2 + src/controller/CHIPDeviceController.cpp | 181 --------- src/controller/CHIPDeviceController.h | 90 ----- src/controller/CommissioningWindowOpener.cpp | 348 ++++++++++++++++++ src/controller/CommissioningWindowOpener.h | 172 +++++++++ .../java/CHIPDeviceController-JNI.cpp | 19 +- .../ChipDeviceController-ScriptBinding.cpp | 18 +- .../Framework/CHIP/CHIPDeviceController.mm | 17 +- 10 files changed, 583 insertions(+), 324 deletions(-) create mode 100644 src/controller/CommissioningWindowOpener.cpp create mode 100644 src/controller/CommissioningWindowOpener.h diff --git a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp index abc94a593e3948..6a277d6b1f4ada 100644 --- a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp +++ b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp @@ -22,26 +22,33 @@ using namespace ::chip; CHIP_ERROR OpenCommissioningWindowCommand::RunCommand() { - return CurrentCommissioner().GetConnectedDevice(mNodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback); + mWindowOpener = Platform::MakeUnique(&CurrentCommissioner()); + if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kOriginalSetupCode) + { + return mWindowOpener->OpenBasicCommissioningWindow(mNodeId, mTimeout, &mOnOpenBasicCommissioningWindowCallback); + } + + if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN) + { + SetupPayload ignored; + return mWindowOpener->OpenCommissioningWindow(mNodeId, mTimeout, mIteration, mDiscriminator, NullOptional, + &mOnOpenCommissioningWindowCallback, ignored, + /* readVIDPIDAttributes */ true); + } + + ChipLogError(chipTool, "Unknown commissioning window option: %d", to_underlying(mCommissioningWindowOption)); + return CHIP_ERROR_INVALID_ARGUMENT; } -void OpenCommissioningWindowCommand::OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device) -{ - OpenCommissioningWindowCommand * command = reinterpret_cast(context); - VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "OnDeviceConnectedFn: context is null")); - command->OpenCommissioningWindow(); -} -void OpenCommissioningWindowCommand::OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR err) +void OpenCommissioningWindowCommand::OnOpenCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err, + chip::SetupPayload payload) { LogErrorOnFailure(err); - OpenCommissioningWindowCommand * command = reinterpret_cast(context); - VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "OnDeviceConnectionFailureFn: context is null")); - command->SetCommandExitStatus(err); + OnOpenBasicCommissioningWindowResponse(context, remoteId, err); } -void OpenCommissioningWindowCommand::OnOpenCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err, - chip::SetupPayload payload) +void OpenCommissioningWindowCommand::OnOpenBasicCommissioningWindowResponse(void * context, NodeId remoteId, CHIP_ERROR err) { LogErrorOnFailure(err); @@ -49,10 +56,3 @@ void OpenCommissioningWindowCommand::OnOpenCommissioningWindowResponse(void * co VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "OnOpenCommissioningWindowCommand: context is null")); command->SetCommandExitStatus(err); } - -CHIP_ERROR OpenCommissioningWindowCommand::OpenCommissioningWindow() -{ - return CurrentCommissioner().OpenCommissioningWindowWithCallback( - mNodeId, mTimeout, mIteration, mDiscriminator, mCommissioningWindowOption, &mOnOpenCommissioningWindowCallback, - /* readVIDPIDAttributes */ true); -} diff --git a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h index d29e328dde22da..b06f13ffea84e8 100644 --- a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h +++ b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.h @@ -20,13 +20,16 @@ #include "../common/CHIPCommand.h" +#include +#include + class OpenCommissioningWindowCommand : public CHIPCommand { public: OpenCommissioningWindowCommand(CredentialIssuerCommands * credIssuerCommands) : - CHIPCommand("open-commissioning-window", credIssuerCommands), mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), - mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this), - mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this) + CHIPCommand("open-commissioning-window", credIssuerCommands), + mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this), + mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this) { AddArgument("node-id", 0, UINT64_MAX, &mNodeId); AddArgument("option", 0, 2, &mCommissioningWindowOption); @@ -41,17 +44,16 @@ class OpenCommissioningWindowCommand : public CHIPCommand private: NodeId mNodeId; - ChipDeviceController::CommissioningWindowOption mCommissioningWindowOption; + chip::Controller::CommissioningWindowOpener::CommissioningWindowOption mCommissioningWindowOption; uint16_t mTimeout; uint32_t mIteration; uint16_t mDiscriminator; - CHIP_ERROR OpenCommissioningWindow(); - static void OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device); - static void OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR error); + chip::Platform::UniquePtr mWindowOpener; + static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload); + static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status); - chip::Callback::Callback mOnDeviceConnectedCallback; - chip::Callback::Callback mOnDeviceConnectionFailureCallback; chip::Callback::Callback mOnOpenCommissioningWindowCallback; + chip::Callback::Callback mOnOpenBasicCommissioningWindowCallback; }; diff --git a/src/controller/BUILD.gn b/src/controller/BUILD.gn index 013f2101c457e1..e3d39d57747957 100644 --- a/src/controller/BUILD.gn +++ b/src/controller/BUILD.gn @@ -47,6 +47,8 @@ static_library("controller") { "CommissionerDiscoveryController.cpp", "CommissionerDiscoveryController.h", "CommissioningDelegate.cpp", + "CommissioningWindowOpener.cpp", + "CommissioningWindowOpener.h", "DeviceDiscoveryDelegate.h", "EmptyDataModelHandler.cpp", "ExampleOperationalCredentialsIssuer.cpp", diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 2c4502f224e55d..36d94a4170b5d2 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -70,8 +70,6 @@ #include #include #include -#include -#include #include #include @@ -399,76 +397,6 @@ CHIP_ERROR DeviceController::GetPeerAddressAndPort(PeerId peerId, Inet::IPAddres return CHIP_NO_ERROR; } -void DeviceController::OnPIDReadResponse(void * context, uint16_t value) -{ - ChipLogProgress(Controller, "Received PID for the device. Value %d", value); - DeviceController * controller = static_cast(context); - controller->mSetupPayload.productID = value; - - if (controller->OpenCommissioningWindowInternal() != CHIP_NO_ERROR) - { - OnOpenPairingWindowFailureResponse(context, CHIP_NO_ERROR); - } -} - -void DeviceController::OnVIDReadResponse(void * context, VendorId value) -{ - ChipLogProgress(Controller, "Received VID for the device. Value %d", to_underlying(value)); - - DeviceController * controller = static_cast(context); - - controller->mSetupPayload.vendorID = value; - - OperationalDeviceProxy * device = - controller->mSystemState->CASESessionMgr()->FindExistingSession(controller->GetPeerIdWithCommissioningWindowOpen()); - if (device == nullptr) - { - ChipLogError(Controller, "Could not find device for opening commissioning window"); - OnOpenPairingWindowFailureResponse(context, CHIP_NO_ERROR); - return; - } - - constexpr EndpointId kBasicClusterEndpoint = 0; - chip::Controller::BasicCluster cluster; - cluster.Associate(device, kBasicClusterEndpoint); - - if (cluster.ReadAttribute(context, OnPIDReadResponse, - OnVIDPIDReadFailureResponse) != CHIP_NO_ERROR) - { - ChipLogError(Controller, "Could not read PID for opening commissioning window"); - OnOpenPairingWindowFailureResponse(context, CHIP_NO_ERROR); - } -} - -void DeviceController::OnVIDPIDReadFailureResponse(void * context, CHIP_ERROR error) -{ - ChipLogProgress(Controller, "Failed to read VID/PID for the device. error %" CHIP_ERROR_FORMAT, error.Format()); - OnOpenPairingWindowFailureResponse(context, error); -} - -void DeviceController::OnOpenPairingWindowSuccessResponse(void * context, const chip::app::DataModel::NullObjectType &) -{ - ChipLogProgress(Controller, "Successfully opened pairing window on the device"); - DeviceController * controller = static_cast(context); - if (controller->mCommissioningWindowCallback != nullptr) - { - controller->mCommissioningWindowCallback->mCall(controller->mCommissioningWindowCallback->mContext, - controller->mDeviceWithCommissioningWindowOpen, CHIP_NO_ERROR, - controller->mSetupPayload); - } -} - -void DeviceController::OnOpenPairingWindowFailureResponse(void * context, CHIP_ERROR error) -{ - ChipLogError(Controller, "Failed to open pairing window on the device. Status %s", chip::ErrorStr(error)); - DeviceController * controller = static_cast(context); - if (controller->mCommissioningWindowCallback != nullptr) - { - controller->mCommissioningWindowCallback->mCall(controller->mCommissioningWindowCallback->mContext, - controller->mDeviceWithCommissioningWindowOpen, error, SetupPayload()); - } -} - CHIP_ERROR DeviceController::ComputePASEVerifier(uint32_t iterations, uint32_t setupPincode, const ByteSpan & salt, Spake2pVerifier & outVerifier) { @@ -477,115 +405,6 @@ CHIP_ERROR DeviceController::ComputePASEVerifier(uint32_t iterations, uint32_t s return CHIP_NO_ERROR; } -CHIP_ERROR DeviceController::OpenCommissioningWindowWithCallback(NodeId deviceId, uint16_t timeout, uint32_t iteration, - uint16_t discriminator, CommissioningWindowOption option, - chip::Callback::Callback * callback, - bool readVIDPIDAttributes) -{ - mSetupPayload = SetupPayload(); - - switch (option) - { - case CommissioningWindowOption::kOriginalSetupCode: - case CommissioningWindowOption::kTokenWithRandomPIN: - break; - case CommissioningWindowOption::kTokenWithProvidedPIN: - mSetupPayload.setUpPINCode = mSuggestedSetUpPINCode; - break; - default: - return CHIP_ERROR_INVALID_ARGUMENT; - } - - mSetupPayload.version = 0; - mSetupPayload.discriminator = discriminator; - mSetupPayload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kOnNetwork); - - mCommissioningWindowOption = option; - mCommissioningWindowCallback = callback; - mDeviceWithCommissioningWindowOpen = deviceId; - mCommissioningWindowTimeout = timeout; - mCommissioningWindowIteration = iteration; - - if (callback != nullptr && mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode && readVIDPIDAttributes) - { - OperationalDeviceProxy * device = - mSystemState->CASESessionMgr()->FindExistingSession(GetPeerIdWithCommissioningWindowOpen()); - VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - constexpr EndpointId kBasicClusterEndpoint = 0; - chip::Controller::BasicCluster cluster; - cluster.Associate(device, kBasicClusterEndpoint); - return cluster.ReadAttribute(this, OnVIDReadResponse, - OnVIDPIDReadFailureResponse); - } - - return OpenCommissioningWindowInternal(); -} - -CHIP_ERROR DeviceController::OpenCommissioningWindowInternal() -{ - ChipLogProgress(Controller, "OpenCommissioningWindow for device ID %" PRIu64, mDeviceWithCommissioningWindowOpen); - VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE); - - OperationalDeviceProxy * device = mSystemState->CASESessionMgr()->FindExistingSession(GetPeerIdWithCommissioningWindowOpen()); - VerifyOrReturnError(device != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - constexpr EndpointId kAdministratorCommissioningClusterEndpoint = 0; - - chip::Controller::AdministratorCommissioningCluster cluster; - cluster.Associate(device, kAdministratorCommissioningClusterEndpoint); - - if (mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode) - { - // TODO: Salt should be provided as an input or it should be randomly generated when - // the PIN is randomly generated. - const char kSpake2pKeyExchangeSalt[] = "SPAKE2P Key Salt"; - ByteSpan salt(Uint8::from_const_char(kSpake2pKeyExchangeSalt), sizeof(kSpake2pKeyExchangeSalt)); - bool randomSetupPIN = (mCommissioningWindowOption == CommissioningWindowOption::kTokenWithRandomPIN); - Spake2pVerifier verifier; - - ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, mCommissioningWindowIteration, salt, randomSetupPIN, - mSetupPayload.setUpPINCode)); - - chip::Spake2pVerifierSerialized serializedVerifier; - MutableByteSpan serializedVerifierSpan(serializedVerifier); - ReturnErrorOnFailure(verifier.Serialize(serializedVerifierSpan)); - - AdministratorCommissioning::Commands::OpenCommissioningWindow::Type request; - request.commissioningTimeout = mCommissioningWindowTimeout; - request.PAKEVerifier = serializedVerifierSpan; - request.discriminator = mSetupPayload.discriminator; - request.iterations = mCommissioningWindowIteration; - request.salt = salt; - - // TODO: What should the timed invoke timeout here be? - uint16_t timedInvokeTimeoutMs = 10000; - ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenPairingWindowSuccessResponse, - OnOpenPairingWindowFailureResponse, MakeOptional(timedInvokeTimeoutMs))); - - char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; - - MutableCharSpan manualCode(payloadBuffer); - ReturnErrorOnFailure(ManualSetupPayloadGenerator(mSetupPayload).payloadDecimalStringRepresentation(manualCode)); - ChipLogProgress(Controller, "Manual pairing code: [%s]", payloadBuffer); - - MutableCharSpan QRCode(payloadBuffer); - ReturnErrorOnFailure(QRCodeBasicSetupPayloadGenerator(mSetupPayload).payloadBase38Representation(QRCode)); - ChipLogProgress(Controller, "SetupQRCode: [%s]", payloadBuffer); - } - else - { - AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type request; - request.commissioningTimeout = mCommissioningWindowTimeout; - // TODO: What should the timed invoke timeout here be? - uint16_t timedInvokeTimeoutMs = 10000; - ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenPairingWindowSuccessResponse, - OnOpenPairingWindowFailureResponse, MakeOptional(timedInvokeTimeoutMs))); - } - - return CHIP_NO_ERROR; -} - ControllerDeviceInitParams DeviceController::GetControllerDeviceInitParams() { return ControllerDeviceInitParams{ diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index b44010458184ba..9d6f473071ee02 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -158,8 +158,6 @@ struct CommissionerInitParams : public ControllerInitParams CommissioningDelegate * defaultCommissioner = nullptr; }; -typedef void (*OnOpenCommissioningWindow)(void * context, NodeId deviceId, CHIP_ERROR status, SetupPayload payload); - /** * @brief * Controller applications can use this class to communicate with already paired CHIP devices. The @@ -174,13 +172,6 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate, public Abstr DeviceController(); ~DeviceController() override {} - enum class CommissioningWindowOption : uint8_t - { - kOriginalSetupCode = 0, - kTokenWithRandomPIN, - kTokenWithProvidedPIN, - }; - CHIP_ERROR Init(ControllerInitParams params); /** @@ -240,62 +231,6 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate, public Abstr CHIP_ERROR ComputePASEVerifier(uint32_t iterations, uint32_t setupPincode, const ByteSpan & salt, Spake2pVerifier & outVerifier); - /** - * @brief - * Trigger a paired device to re-enter the commissioning mode. The device will exit the commissioning mode - * after a successful commissioning, or after the given `timeout` time. - * - * @param[in] deviceId The device Id. - * @param[in] timeout The commissioning mode should terminate after this much time. - * @param[in] iteration The PAKE iteration count associated with the PAKE Passcode ID and ephemeral - * PAKE passcode verifier to be used for this commissioning. - * @param[in] discriminator The long discriminator for the DNS-SD advertisement. - * @param[in] option The commissioning window can be opened using the original setup code, or an - * onboarding token can be generated using a random setup PIN code (or with - * the PIN code provied in the setupPayload). - * @param[in,out] payload The generated setup payload. - * - The payload is generated only if the user didn't ask for using the original setup code. - * - If the user asked to use the provided setup PIN, the PIN must be provided as part of - * this payload - * - * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error - */ - CHIP_ERROR OpenCommissioningWindow(NodeId deviceId, uint16_t timeout, uint32_t iteration, uint16_t discriminator, - CommissioningWindowOption option, SetupPayload & payload) - { - mSuggestedSetUpPINCode = payload.setUpPINCode; - ReturnErrorOnFailure(OpenCommissioningWindowWithCallback(deviceId, timeout, iteration, discriminator, option, nullptr)); - payload = mSetupPayload; - return CHIP_NO_ERROR; - } - - /** - * @brief - * Trigger a paired device to re-enter the commissioning mode. The device will exit the commissioning mode - * after a successful commissioning, or after the given `timeout` time. - * - * @param[in] deviceId The device Id. - * @param[in] timeout The commissioning mode should terminate after this much time. - * @param[in] iteration The PAKE iteration count associated with the PAKE Passcode ID and ephemeral - * PAKE passcode verifier to be used for this commissioning. - * @param[in] discriminator The long discriminator for the DNS-SD advertisement. - * @param[in] option The commissioning window can be opened using the original setup code, or an - * onboarding token can be generated using a random setup PIN code (or with - * the PIN code provied in the setupPayload). - * @param[in] callback The function to be called on success or failure of opening of commissioning window. - * - * @param[in] readVIDPIDAttributes Should the API internally read VID and PID from the device while opening the - * commissioning window. VID and PID is only needed for enchanced commissioning mode. - * If this argument is `true`, and enhanced commissioning mode is used, the API will - * read VID and PID from the device. - * - * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error - */ - CHIP_ERROR OpenCommissioningWindowWithCallback(NodeId deviceId, uint16_t timeout, uint32_t iteration, uint16_t discriminator, - CommissioningWindowOption option, - Callback::Callback * callback, - bool readVIDPIDAttributes = false); - void RegisterDeviceDiscoveryDelegate(DeviceDiscoveryDelegate * delegate) { mDeviceDiscoveryDelegate = delegate; } /** @@ -384,31 +319,6 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate, public Abstr private: void ReleaseOperationalDevice(OperationalDeviceProxy * device); - static void OnPIDReadResponse(void * context, uint16_t value); - static void OnVIDReadResponse(void * context, VendorId value); - static void OnVIDPIDReadFailureResponse(void * context, CHIP_ERROR error); - - CHIP_ERROR OpenCommissioningWindowInternal(); - - PeerId GetPeerIdWithCommissioningWindowOpen() - { - return mFabricInfo ? mFabricInfo->GetPeerIdForNode(mDeviceWithCommissioningWindowOpen) : PeerId(); - } - - // TODO - Support opening commissioning window simultaneously on multiple devices - Callback::Callback * mCommissioningWindowCallback = nullptr; - SetupPayload mSetupPayload; - NodeId mDeviceWithCommissioningWindowOpen; - uint32_t mSuggestedSetUpPINCode = 0; - - uint16_t mCommissioningWindowTimeout; - uint32_t mCommissioningWindowIteration; - - CommissioningWindowOption mCommissioningWindowOption; - - static void OnOpenPairingWindowSuccessResponse(void * context, const chip::app::DataModel::NullObjectType &); - static void OnOpenPairingWindowFailureResponse(void * context, CHIP_ERROR error); - CHIP_ERROR ProcessControllerNOCChain(const ControllerInitParams & params); }; diff --git a/src/controller/CommissioningWindowOpener.cpp b/src/controller/CommissioningWindowOpener.cpp new file mode 100644 index 00000000000000..843319b883f2db --- /dev/null +++ b/src/controller/CommissioningWindowOpener.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2022 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip::app::Clusters; + +namespace chip { +namespace Controller { + +CHIP_ERROR CommissioningWindowOpener::OpenBasicCommissioningWindow(NodeId deviceId, uint16_t timeout, + Callback::Callback * callback) +{ + VerifyOrReturnError(mNextStep == Step::kAcceptCommissioningStart, CHIP_ERROR_INCORRECT_STATE); + mSetupPayload = SetupPayload(); + + // Basic commissioning does not use the setup payload. + + mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode; + mBasicCommissioningWindowCallback = callback; + mCommissioningWindowCallback = nullptr; + mNodeId = deviceId; + mCommissioningWindowTimeout = timeout; + + mNextStep = Step::kOpenCommissioningWindow; + return mController->GetConnectedDevice(mNodeId, &mDeviceConnected, &mDeviceConnectionFailure); +} + +CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindow(NodeId deviceId, uint16_t timeout, uint32_t iteration, + uint16_t discriminator, Optional setupPIN, + Callback::Callback * callback, + SetupPayload & payload, bool readVIDPIDAttributes) +{ + VerifyOrReturnError(mNextStep == Step::kAcceptCommissioningStart, CHIP_ERROR_INCORRECT_STATE); + + mSetupPayload = SetupPayload(); + + if (setupPIN.HasValue()) + { + mCommissioningWindowOption = CommissioningWindowOption::kTokenWithProvidedPIN; + mSetupPayload.setUpPINCode = setupPIN.Value(); + } + else + { + mCommissioningWindowOption = CommissioningWindowOption::kTokenWithRandomPIN; + } + + mSetupPayload.version = 0; + mSetupPayload.discriminator = discriminator; + mSetupPayload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kOnNetwork); + + mCommissioningWindowCallback = callback; + mBasicCommissioningWindowCallback = nullptr; + mNodeId = deviceId; + mCommissioningWindowTimeout = timeout; + mCommissioningWindowIteration = iteration; + + bool randomSetupPIN = !setupPIN.HasValue(); + ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(mVerifier, mCommissioningWindowIteration, GetSPAKE2Salt(), + randomSetupPIN, mSetupPayload.setUpPINCode)); + + payload = mSetupPayload; + + if (readVIDPIDAttributes) + { + mNextStep = Step::kReadVID; + } + else + { + mNextStep = Step::kOpenCommissioningWindow; + } + + return mController->GetConnectedDevice(mNodeId, &mDeviceConnected, &mDeviceConnectionFailure); +} + +CHIP_ERROR CommissioningWindowOpener::OpenCommissioningWindowInternal(OperationalDeviceProxy * device) +{ + ChipLogProgress(Controller, "OpenCommissioningWindow for device ID %" PRIu64, mNodeId); + + constexpr EndpointId kAdministratorCommissioningClusterEndpoint = 0; + + AdministratorCommissioningCluster cluster; + cluster.Associate(device, kAdministratorCommissioningClusterEndpoint); + + if (mCommissioningWindowOption != CommissioningWindowOption::kOriginalSetupCode) + { + chip::Spake2pVerifierSerialized serializedVerifier; + MutableByteSpan serializedVerifierSpan(serializedVerifier); + ReturnErrorOnFailure(mVerifier.Serialize(serializedVerifierSpan)); + + AdministratorCommissioning::Commands::OpenCommissioningWindow::Type request; + request.commissioningTimeout = mCommissioningWindowTimeout; + request.PAKEVerifier = serializedVerifierSpan; + request.discriminator = mSetupPayload.discriminator; + request.iterations = mCommissioningWindowIteration; + request.salt = GetSPAKE2Salt(); + + // TODO: What should the timed invoke timeout here be? + uint16_t timedInvokeTimeoutMs = 10000; + ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, + OnOpenCommissioningWindowFailure, MakeOptional(timedInvokeTimeoutMs))); + + char payloadBuffer[QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength]; + + MutableCharSpan manualCode(payloadBuffer); + ReturnErrorOnFailure(ManualSetupPayloadGenerator(mSetupPayload).payloadDecimalStringRepresentation(manualCode)); + ChipLogProgress(Controller, "Manual pairing code: [%s]", payloadBuffer); + + MutableCharSpan QRCode(payloadBuffer); + ReturnErrorOnFailure(QRCodeBasicSetupPayloadGenerator(mSetupPayload).payloadBase38Representation(QRCode)); + ChipLogProgress(Controller, "SetupQRCode: [%s]", payloadBuffer); + } + else + { + AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type request; + request.commissioningTimeout = mCommissioningWindowTimeout; + // TODO: What should the timed invoke timeout here be? + uint16_t timedInvokeTimeoutMs = 10000; + ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, + OnOpenCommissioningWindowFailure, MakeOptional(timedInvokeTimeoutMs))); + } + + return CHIP_NO_ERROR; +} + +void CommissioningWindowOpener::OnPIDReadResponse(void * context, uint16_t value) +{ + ChipLogProgress(Controller, "Received PID for the device. Value %d", value); + auto * self = static_cast(context); + self->mSetupPayload.productID = value; + + self->mNextStep = Step::kOpenCommissioningWindow; + + CHIP_ERROR err = self->mController->GetConnectedDevice(self->mNodeId, &self->mDeviceConnected, &self->mDeviceConnectionFailure); + if (err != CHIP_NO_ERROR) + { + OnOpenCommissioningWindowFailure(context, err); + } +} + +void CommissioningWindowOpener::OnVIDReadResponse(void * context, VendorId value) +{ + ChipLogProgress(Controller, "Received VID for the device. Value %d", to_underlying(value)); + + auto * self = static_cast(context); + + self->mSetupPayload.vendorID = value; + + self->mNextStep = Step::kReadPID; + CHIP_ERROR err = self->mController->GetConnectedDevice(self->mNodeId, &self->mDeviceConnected, &self->mDeviceConnectionFailure); + if (err != CHIP_NO_ERROR) + { + OnOpenCommissioningWindowFailure(context, err); + } +} + +void CommissioningWindowOpener::OnVIDPIDReadFailureResponse(void * context, CHIP_ERROR error) +{ + ChipLogProgress(Controller, "Failed to read VID/PID for the device. error %" CHIP_ERROR_FORMAT, error.Format()); + OnOpenCommissioningWindowFailure(context, error); +} + +void CommissioningWindowOpener::OnOpenCommissioningWindowSuccess(void * context, const chip::app::DataModel::NullObjectType &) +{ + ChipLogProgress(Controller, "Successfully opened pairing window on the device"); + auto * self = static_cast(context); + self->mNextStep = Step::kAcceptCommissioningStart; + if (self->mCommissioningWindowCallback != nullptr) + { + self->mCommissioningWindowCallback->mCall(self->mCommissioningWindowCallback->mContext, self->mNodeId, CHIP_NO_ERROR, + self->mSetupPayload); + } + else if (self->mBasicCommissioningWindowCallback != nullptr) + { + self->mBasicCommissioningWindowCallback->mCall(self->mBasicCommissioningWindowCallback->mContext, self->mNodeId, + CHIP_NO_ERROR); + } +} + +void CommissioningWindowOpener::OnOpenCommissioningWindowFailure(void * context, CHIP_ERROR error) +{ + ChipLogError(Controller, "Failed to open pairing window on the device. Status %" CHIP_ERROR_FORMAT, error.Format()); + auto * self = static_cast(context); + self->mNextStep = Step::kAcceptCommissioningStart; + if (self->mCommissioningWindowCallback != nullptr) + { + self->mCommissioningWindowCallback->mCall(self->mCommissioningWindowCallback->mContext, self->mNodeId, error, + SetupPayload()); + } + else if (self->mBasicCommissioningWindowCallback != nullptr) + { + self->mBasicCommissioningWindowCallback->mCall(self->mBasicCommissioningWindowCallback->mContext, self->mNodeId, error); + } +} + +void CommissioningWindowOpener::OnDeviceConnectedCallback(void * context, OperationalDeviceProxy * device) +{ + auto * self = static_cast(context); + +#if CHIP_ERROR_LOGGING + const char * messageIfError = nullptr; +#endif // CHIP_ERROR_LOGGING + CHIP_ERROR err = CHIP_NO_ERROR; + + switch (self->mNextStep) + { + case Step::kReadVID: { + constexpr EndpointId kBasicClusterEndpoint = 0; + BasicCluster cluster; + cluster.Associate(device, kBasicClusterEndpoint); + err = cluster.ReadAttribute(context, OnVIDReadResponse, + OnVIDPIDReadFailureResponse); +#if CHIP_ERROR_LOGGING + messageIfError = "Could not read VID for opening commissioning window"; +#endif // CHIP_ERROR_LOGGING + break; + } + case Step::kReadPID: { + constexpr EndpointId kBasicClusterEndpoint = 0; + chip::Controller::BasicCluster cluster; + cluster.Associate(device, kBasicClusterEndpoint); + err = cluster.ReadAttribute(context, OnPIDReadResponse, + OnVIDPIDReadFailureResponse); +#if CHIP_ERROR_LOGGING + messageIfError = "Could not read VID for opening commissioning window"; +#endif // CHIP_ERROR_LOGGING + break; + } + case Step::kOpenCommissioningWindow: { + err = self->OpenCommissioningWindowInternal(device); +#if CHIP_ERROR_LOGGING + messageIfError = "Could not connect to open commissioning window"; +#endif // CHIP_ERROR_LOGGING + break; + } + case Step::kAcceptCommissioningStart: { + err = CHIP_ERROR_INCORRECT_STATE; +#if CHIP_ERROR_LOGGING + messageIfError = "Just got a connected device; how can we be done?"; +#endif // CHIP_ERROR_LOGGING + break; + } + } + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "%s", messageIfError); + OnOpenCommissioningWindowFailure(context, err); + } +} + +void CommissioningWindowOpener::OnDeviceConnectionFailureCallback(void * context, PeerId peerId, CHIP_ERROR error) +{ + OnOpenCommissioningWindowFailure(context, error); +} + +namespace { +constexpr char kSpake2pKeyExchangeSalt[] = "SPAKE2P Key Salt"; +} // anonymous namespace + +ByteSpan CommissioningWindowOpener::GetSPAKE2Salt() +{ + return ByteSpan(Uint8::from_const_char(kSpake2pKeyExchangeSalt), sizeof(kSpake2pKeyExchangeSalt) - 1); +} + +AutoCommissioningWindowOpener::AutoCommissioningWindowOpener(DeviceController * controller) : + CommissioningWindowOpener(controller), mOnOpenCommissioningWindowCallback(OnOpenCommissioningWindowResponse, this), + mOnOpenBasicCommissioningWindowCallback(OnOpenBasicCommissioningWindowResponse, this) +{} + +CHIP_ERROR AutoCommissioningWindowOpener::OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId, + uint16_t timeout) +{ + // Not using Platform::New because we want to keep our constructor private. + auto * opener = new AutoCommissioningWindowOpener(controller); + if (opener == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + + CHIP_ERROR err = opener->CommissioningWindowOpener::OpenBasicCommissioningWindow( + deviceId, timeout, &opener->mOnOpenBasicCommissioningWindowCallback); + if (err != CHIP_NO_ERROR) + { + delete opener; + } + // Else will clean up when the callback is called. + return err; +} + +CHIP_ERROR AutoCommissioningWindowOpener::OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, uint16_t timeout, + uint32_t iteration, uint16_t discriminator, + Optional setupPIN, SetupPayload & payload, + bool readVIDPIDAttributes) +{ + // Not using Platform::New because we want to keep our constructor private. + auto * opener = new AutoCommissioningWindowOpener(controller); + if (opener == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + + CHIP_ERROR err = opener->CommissioningWindowOpener::OpenCommissioningWindow( + deviceId, timeout, iteration, discriminator, setupPIN, &opener->mOnOpenCommissioningWindowCallback, payload, + readVIDPIDAttributes); + if (err != CHIP_NO_ERROR) + { + delete opener; + } + // Else will clean up when the callback is called. + return err; +} + +void AutoCommissioningWindowOpener::OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, + chip::SetupPayload payload) +{ + auto * self = static_cast(context); + delete self; +} +void AutoCommissioningWindowOpener::OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status) +{ + auto * self = static_cast(context); + delete self; +} + +} // namespace Controller +} // namespace chip diff --git a/src/controller/CommissioningWindowOpener.h b/src/controller/CommissioningWindowOpener.h new file mode 100644 index 00000000000000..781d63b7e502ad --- /dev/null +++ b/src/controller/CommissioningWindowOpener.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2022 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * A helper class to open a commissioning window given some parameters. + */ + +namespace chip { +namespace Controller { + +// Passing SetupPayload by value on purpose, in case a consumer decides to reuse +// this object from inside the callback. +typedef void (*OnOpenCommissioningWindow)(void * context, NodeId deviceId, CHIP_ERROR status, SetupPayload payload); +typedef void (*OnOpenBasicCommissioningWindow)(void * context, NodeId deviceId, CHIP_ERROR status); + +class CommissioningWindowOpener +{ +public: + CommissioningWindowOpener(DeviceController * controller) : + mController(controller), mDeviceConnected(&OnDeviceConnectedCallback, this), + mDeviceConnectionFailure(&OnDeviceConnectionFailureCallback, this) + {} + + enum class CommissioningWindowOption : uint8_t + { + kOriginalSetupCode = 0, + kTokenWithRandomPIN, + kTokenWithProvidedPIN, + }; + + /* + * @brief + * Try to look up the device attached to our controller with the given + * node id and ask it to re-enter commissioning mode with its original + * PASE verifier, discriminator, etc. The device will exit commissioning + * mode after a successful commissioning, or after the given `timeout` + * time. + * + * @param[in] deviceId The device Id. + * @param[in] timeout The commissioning mode should terminate after this much time. + * @param[in] callback The callback to call once the commissioning window is + * open or if an error occurs. + */ + CHIP_ERROR OpenBasicCommissioningWindow(NodeId deviceId, uint16_t timeout, + Callback::Callback * callback); + + /** + * @brief + * Try to look up the device attached to our controller with the given + * node id and ask it to re-enter commissioning mode with a PASE verifier + * derived from the given information and the given discriminator. The + * device will exit commissioning mode after a successful commissioning, + * or after the given `timeout` time. + * + * @param[in] deviceId The device Id. + * @param[in] timeout The commissioning mode should terminate after this much time. + * @param[in] iteration The PAKE iteration count associated with the PAKE Passcode ID and ephemeral + * PAKE passcode verifier to be used for this commissioning. + * @param[in] discriminator The long discriminator for the DNS-SD advertisement. + * @param[in] setupPIN The setup PIN to use, or NullOptional to use a randomly-generated one. + * @param[in] callback The function to be called on success or failure of opening of commissioning window. + * @param[out] payload The setup payload, not including the VID/PID bits, that is generated based on the + * passed-in information. + * + * @param[in] readVIDPIDAttributes Should the API internally read VID and PID from the device while opening the + * commissioning window. If this argument is `true`, the API will read VID and + * PID from the device and include them in the setup payload passed to the + * callback. + * + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error + */ + CHIP_ERROR OpenCommissioningWindow(NodeId deviceId, uint16_t timeout, uint32_t iteration, uint16_t discriminator, + Optional setupPIN, Callback::Callback * callback, + SetupPayload & payload, bool readVIDPIDAttributes = false); + +private: + enum class Step : uint8_t + { + // Ready to start opening a commissioning window. + kAcceptCommissioningStart, + // Need to read VID. + kReadVID, + // Need to read PID. + kReadPID, + // Need to open commissioning window. + kOpenCommissioningWindow, + }; + + CHIP_ERROR OpenCommissioningWindowInternal(OperationalDeviceProxy * device); + static void OnPIDReadResponse(void * context, uint16_t value); + static void OnVIDReadResponse(void * context, VendorId value); + static void OnVIDPIDReadFailureResponse(void * context, CHIP_ERROR error); + static void OnOpenCommissioningWindowSuccess(void * context, const app::DataModel::NullObjectType &); + static void OnOpenCommissioningWindowFailure(void * context, CHIP_ERROR error); + static void OnDeviceConnectedCallback(void * context, OperationalDeviceProxy * device); + static void OnDeviceConnectionFailureCallback(void * context, PeerId peerId, CHIP_ERROR error); + + // TODO: Salt should be provided as an input or it should be randomly generated when + // the PIN is randomly generated. + static ByteSpan GetSPAKE2Salt(); + + DeviceController * const mController = nullptr; + Step mNextStep = Step::kAcceptCommissioningStart; + + Callback::Callback * mCommissioningWindowCallback = nullptr; + Callback::Callback * mBasicCommissioningWindowCallback = nullptr; + SetupPayload mSetupPayload; + NodeId mNodeId = kUndefinedNodeId; + uint16_t mCommissioningWindowTimeout = 0; + uint32_t mCommissioningWindowIteration = 0; + CommissioningWindowOption mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode; + Spake2pVerifier mVerifier; // Used for non-basic commissioning. + + Callback::Callback mDeviceConnected; + Callback::Callback mDeviceConnectionFailure; +}; + +/** + * A helper class that can be used by consumers that don't care about the callback from the + * open-commissioning-window process and just want automatic cleanup of the CommissioningWindowOpener when done + * with it. + */ +class AutoCommissioningWindowOpener : private CommissioningWindowOpener +{ +public: + // Takes the same arguments as CommissioningWindowOpener::OpenBasicCommissioningWindow except without the + // callback. + static CHIP_ERROR OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId, uint16_t timeout); + // Takes the same arguments as CommissioningWindowOpener::OpenCommissioningWindow except without the + // callback. + static CHIP_ERROR OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, uint16_t timeout, uint32_t iteration, + uint16_t discriminator, Optional setupPIN, SetupPayload & payload, + bool readVIDPIDAttributes = false); + +private: + AutoCommissioningWindowOpener(DeviceController * controller); + + static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload); + static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status); + + chip::Callback::Callback mOnOpenCommissioningWindowCallback; + chip::Callback::Callback mOnOpenBasicCommissioningWindowCallback; +}; + +} // Namespace Controller +} // namespace chip diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index f653f51765626a..c21a45af699922 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -560,7 +561,6 @@ JNI_METHOD(jboolean, openPairingWindow)(JNIEnv * env, jobject self, jlong handle { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; - chip::SetupPayload setupPayload; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) @@ -569,10 +569,9 @@ JNI_METHOD(jboolean, openPairingWindow)(JNIEnv * env, jobject self, jlong handle return false; } - AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - DeviceController::CommissioningWindowOption option = DeviceController::CommissioningWindowOption::kOriginalSetupCode; + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - err = wrapper->Controller()->OpenCommissioningWindow(chipDevice->GetDeviceId(), duration, 0, 0, option, setupPayload); + err = AutoCommissioningWindowOpener::OpenBasicCommissioningWindow(wrapper->Controller(), chipDevice->GetDeviceId(), duration); if (err != CHIP_NO_ERROR) { @@ -588,9 +587,6 @@ JNI_METHOD(jboolean, openPairingWindowWithPIN) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; - chip::SetupPayload setupPayload; - setupPayload.discriminator = discriminator; - setupPayload.setUpPINCode = setupPinCode; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) @@ -599,11 +595,12 @@ JNI_METHOD(jboolean, openPairingWindowWithPIN) return false; } - AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - DeviceController::CommissioningWindowOption option = DeviceController::CommissioningWindowOption::kTokenWithProvidedPIN; + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - err = wrapper->Controller()->OpenCommissioningWindow(chipDevice->GetDeviceId(), duration, iteration, discriminator, option, - setupPayload); + chip::SetupPayload setupPayload; + err = AutoCommissioningWindowOpener::OpenCommissioningWindow(wrapper->Controller(), chipDevice->GetDeviceId(), duration, + iteration, discriminator, + MakeOptional(static_cast(setupPinCode)), setupPayload); if (err != CHIP_NO_ERROR) { diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 04276868b47abb..64c1f8de99e1de 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -412,10 +413,21 @@ ChipError::StorageType pychip_DeviceController_OpenCommissioningWindow(chip::Con chip::NodeId nodeid, uint16_t timeout, uint32_t iteration, uint16_t discriminator, uint8_t optionInt) { - SetupPayload payload; - const auto option = static_cast(optionInt); + const auto option = static_cast(optionInt); + if (option == Controller::CommissioningWindowOpener::CommissioningWindowOption::kOriginalSetupCode) + { + return Controller::AutoCommissioningWindowOpener::OpenBasicCommissioningWindow(devCtrl, nodeid, timeout).AsInteger(); + } + + if (option == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN) + { + SetupPayload payload; + return Controller::AutoCommissioningWindowOpener::OpenCommissioningWindow(devCtrl, nodeid, timeout, iteration, + discriminator, NullOptional, payload) + .AsInteger(); + } - return devCtrl->OpenCommissioningWindow(nodeid, timeout, iteration, discriminator, option, payload).AsInteger(); + return CHIP_ERROR_INVALID_ARGUMENT.AsInteger(); } void pychip_DeviceController_PrintDiscoveredDevices(chip::Controller::DeviceCommissioner * devCtrl) diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController.mm b/src/darwin/Framework/CHIP/CHIPDeviceController.mm index 8d4e54ae952f97..bf0e555bdcbb19 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceController.mm @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -479,9 +480,8 @@ - (BOOL)openPairingWindow:(uint64_t)deviceID duration:(NSUInteger)duration error return NO; } - chip::SetupPayload setupPayload; - err = self.cppCommissioner->OpenCommissioningWindow(deviceID, (uint16_t) duration, 0, 0, - chip::Controller::DeviceController::CommissioningWindowOption::kOriginalSetupCode, setupPayload); + err = chip::Controller::AutoCommissioningWindowOpener::OpenBasicCommissioningWindow( + self.cppCommissioner, deviceID, static_cast(duration)); if (err != CHIP_NO_ERROR) { CHIP_LOG_ERROR("Error(%s): Open Pairing Window failed", chip::ErrorStr(err)); @@ -502,8 +502,6 @@ - (NSString *)openPairingWindowWithPIN:(uint64_t)deviceID { CHIP_ERROR err = CHIP_NO_ERROR; - chip::SetupPayload setupPayload; - if (duration > UINT16_MAX) { CHIP_LOG_ERROR("Error: Duration %tu is too large. Max value %d", duration, UINT16_MAX); if (error) { @@ -518,15 +516,14 @@ - (NSString *)openPairingWindowWithPIN:(uint64_t)deviceID *error = [CHIPError errorForCHIPErrorCode:CHIP_ERROR_INVALID_INTEGER_VALUE]; } return nil; - } else { - setupPayload.discriminator = (uint16_t) discriminator; } setupPIN &= ((1 << chip::kSetupPINCodeFieldLengthInBits) - 1); - setupPayload.setUpPINCode = (uint32_t) setupPIN; - err = self.cppCommissioner->OpenCommissioningWindow(deviceID, (uint16_t) duration, 1000, (uint16_t) discriminator, - chip::Controller::DeviceController::CommissioningWindowOption::kTokenWithProvidedPIN, setupPayload); + chip::SetupPayload setupPayload; + err = chip::Controller::AutoCommissioningWindowOpener::OpenCommissioningWindow(self.cppCommissioner, deviceID, + static_cast(duration), 1000, static_cast(discriminator), + chip::MakeOptional(static_cast(setupPIN)), setupPayload); if (err != CHIP_NO_ERROR) { CHIP_LOG_ERROR("Error(%s): Open Pairing Window failed", chip::ErrorStr(err));