diff --git a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp index abc94a593e3948..bd39eb855b715b 100644 --- a/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp +++ b/examples/chip-tool/commands/pairing/OpenCommissioningWindowCommand.cpp @@ -18,30 +18,40 @@ #include "OpenCommissioningWindowCommand.h" +#include + 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, System::Clock::Seconds16(mTimeout), + &mOnOpenBasicCommissioningWindowCallback); + } + + if (mCommissioningWindowOption == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN) + { + SetupPayload ignored; + return mWindowOpener->OpenCommissioningWindow(mNodeId, System::Clock::Seconds16(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 +59,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 90553946503d92..8b8a168a134288 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 e4f1b3d888ea5d..c2365bb122fd5e 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..977c44ffc74245 --- /dev/null +++ b/src/controller/CommissioningWindowOpener.cpp @@ -0,0 +1,350 @@ +/* + * 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; +using namespace chip::System::Clock; + +namespace { +// TODO: What should the timed invoke timeout here be? +constexpr uint16_t kTimedInvokeTimeoutMs = 10000; +} // anonymous namespace + +namespace chip { +namespace Controller { + +CHIP_ERROR CommissioningWindowOpener::OpenBasicCommissioningWindow(NodeId deviceId, Seconds16 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, Seconds16 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.count(); + request.PAKEVerifier = serializedVerifierSpan; + request.discriminator = mSetupPayload.discriminator; + request.iterations = mCommissioningWindowIteration; + request.salt = GetSPAKE2Salt(); + + ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, + OnOpenCommissioningWindowFailure, MakeOptional(kTimedInvokeTimeoutMs))); + + 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.count(); + ReturnErrorOnFailure(cluster.InvokeCommand(request, this, OnOpenCommissioningWindowSuccess, + OnOpenCommissioningWindowFailure, MakeOptional(kTimedInvokeTimeoutMs))); + } + + 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 PID 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: %" CHIP_ERROR_FORMAT, messageIfError, err.Format()); + 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, + Seconds16 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, Seconds16 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..d3bc789d35c06f --- /dev/null +++ b/src/controller/CommissioningWindowOpener.h @@ -0,0 +1,176 @@ +/* + * 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 +#include + +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); + +/** + * A helper class to open a commissioning window given some parameters. + */ +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, System::Clock::Seconds16 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, + * even if those were asked for, that is generated + * based on the passed-in information. The payload + * provided to the callback function, unlike this + * out parameter, will include the VID/PID bits if + * readVIDPIDAttributes is true. + * + * @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. + */ + CHIP_ERROR OpenCommissioningWindow(NodeId deviceId, System::Clock::Seconds16 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; + System::Clock::Seconds16 mCommissioningWindowTimeout = System::Clock::kZero; + 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, + System::Clock::Seconds16 timeout); + // Takes the same arguments as CommissioningWindowOpener::OpenCommissioningWindow except without the + // callback. + static CHIP_ERROR OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, System::Clock::Seconds16 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 f4456bd11c888d..b4338f067e5b66 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 @@ -47,6 +48,7 @@ #include #include #include +#include #include #include @@ -584,7 +586,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) @@ -593,10 +594,10 @@ 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(), + System::Clock::Seconds16(duration)); if (err != CHIP_NO_ERROR) { @@ -612,9 +613,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) @@ -623,11 +621,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(), + System::Clock::Seconds16(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..482a062e924f34 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 @@ -66,6 +67,7 @@ #include #include #include +#include using namespace chip; using namespace chip::Ble; @@ -412,10 +414,23 @@ 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, + System::Clock::Seconds16(timeout)) + .AsInteger(); + } + + if (option == Controller::CommissioningWindowOpener::CommissioningWindowOption::kTokenWithRandomPIN) + { + SetupPayload payload; + return Controller::AutoCommissioningWindowOpener::OpenCommissioningWindow( + devCtrl, nodeid, System::Clock::Seconds16(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 b11abb160d61b3..cd15f0bf622c11 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceController.mm @@ -37,11 +37,13 @@ #include #include +#include #include #include #include #include #include +#include static const char * const CHIP_COMMISSIONER_DEVICE_ID_KEY = "com.zigbee.chip.commissioner.device_id"; @@ -482,9 +484,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, chip::System::Clock::Seconds16(static_cast(duration))); if (err != CHIP_NO_ERROR) { CHIP_LOG_ERROR("Error(%s): Open Pairing Window failed", chip::ErrorStr(err)); @@ -505,8 +506,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) { @@ -521,15 +520,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, + chip::System::Clock::Seconds16(static_cast(duration)), chip::Crypto::kSpake2p_Min_PBKDF_Iterations, + 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));