From 710b9d8e043b45ca96e09f15df5dbef44b5bc4b4 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 24 Mar 2022 16:08:47 -0400 Subject: [PATCH] Add a helper class for opening commissioning windows. (#16474) * 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 * Address review comments. * Address review comments. --- .../OpenCommissioningWindowCommand.cpp | 43 ++- .../pairing/OpenCommissioningWindowCommand.h | 20 +- src/controller/BUILD.gn | 2 + src/controller/CHIPDeviceController.cpp | 181 --------- src/controller/CHIPDeviceController.h | 90 ----- src/controller/CommissioningWindowOpener.cpp | 350 ++++++++++++++++++ src/controller/CommissioningWindowOpener.h | 176 +++++++++ .../java/CHIPDeviceController-JNI.cpp | 21 +- .../ChipDeviceController-ScriptBinding.cpp | 21 +- .../Framework/CHIP/CHIPDeviceController.mm | 18 +- 10 files changed, 598 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..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));