diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp index 1b9578e9535abf..61e1da66b62264 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.cpp +++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp @@ -131,30 +131,12 @@ void PairingCommand::OnDeviceConnectionFailureFn(void * context, NodeId deviceId CHIP_ERROR PairingCommand::PairWithQRCode(NodeId remoteId) { - SetupPayload payload; - ReturnErrorOnFailure(QRCodeSetupPayloadParser(mOnboardingPayload).populatePayload(payload)); - - chip::RendezvousInformationFlags rendezvousInformation = payload.rendezvousInformation; - ReturnErrorCodeIf(rendezvousInformation != RendezvousInformationFlag::kBLE, CHIP_ERROR_INVALID_ARGUMENT); - - return PairWithCode(remoteId, payload); + return GetExecContext()->commissioner->PairDevice(remoteId, mOnboardingPayload); } CHIP_ERROR PairingCommand::PairWithManualCode(NodeId remoteId) { - SetupPayload payload; - ReturnErrorOnFailure(ManualSetupPayloadParser(mOnboardingPayload).populatePayload(payload)); - return PairWithCode(remoteId, payload); -} - -CHIP_ERROR PairingCommand::PairWithCode(NodeId remoteId, SetupPayload payload) -{ - RendezvousParameters params = RendezvousParameters() - .SetSetupPINCode(payload.setUpPINCode) - .SetDiscriminator(payload.discriminator) - .SetPeerAddress(PeerAddress::BLE()); - - return GetExecContext()->commissioner->PairDevice(remoteId, params); + return GetExecContext()->commissioner->PairDevice(remoteId, mOnboardingPayload); } CHIP_ERROR PairingCommand::Pair(NodeId remoteId, PeerAddress address) diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h index 2ea94fc17451ef..5815bf1e59eca4 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.h +++ b/examples/chip-tool/commands/pairing/PairingCommand.h @@ -86,7 +86,6 @@ class PairingCommand : public Command, break; case PairingMode::QRCode: case PairingMode::ManualCode: - AddArgument("fabric-id", 0, UINT64_MAX, &mFabricId); AddArgument("payload", &mOnboardingPayload); break; case PairingMode::Ble: diff --git a/scripts/tests/test_suites.sh b/scripts/tests/test_suites.sh index a0227c25c64539..6747917d33d8d0 100755 --- a/scripts/tests/test_suites.sh +++ b/scripts/tests/test_suites.sh @@ -121,7 +121,7 @@ for j in "${iter_array[@]}"; do # the data is there yet. background_pid="$(OnConnectionComplete = OnConnectionComplete; - mConnectionDelegate->OnConnectionError = OnConnectionError; - // TODO: We are passing the same parameter two times, should take a look at it to see if we can remove one of them. - mConnectionDelegate->NewConnection(this, this, connDiscriminator); + mConnectionDelegate->OnConnectionComplete = onSuccess; + mConnectionDelegate->OnConnectionError = onError; + + mConnectionDelegate->NewConnection(this, appState == nullptr ? this : appState, connDiscriminator); return CHIP_NO_ERROR; } diff --git a/src/ble/BleLayer.h b/src/ble/BleLayer.h index 26e0507096c9d1..d9df92b3a6f7ff 100644 --- a/src/ble/BleLayer.h +++ b/src/ble/BleLayer.h @@ -247,7 +247,9 @@ class DLL_EXPORT BleLayer CHIP_ERROR Shutdown(); CHIP_ERROR CancelBleIncompleteConnection(); - CHIP_ERROR NewBleConnectionByDiscriminator(uint16_t connDiscriminator); + CHIP_ERROR NewBleConnectionByDiscriminator(uint16_t connDiscriminator, void * appState = nullptr, + BleConnectionDelegate::OnConnectionCompleteFunct onSucess = OnConnectionComplete, + BleConnectionDelegate::OnConnectionErrorFunct onError = OnConnectionError); CHIP_ERROR NewBleConnectionByObject(BLE_CONNECTION_OBJECT connObj); CHIP_ERROR NewBleEndPoint(BLEEndPoint ** retEndPoint, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose); diff --git a/src/controller/BUILD.gn b/src/controller/BUILD.gn index a6e4e726fea8c7..cc80ba890e5e02 100644 --- a/src/controller/BUILD.gn +++ b/src/controller/BUILD.gn @@ -41,6 +41,8 @@ static_library("controller") { "EmptyDataModelHandler.cpp", "ExampleOperationalCredentialsIssuer.cpp", "ExampleOperationalCredentialsIssuer.h", + "SetUpCodePairer.cpp", + "SetUpCodePairer.h", ] cflags = [ "-Wconversion" ] diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index e90a6ee21f6a03..ddc3cc02c8c99d 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -598,7 +598,7 @@ DeviceCommissioner::DeviceCommissioner() : mOnAttestationFailureCallback(OnAttestationFailureResponse, this), mOnCSRFailureCallback(OnCSRFailureResponse, this), mOnCertFailureCallback(OnAddNOCFailureResponse, this), mOnRootCertFailureCallback(OnRootCertFailureResponse, this), mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this), - mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this) + mDeviceNOCChainCallback(OnDeviceNOCChainGeneration, this), mSetUpCodePairer(this) { mPairingDelegate = nullptr; mDeviceBeingPaired = kNumMaxActiveDevices; @@ -642,6 +642,10 @@ CHIP_ERROR DeviceCommissioner::Init(CommissionerInitParams params) mUdcServer->SetInstanceNameResolver(this); mUdcServer->SetUserConfirmationProvider(this); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY + +#if CONFIG_NETWORK_LAYER_BLE + mSetUpCodePairer.SetBleLayer(mSystemState->BleLayer()); +#endif // CONFIG_NETWORK_LAYER_BLE return CHIP_NO_ERROR; } @@ -674,6 +678,11 @@ CHIP_ERROR DeviceCommissioner::Shutdown() return CHIP_NO_ERROR; } +CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * setUpCode) +{ + return mSetUpCodePairer.PairDevice(remoteDeviceId, setUpCode); +} + CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 4af19e1f558429..16fe677bd84ccf 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -379,6 +380,21 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, CHIP_ERROR Shutdown() override; // ----- Connection Management ----- + /** + * @brief + * Pair a CHIP device with the provided code. The code can be either a QRCode + * or a Manual Setup Code. + * Use registered DevicePairingDelegate object to receive notifications on + * pairing status updates. + * + * Note: Pairing process requires that the caller has registered PersistentStorageDelegate + * in the Init() call. + * + * @param[in] remoteDeviceId The remote device Id. + * @param[in] setUpCode The setup code for connecting to the device + */ + CHIP_ERROR PairDevice(NodeId remoteDeviceId, const char * setUpCode); + /** * @brief * Pair a CHIP device with the provided Rendezvous connection parameters. @@ -688,6 +704,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, Callback::Callback mOnDeviceConnectionFailureCallback; Callback::Callback mDeviceNOCChainCallback; + SetUpCodePairer mSetUpCodePairer; PASESession mPairingSession; }; diff --git a/src/controller/SetUpCodePairer.cpp b/src/controller/SetUpCodePairer.cpp new file mode 100644 index 00000000000000..19d78bdeb49494 --- /dev/null +++ b/src/controller/SetUpCodePairer.cpp @@ -0,0 +1,178 @@ +/* + * + * Copyright (c) 2021 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. + */ + +/** + * @file + * Implementation of SetUp Code Pairer, a class that parses a given + * setup code and uses the extracted informations to discover and + * filter commissionables nodes, before initiating the pairing process. + * + */ + +#include + +#include +#include +#include + +namespace chip { +namespace Controller { + +CHIP_ERROR SetUpCodePairer::PairDevice(NodeId remoteId, const char * setUpCode) +{ + SetupPayload payload; + + bool isQRCode = strncmp(setUpCode, kQRCodePrefix, strlen(kQRCodePrefix)) == 0; + ReturnErrorOnFailure(isQRCode ? QRCodeSetupPayloadParser(setUpCode).populatePayload(payload) + : ManualSetupPayloadParser(setUpCode).populatePayload(payload)); + + mRemoteId = remoteId; + mSetUpPINCode = payload.setUpPINCode; + + return Connect(payload.rendezvousInformation, payload.discriminator, !isQRCode); +} + +CHIP_ERROR SetUpCodePairer::Connect(RendezvousInformationFlag rendezvousInformation, uint16_t discriminator, bool isShort) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + bool isRunning = false; + + bool searchOverAll = rendezvousInformation == RendezvousInformationFlag::kNone; + if (searchOverAll || rendezvousInformation == RendezvousInformationFlag::kBLE) + { + if (CHIP_NO_ERROR == (err = StartDiscoverOverBle(discriminator, isShort))) + { + isRunning = true; + } + VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err, err); + } + + if (searchOverAll || rendezvousInformation == RendezvousInformationFlag::kOnNetwork) + { + if (CHIP_NO_ERROR == (err = StartDiscoverOverIP(discriminator, isShort))) + { + isRunning = true; + } + VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err, err); + } + + if (searchOverAll || rendezvousInformation == RendezvousInformationFlag::kSoftAP) + { + if (CHIP_NO_ERROR == (err = StartDiscoverOverSoftAP(discriminator, isShort))) + { + isRunning = true; + } + VerifyOrReturnError(searchOverAll || CHIP_NO_ERROR == err, err); + } + + return isRunning ? CHIP_NO_ERROR : CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR SetUpCodePairer::StartDiscoverOverBle(uint16_t discriminator, bool isShort) +{ +#if CONFIG_NETWORK_LAYER_BLE + VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + return mBleLayer->NewBleConnectionByDiscriminator(discriminator, this, OnDiscoveredDeviceOverBleSuccess, + OnDiscoveredDeviceOverBleError); +#else + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // CONFIG_NETWORK_LAYER_BLE +} + +CHIP_ERROR SetUpCodePairer::StopConnectOverBle() +{ +#if CONFIG_NETWORK_LAYER_BLE + VerifyOrReturnError(mBleLayer != nullptr, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + return mBleLayer->CancelBleIncompleteConnection(); +#else + return CHIP_NO_ERROR; +#endif // CONFIG_NETWORK_LAYER_BLE +} + +CHIP_ERROR SetUpCodePairer::StartDiscoverOverIP(uint16_t discriminator, bool isShort) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS + mCommissioner->RegisterDeviceDiscoveryDelegate(this); + Mdns::DiscoveryFilter filter(isShort ? Mdns::DiscoveryFilterType::kShort : Mdns::DiscoveryFilterType::kLong, discriminator); + return mCommissioner->DiscoverCommissionableNodes(filter); +#else + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS +} + +CHIP_ERROR SetUpCodePairer::StopConnectOverIP() +{ +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS + mCommissioner->RegisterDeviceDiscoveryDelegate(nullptr); +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS + return CHIP_NO_ERROR; +} + +CHIP_ERROR SetUpCodePairer::StartDiscoverOverSoftAP(uint16_t discriminator, bool isShort) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +CHIP_ERROR SetUpCodePairer::StopConnectOverSoftAP() +{ + return CHIP_NO_ERROR; +} + +void SetUpCodePairer::OnDeviceDiscovered(RendezvousParameters & params) +{ + LogErrorOnFailure(mCommissioner->PairDevice(mRemoteId, params.SetSetupPINCode(mSetUpPINCode))); +} + +#if CONFIG_NETWORK_LAYER_BLE +void SetUpCodePairer::OnDiscoveredDeviceOverBle(BLE_CONNECTION_OBJECT connObj) +{ + LogErrorOnFailure(StopConnectOverIP()); + LogErrorOnFailure(StopConnectOverSoftAP()); + + Transport::PeerAddress peerAddress = Transport::PeerAddress::BLE(); + RendezvousParameters params = RendezvousParameters().SetPeerAddress(peerAddress).SetConnectionObject(connObj); + OnDeviceDiscovered(params); +} + +void SetUpCodePairer::OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj) +{ + (static_cast(appState))->OnDiscoveredDeviceOverBle(connObj); +} + +void SetUpCodePairer::OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err) +{ + LogErrorOnFailure(err); +} +#endif // CONFIG_NETWORK_LAYER_BLE + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS +void SetUpCodePairer::OnDiscoveredDevice(const Mdns::DiscoveredNodeData & nodeData) +{ + LogErrorOnFailure(StopConnectOverBle()); + LogErrorOnFailure(StopConnectOverIP()); + LogErrorOnFailure(StopConnectOverSoftAP()); + + Inet::InterfaceId interfaceId = nodeData.ipAddress[0].IsIPv6LinkLocal() ? nodeData.interfaceId[0] : INET_NULL_INTERFACEID; + Transport::PeerAddress peerAddress = Transport::PeerAddress::UDP(nodeData.ipAddress[0], nodeData.port, interfaceId); + RendezvousParameters params = RendezvousParameters().SetPeerAddress(peerAddress); + OnDeviceDiscovered(params); +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS + +} // namespace Controller +} // namespace chip diff --git a/src/controller/SetUpCodePairer.h b/src/controller/SetUpCodePairer.h new file mode 100644 index 00000000000000..5f50a8bac1e552 --- /dev/null +++ b/src/controller/SetUpCodePairer.h @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2021 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. + */ + +/** + * @file + * Declaration of SetUp Code Pairer, a class that parses a given + * setup code and uses the extracted informations to discover and + * filter commissionables nodes, before initiating the pairing process. + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if CONFIG_NETWORK_LAYER_BLE +#include +#endif // CONFIG_NETWORK_BLE + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS +#include +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS + +namespace chip { +namespace Controller { + +class DeviceCommissioner; + +class DLL_EXPORT SetUpCodePairer +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS + : public DeviceDiscoveryDelegate +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS +{ +public: + SetUpCodePairer(DeviceCommissioner * commissioner) : mCommissioner(commissioner) {} + virtual ~SetUpCodePairer() {} + + CHIP_ERROR PairDevice(chip::NodeId remoteId, const char * setUpCode); + +#if CONFIG_NETWORK_LAYER_BLE + void SetBleLayer(Ble::BleLayer * bleLayer) { mBleLayer = bleLayer; }; +#endif // CONFIG_NETWORK_LAYER_BLE + +private: + CHIP_ERROR Connect(RendezvousInformationFlag rendezvousInformation, uint16_t discriminator, bool isShort); + CHIP_ERROR StartDiscoverOverBle(uint16_t discriminator, bool isShort); + CHIP_ERROR StopConnectOverBle(); + CHIP_ERROR StartDiscoverOverIP(uint16_t discriminator, bool isShort); + CHIP_ERROR StopConnectOverIP(); + CHIP_ERROR StartDiscoverOverSoftAP(uint16_t discriminator, bool isShort); + CHIP_ERROR StopConnectOverSoftAP(); + + void OnDeviceDiscovered(RendezvousParameters & params); + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS + /////////// DeviceDiscoveryDelegate Interface ///////// + void OnDiscoveredDevice(const chip::Mdns::DiscoveredNodeData & nodeData) override; +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS + +#if CONFIG_NETWORK_LAYER_BLE + Ble::BleLayer * mBleLayer = nullptr; + void OnDiscoveredDeviceOverBle(BLE_CONNECTION_OBJECT connObj); + /////////// BLEConnectionDelegate Callbacks ///////// + static void OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj); + static void OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err); +#endif // CONFIG_NETWORK_LAYER_BLE + + DeviceCommissioner * mCommissioner = nullptr; + chip::NodeId mRemoteId; + uint32_t mSetUpPINCode = 0; +}; + +} // namespace Controller +} // namespace chip