From 047424fca5a7b8d60e844db27f5e249aca3a8d81 Mon Sep 17 00:00:00 2001 From: Pankaj Garg Date: Tue, 10 Nov 2020 21:56:59 -0800 Subject: [PATCH] Enable pairing for multiple devices (#3630) --- .../esp32/main/RendezvousDeviceDelegate.cpp | 11 + examples/chip-tool/commands/common/Command.h | 2 +- examples/chip-tool/commands/common/Commands.h | 2 +- src/controller/BUILD.gn | 4 + src/controller/CHIPDevice.cpp | 216 +++++ src/controller/CHIPDevice.h | 260 ++++++ src/controller/CHIPDeviceController.cpp | 799 +++++++++--------- src/controller/CHIPDeviceController.h | 311 ++++--- .../CHIPDeviceController_deprecated.cpp | 239 ++++++ .../CHIPDeviceController_deprecated.h | 220 +++++ .../CHIPPersistentStorageDelegate.h | 19 +- .../java/AndroidDeviceControllerWrapper.h | 4 +- .../java/CHIPDeviceController-JNI.cpp | 2 +- src/controller/python/BUILD.gn | 3 +- .../ChipDeviceController-ScriptBinding.cpp | 6 +- ...ceController-ScriptDevicePairingDelegate.h | 4 +- .../Framework Helpers/DefaultsUtils.m | 8 + .../Framework/CHIP/CHIPDeviceController.mm | 18 +- .../CHIP/CHIPDevicePairingDelegateBridge.h | 2 +- .../CHIP/CHIPPersistentStorageDelegate.h | 6 + .../CHIPPersistentStorageDelegateBridge.h | 8 +- .../CHIPPersistentStorageDelegateBridge.mm | 39 +- src/lib/support/SerializableIntegerSet.h | 6 +- src/transport/RendezvousSession.cpp | 22 +- src/transport/RendezvousSession.h | 2 +- src/transport/SecurePairingSession.cpp | 76 +- src/transport/SecurePairingSession.h | 75 +- src/transport/SecureSessionMgr.cpp | 4 + src/transport/SecureSessionMgr.h | 6 + src/transport/raw/Base.h | 5 + src/transport/raw/UDP.cpp | 25 +- src/transport/raw/UDP.h | 5 + 32 files changed, 1728 insertions(+), 681 deletions(-) create mode 100644 src/controller/CHIPDevice.cpp create mode 100644 src/controller/CHIPDevice.h create mode 100644 src/controller/CHIPDeviceController_deprecated.cpp create mode 100644 src/controller/CHIPDeviceController_deprecated.h diff --git a/examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp b/examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp index 5060b57595c12d..683a577c694fe3 100644 --- a/examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp +++ b/examples/all-clusters-app/esp32/main/RendezvousDeviceDelegate.cpp @@ -70,12 +70,23 @@ void RendezvousDeviceDelegate::OnRendezvousStatusUpdate(RendezvousSessionDelegat bluetoothLED.Set(true); break; + case RendezvousSessionDelegate::SecurePairingFailed: + ESP_LOGI(TAG, "Failed in SPAKE2+ handshake\n"); + bluetoothLED.Set(false); + break; + case RendezvousSessionDelegate::NetworkProvisioningSuccess: ESP_LOGI(TAG, "Device was assigned an ip address\n"); bluetoothLED.Set(false); break; + case RendezvousSessionDelegate::NetworkProvisioningFailed: + + ESP_LOGI(TAG, "Failed in network provisioning\n"); + bluetoothLED.Set(false); + break; + default: break; }; diff --git a/examples/chip-tool/commands/common/Command.h b/examples/chip-tool/commands/common/Command.h index 8c81731d486726..7ef5727c32b5fe 100644 --- a/examples/chip-tool/commands/common/Command.h +++ b/examples/chip-tool/commands/common/Command.h @@ -18,7 +18,7 @@ #pragma once -#include +#include #include #include diff --git a/examples/chip-tool/commands/common/Commands.h b/examples/chip-tool/commands/common/Commands.h index 531b557994ada7..c331831f86245f 100644 --- a/examples/chip-tool/commands/common/Commands.h +++ b/examples/chip-tool/commands/common/Commands.h @@ -21,7 +21,7 @@ #include "Command.h" #include -#include +#include class Commands { diff --git a/src/controller/BUILD.gn b/src/controller/BUILD.gn index 7d843de0f38dfc..aaab1fef51e675 100644 --- a/src/controller/BUILD.gn +++ b/src/controller/BUILD.gn @@ -18,8 +18,12 @@ static_library("controller") { output_name = "libChipController" sources = [ + "CHIPDevice.cpp", + "CHIPDevice.h", "CHIPDeviceController.cpp", "CHIPDeviceController.h", + "CHIPDeviceController_deprecated.cpp", + "CHIPDeviceController_deprecated.h", ] cflags = [ "-Wconversion" ] diff --git a/src/controller/CHIPDevice.cpp b/src/controller/CHIPDevice.cpp new file mode 100644 index 00000000000000..68048e7d97c1ba --- /dev/null +++ b/src/controller/CHIPDevice.cpp @@ -0,0 +1,216 @@ +/* + * + * Copyright (c) 2020 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 + * This file contains implementation of Device class. The objects of this + * class will be used by Controller applications to interact with CHIP + * devices. The class provides mechanism to construct, send and receive + * messages to and from the corresponding CHIP devices. + */ + +#include + +#if CONFIG_DEVICE_LAYER +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip::Inet; +using namespace chip::System; + +namespace chip { +namespace Controller { + +CHIP_ERROR Device::SendMessage(System::PacketBuffer * buffer) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + System::PacketBuffer * resend = nullptr; + + VerifyOrExit(mSessionManager != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(buffer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + + // If there is no secure connection to the device, try establishing it + if (mState != ConnectionState::SecureConnected) + { + err = LoadSecureSessionParameters(); + SuccessOrExit(err); + } + else + { + // Secure connection already exists + // Hold on to the buffer, in case session resumption and resend is needed + buffer->AddRef(); + resend = buffer; + } + + err = mSessionManager->SendMessage(mDeviceId, buffer); + buffer = nullptr; + ChipLogDetail(Controller, "SendMessage returned %d", err); + + // The send could fail due to network timeouts (e.g. broken pipe) + // Try sesion resumption if needed + if (err != CHIP_NO_ERROR && resend != nullptr && mState == ConnectionState::SecureConnected) + { + mState = ConnectionState::NotConnected; + + err = LoadSecureSessionParameters(); + SuccessOrExit(err); + + err = mSessionManager->SendMessage(mDeviceId, resend); + resend = nullptr; + ChipLogDetail(Controller, "Re-SendMessage returned %d", err); + SuccessOrExit(err); + } + +exit: + + if (buffer != nullptr) + { + PacketBuffer::Free(buffer); + } + + if (resend != nullptr) + { + PacketBuffer::Free(resend); + } + + return err; +} + +CHIP_ERROR Device::Serialize(SerializedDevice & output) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + uint16_t serializedLen = 0; + SerializableDevice serializable; + + nlSTATIC_ASSERT_PRINT(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner), + "Size of serializable should be <= size of output"); + + CHIP_ZERO_AT(serializable); + + memmove(&serializable.mOpsCreds, &mPairing, sizeof(mPairing)); + serializable.mDeviceId = Encoding::LittleEndian::HostSwap64(mDeviceId); + serializable.mDevicePort = Encoding::LittleEndian::HostSwap16(mDevicePort); + nlSTATIC_ASSERT_PRINT(sizeof(serializable.mDeviceAddr) <= INET6_ADDRSTRLEN, + "Size of device address must fit within INET6_ADDRSTRLEN"); + mDeviceAddr.ToString(Uint8::to_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr)); + + serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast(&serializable)), + static_cast(sizeof(serializable)), Uint8::to_char(output.inner)); + VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT); + output.inner[serializedLen] = '\0'; + +exit: + return error; +} + +CHIP_ERROR Device::Deserialize(const SerializedDevice & input) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + SerializableDevice serializable; + size_t maxlen = BASE64_ENCODED_LEN(sizeof(serializable)); + size_t len = strnlen(Uint8::to_const_char(&input.inner[0]), maxlen); + uint16_t deserializedLen = 0; + + VerifyOrExit(len < sizeof(SerializedDevice), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(CanCastTo(len), error = CHIP_ERROR_INVALID_ARGUMENT); + + CHIP_ZERO_AT(serializable); + deserializedLen = Base64Decode(Uint8::to_const_char(input.inner), static_cast(len), + Uint8::to_uchar(reinterpret_cast(&serializable))); + + VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT); + + // The second parameter to FromString takes the strlen value. We are subtracting 1 + // from the sizeof(serializable.mDeviceAddr) to account for null termination, since + // strlen doesn't include null character in the size. + VerifyOrExit( + IPAddress::FromString(Uint8::to_const_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr) - 1, mDeviceAddr), + error = CHIP_ERROR_INVALID_ADDRESS); + + memmove(&mPairing, &serializable.mOpsCreds, sizeof(mPairing)); + mDeviceId = Encoding::LittleEndian::HostSwap64(serializable.mDeviceId); + mDevicePort = Encoding::LittleEndian::HostSwap16(serializable.mDevicePort); + +exit: + return error; +} + +void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, + Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, SecureSessionMgrBase * mgr) +{ + if (mState == ConnectionState::SecureConnected && mStatusDelegate != nullptr) + { + mStatusDelegate->OnMessage(msgBuf); + } +} + +CHIP_ERROR Device::LoadSecureSessionParameters() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + SecurePairingSession pairingSession; + + if (mSessionManager == nullptr || mState == ConnectionState::SecureConnected) + { + ExitNow(err = CHIP_ERROR_INCORRECT_STATE); + } + + err = pairingSession.FromSerializable(mPairing); + SuccessOrExit(err); + + err = mSessionManager->ResetTransport(Transport::UdpListenParameters(mInetLayer).SetAddressType(mDeviceAddr.Type())); + SuccessOrExit(err); + + err = mSessionManager->NewPairing( + Optional::Value(Transport::PeerAddress::UDP(mDeviceAddr, mDevicePort, mInterface)), + &pairingSession); + SuccessOrExit(err); + + mState = ConnectionState::SecureConnected; + +exit: + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "LoadSecureSessionParameters returning error %d\n", err); + } + return err; +} + +bool Device::GetIpAddress(Inet::IPAddress & addr) const +{ + if (mState == ConnectionState::SecureConnected) + addr = mDeviceAddr; + return mState == ConnectionState::SecureConnected; +} + +} // namespace Controller +} // namespace chip diff --git a/src/controller/CHIPDevice.h b/src/controller/CHIPDevice.h new file mode 100644 index 00000000000000..69d7491717c08a --- /dev/null +++ b/src/controller/CHIPDevice.h @@ -0,0 +1,260 @@ +/* + * + * Copyright (c) 2020 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 + * This file contains definitions for Device class. The objects of this + * class will be used by Controller applications to interact with CHIP + * devices. The class provides mechanism to construct, send and receive + * messages to and from the corresponding CHIP devices. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Controller { + +class DeviceController; +class DeviceStatusDelegate; +struct SerializedDevice; + +class DLL_EXPORT Device +{ +public: + Device() : mActive(false), mState(ConnectionState::NotConnected) {} + ~Device() {} + + /** + * @brief + * Set the delegate object which will be called when a message is received. + * The user of this Device object must reset the delegate (by calling + * SetDelegate(nullptr)) before releasing their delegate object. + * + * @param[in] delegate The pointer to the delegate object. + */ + void SetDelegate(DeviceStatusDelegate * delegate) { mStatusDelegate = delegate; } + + // ----- Messaging ----- + /** + * @brief + * Send the provided message to the device + * + * @param[in] message The message to be sent. The ownership of the message buffer + * is handed over to Device object. SendMessage() will + * decrement the reference count of the message buffer before + * returning. + * + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error + */ + CHIP_ERROR SendMessage(System::PacketBuffer * message); + + /** + * @brief + * Get the IP address assigned to the device. + * + * @param[out] addr The reference to the IP address. + * + * @return true, if the IP address was filled in the out parameter, false otherwise + */ + bool GetIpAddress(Inet::IPAddress & addr) const; + + /** + * @brief + * Initialize the device object with secure session manager and inet layer object + * references. This variant of function is typically used when the device object + * is created from a serialized device information. The other parameters (address, port, + * interface etc) are part of the serialized device, so those are not required to be + * initialized. + * + * Note: The lifetime of session manager and inet layer objects must be longer than + * that of this device object. If these objects are freed, while the device object is + * still using them, it can lead to unknown behavior and crashes. + * + * @param[in] sessionMgr Secure session manager object pointer + * @param[in] inetLayer InetLayer object pointer + */ + void Init(SecureSessionMgr * sessionMgr, Inet::InetLayer * inetLayer) + { + mSessionManager = sessionMgr; + mInetLayer = inetLayer; + } + + /** + * @brief + * Initialize a new device object with secure session manager, inet layer object, + * and other device specific parameters. This variant of function is typically used when + * a new device is paired, and the corresponding device object needs to updated with + * all device specifc parameters (address, port, interface etc). + * + * This is not done as part of constructor so that the controller can have a list of + * uninitialzed/unpaired device objects. The object is initialized only when the device + * is actually paired. + * + * @param[in] sessionMgr Secure session manager object pointer + * @param[in] inetLayer InetLayer object pointer + * @param[in] deviceId Node ID of the device + * @param[in] devicePort Port on which device is listening (typically CHIP_PORT) + * @param[in] interfaceId Local Interface ID that should be used to talk to the device + */ + void Init(SecureSessionMgr * sessionMgr, Inet::InetLayer * inetLayer, NodeId deviceId, uint16_t devicePort, + Inet::InterfaceId interfaceId) + { + Init(sessionMgr, inetLayer); + mDeviceId = deviceId; + mDevicePort = devicePort; + mInterface = interfaceId; + mState = ConnectionState::Connecting; + } + + /** @brief Serialize the Pairing Session to a string. It's guaranteed that the string + * will be null terminated, and there won't be any embedded null characters. + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Serialize(SerializedDevice & output); + + /** @brief Deserialize the Pairing Session from the string. It's expected that the string + * will be null terminated, and there won't be any embedded null characters. + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Deserialize(const SerializedDevice & input); + + /** + * @brief + * This function is called when a message is received from the corresponding CHIP + * device. The message ownership is transferred to the function, and it is expected + * to release the message buffer before returning. + * + * @param[in] header Reference to common packet header of the received message + * @param[in] payloadHeader Reference to payload header in the message + * @param[in] state Pointer to the peer connection state on which message is received + * @param[in] msgBuf The message buffer + * @param[in] mgr Pointer to secure session manager which received the message + */ + void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, Transport::PeerConnectionState * state, + System::PacketBuffer * msgBuf, SecureSessionMgrBase * mgr); + + /** + * @brief + * Return whether the current device object is actively associated with a paired CHIP + * device. An active object can be used to communicate with the corresponding device. + */ + bool IsActive() const { return mActive; } + + void SetActive(bool active) { mActive = active; } + + NodeId GetDeviceId() const { return mDeviceId; } + + void SetAddress(const Inet::IPAddress & deviceAddr) { mDeviceAddr = deviceAddr; } + + SecurePairingSessionSerializable & GetPairing() { return mPairing; } + +private: + enum class ConnectionState + { + NotConnected, + Connecting, + SecureConnected, + }; + + /* Node ID assigned to the CHIP device */ + NodeId mDeviceId; + + /* IP Address of the CHIP device */ + Inet::IPAddress mDeviceAddr; + + /* Port on which the CHIP device is receiving messages. Typically it is CHIP_PORT */ + uint16_t mDevicePort; + + /* Local network interface that should be used to communicate with the device */ + Inet::InterfaceId mInterface; + + Inet::InetLayer * mInetLayer; + + bool mActive; + ConnectionState mState; + + SecurePairingSessionSerializable mPairing; + + DeviceStatusDelegate * mStatusDelegate; + + SecureSessionMgr * mSessionManager; + + /** + * @brief + * This function loads the secure session object from the serialized operational + * credentials corresponding to the device. This is typically done when the device + * does not have an active secure channel. + */ + CHIP_ERROR LoadSecureSessionParameters(); +}; + +/** + * This class defines an interface for an object that the user of Device + * can register as a delegate. The delegate object will be called by the + * Device when a new message or status update is received from the corresponding + * CHIP device. + */ +class DLL_EXPORT DeviceStatusDelegate +{ +public: + virtual ~DeviceStatusDelegate() {} + + /** + * @brief + * Called when a message is received from the device. + * + * @param[in] msg Received message buffer. + */ + virtual void OnMessage(System::PacketBuffer * msg) = 0; + + /** + * @brief + * Called when device status is updated. + * + */ + virtual void OnStatusChange(void){}; +}; + +typedef struct SerializableDevice +{ + SecurePairingSessionSerializable mOpsCreds; + uint64_t mDeviceId; /* This field is serialized in LittleEndian byte order */ + uint8_t mDeviceAddr[INET6_ADDRSTRLEN]; + uint16_t mDevicePort; /* This field is serealized in LittelEndian byte order */ +} SerializableDevice; + +typedef struct SerializedDevice +{ + // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads) + // The encoder may not include a NULL character, and there are maximum 2 bytes of padding. + // So extra 8 bytes should be sufficient to absorb this overhead. + uint8_t inner[BASE64_ENCODED_LEN(sizeof(SerializableDevice) + sizeof(uint64_t))]; +} SerializedDevice; + +} // namespace Controller +} // namespace chip diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index ab1471b3d1f651..7ce20bddb661e3 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -59,12 +60,12 @@ using namespace chip::Inet; using namespace chip::System; namespace chip { -namespace DeviceController { +namespace Controller { using namespace chip::Encoding; -constexpr const char kDeviceCredentialsKeyPrefix[] = "DeviceCredentials"; -constexpr const char kDeviceAddressKeyPrefix[] = "DeviceAddress"; +constexpr const char kPairedDeviceListKeyPrefix[] = "ListPairedDevices"; +constexpr const char kPairedDeviceKeyPrefix[] = "PairedDevice"; // This macro generates a key using node ID an key prefix, and performs the given action // on that key. @@ -80,66 +81,41 @@ constexpr const char kDeviceAddressKeyPrefix[] = "DeviceAddress"; action; \ } while (0) -ChipDeviceController::ChipDeviceController() +DeviceController::DeviceController() { - mState = kState_NotInitialized; - AppState = nullptr; - mConState = kConnectionState_NotConnected; - mRendezvousSession = nullptr; - mSessionManager = nullptr; - mCurReqMsg = nullptr; - mOnError = nullptr; - mOnNewConnection = nullptr; - mPairingDelegate = nullptr; - mStorageDelegate = nullptr; - mListenPort = CHIP_PORT; - mDeviceAddr = IPAddress::Any; - mDevicePort = CHIP_PORT; - mInterface = INET_NULL_INTERFACEID; - mLocalDeviceId = 0; - mNumCachedPackets = 0; - CHIP_ZERO_AT(mOnComplete); - CHIP_ZERO_AT(mCachedPackets); + mState = State::NotInitialized; + mSessionManager = nullptr; + mLocalDeviceId = 0; + mStorageDelegate = nullptr; + mPairedDevicesInitialized = false; } -ChipDeviceController::~ChipDeviceController() -{ - if (mTestSecurePairingSecret != nullptr) - { - chip::Platform::Delete(mTestSecurePairingSecret); - } -} - -CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, DevicePairingDelegate * pairingDelegate, - PersistentStorageDelegate * storageDelegate) +CHIP_ERROR DeviceController::Init(NodeId localDeviceId, PersistentStorageDelegate * storageDelegate, System::Layer * systemLayer, + Inet::InetLayer * inetLayer) { CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mState == State::NotInitialized, err = CHIP_ERROR_INCORRECT_STATE); + if (systemLayer != nullptr && inetLayer != nullptr) + { + mSystemLayer = systemLayer; + mInetLayer = inetLayer; + } + else + { #if CONFIG_DEVICE_LAYER - err = DeviceLayer::PlatformMgr().InitChipStack(); - SuccessOrExit(err); + err = DeviceLayer::PlatformMgr().InitChipStack(); + SuccessOrExit(err); - err = Init(localNodeId, &DeviceLayer::SystemLayer, &DeviceLayer::InetLayer, pairingDelegate, storageDelegate); + mSystemLayer = &DeviceLayer::SystemLayer; + mInetLayer = &DeviceLayer::InetLayer; #endif // CONFIG_DEVICE_LAYER + } -exit: - return err; -} - -CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, System::Layer * systemLayer, InetLayer * inetLayer, - DevicePairingDelegate * pairingDelegate, PersistentStorageDelegate * storageDelegate) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mSystemLayer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mInetLayer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - mState = kState_Initialized; - mLocalDeviceId = localNodeId; - mSystemLayer = systemLayer; - mInetLayer = inetLayer; - mPairingDelegate = pairingDelegate; mStorageDelegate = storageDelegate; if (mStorageDelegate != nullptr) @@ -147,19 +123,30 @@ CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, System::Layer * system mStorageDelegate->SetDelegate(this); } + mSessionManager = chip::Platform::New>(); + + err = mSessionManager->Init(localDeviceId, mSystemLayer, + Transport::UdpListenParameters(mInetLayer).SetAddressType(Inet::kIPAddressType_IPv6)); + SuccessOrExit(err); + + mSessionManager->SetDelegate(this); + + mState = State::Initialized; + mLocalDeviceId = localDeviceId; + exit: return err; } -CHIP_ERROR ChipDeviceController::Shutdown() +CHIP_ERROR DeviceController::Shutdown() { CHIP_ERROR err = CHIP_NO_ERROR; - ChipLogDetail(Controller, "Shutting down the controller"); + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); + ChipLogDetail(Controller, "Shutting down the controller"); - mState = kState_NotInitialized; + mState = State::NotInitialized; #if CONFIG_DEVICE_LAYER err = DeviceLayer::PlatformMgr().Shutdown(); @@ -174,285 +161,276 @@ CHIP_ERROR ChipDeviceController::Shutdown() mSystemLayer = nullptr; mInetLayer = nullptr; - if (mSessionManager != nullptr) + if (mStorageDelegate != nullptr) { - chip::Platform::Delete(mSessionManager); - mSessionManager = nullptr; + mStorageDelegate->SetDelegate(nullptr); + mStorageDelegate = nullptr; } - if (mRendezvousSession != nullptr) + if (mSessionManager != nullptr) { - chip::Platform::Delete(mRendezvousSession); - mRendezvousSession = nullptr; + mSessionManager->SetDelegate(nullptr); + chip::Platform::Delete(mSessionManager); + mSessionManager = nullptr; } - mConState = kConnectionState_NotConnected; - CHIP_ZERO_AT(mOnComplete); - mOnError = nullptr; - mOnNewConnection = nullptr; - mRemoteDeviceId.ClearValue(); - exit: return err; } -CHIP_ERROR ChipDeviceController::ConnectDevice(NodeId remoteDeviceId, RendezvousParameters & params, void * appReqState, - NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, - ErrorHandler onError, uint16_t devicePort, Inet::InterfaceId interfaceId) +CHIP_ERROR DeviceController::GetDevice(NodeId deviceId, const SerializedDevice & deviceInfo, Device ** out_device) { - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; + uint16_t index = 0; - VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(mConState == kConnectionState_NotConnected, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(out_device != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + index = FindDeviceIndex(deviceId); -#if CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE - if (!params.HasBleLayer()) + if (index < kNumMaxActiveDevices) { - params.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer()); + device = &mActiveDevices[index]; } -#endif // CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE + else + { + VerifyOrExit(mPairedDevices.Contains(deviceId), err = CHIP_ERROR_NOT_CONNECTED); - mRendezvousSession = chip::Platform::New(this); - err = mRendezvousSession->Init(params.SetLocalNodeId(mLocalDeviceId)); - SuccessOrExit(err); + index = GetInactiveDeviceIndex(); + VerifyOrExit(index < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY); + device = &mActiveDevices[index]; - mRemoteDeviceId = Optional::Value(remoteDeviceId); - mDevicePort = devicePort; - mInterface = interfaceId; - mAppReqState = appReqState; - mOnNewConnection = onConnected; + err = device->Deserialize(deviceInfo); + VerifyOrExit(err == CHIP_NO_ERROR, ReleaseDevice(device)); - // connected state before 'OnConnect' - mConState = kConnectionState_Connected; + device->Init(mSessionManager, mInetLayer); + } - mOnComplete.Response = onMessageReceived; - mOnError = onError; + *out_device = device; exit: - if (err != CHIP_NO_ERROR && mRendezvousSession != nullptr) - { - chip::Platform::Delete(mRendezvousSession); - mRendezvousSession = nullptr; - } - return err; } -CHIP_ERROR ChipDeviceController::ConnectDeviceWithoutSecurePairing(NodeId remoteDeviceId, const IPAddress & deviceAddr, - void * appReqState, NewConnectionHandler onConnected, - MessageReceiveHandler onMessageReceived, ErrorHandler onError, - uint16_t devicePort, Inet::InterfaceId interfaceId) +CHIP_ERROR DeviceController::GetDevice(NodeId deviceId, Device ** out_device) { - if (mTestSecurePairingSecret != nullptr) - { - chip::Platform::Delete(mTestSecurePairingSecret); - } - - mTestSecurePairingSecret = chip::Platform::New( - Optional::Value(remoteDeviceId), static_cast(0), static_cast(0)); - - mSecurePairingSession = mTestSecurePairingSecret; + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; + uint16_t index = 0; + char * buffer = nullptr; - mDeviceAddr = deviceAddr; - mRemoteDeviceId = Optional::Value(remoteDeviceId); - mDevicePort = devicePort; - mInterface = interfaceId; - mAppReqState = appReqState; - mOnNewConnection = onConnected; + VerifyOrExit(out_device != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + index = FindDeviceIndex(deviceId); - mConState = kConnectionState_Connected; - - mOnComplete.Response = onMessageReceived; - mOnError = onError; - - if (mOnNewConnection) + if (index < kNumMaxActiveDevices) { - mOnNewConnection(this, nullptr, mAppReqState); + device = &mActiveDevices[index]; } + else + { + VerifyOrExit(mStorageDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - return CHIP_NO_ERROR; -} + if (!mPairedDevicesInitialized) + { + constexpr uint16_t max_size = CHIP_MAX_SERIALIZED_SIZE_U64(kNumMaxPairedDevices); + buffer = static_cast(chip::Platform::MemoryAlloc(max_size)); + uint16_t size = max_size; -CHIP_ERROR ChipDeviceController::SetUdpListenPort(uint16_t listenPort) -{ - if (mState != kState_Initialized || mConState != kConnectionState_NotConnected) - return CHIP_ERROR_INCORRECT_STATE; - mListenPort = listenPort; - return CHIP_NO_ERROR; -} + VerifyOrExit(buffer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); -CHIP_ERROR ChipDeviceController::EstablishSecureSession() -{ - CHIP_ERROR err = CHIP_NO_ERROR; + PERSISTENT_KEY_OP(static_cast(0), kPairedDeviceListKeyPrefix, key, + err = mStorageDelegate->GetKeyValue(key, buffer, size)); + SuccessOrExit(err); + VerifyOrExit(size <= max_size, err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR); - VerifyOrExit(mSecurePairingSession != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + err = SetPairedDeviceList(buffer); + SuccessOrExit(err); + } - mSessionManager = chip::Platform::New>(); + VerifyOrExit(mPairedDevices.Contains(deviceId), err = CHIP_ERROR_NOT_CONNECTED); - err = mSessionManager->Init( - mLocalDeviceId, mSystemLayer, - Transport::UdpListenParameters(mInetLayer).SetAddressType(mDeviceAddr.Type()).SetListenPort(mListenPort)); - SuccessOrExit(err); + index = GetInactiveDeviceIndex(); + VerifyOrExit(index < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY); + device = &mActiveDevices[index]; - mSessionManager->SetDelegate(this); + { + SerializedDevice deviceInfo; + uint16_t size = sizeof(deviceInfo.inner); - err = mSessionManager->NewPairing( - Optional::Value(Transport::PeerAddress::UDP(mDeviceAddr, mDevicePort, mInterface)), - mSecurePairingSession); - SuccessOrExit(err); + PERSISTENT_KEY_OP(deviceId, kPairedDeviceKeyPrefix, key, + err = mStorageDelegate->GetKeyValue(key, Uint8::to_char(deviceInfo.inner), size)); + SuccessOrExit(err); + VerifyOrExit(size <= sizeof(deviceInfo.inner), err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR); - mConState = kConnectionState_SecureConnected; + err = device->Deserialize(deviceInfo); + VerifyOrExit(err == CHIP_NO_ERROR, ReleaseDevice(device)); - if (mDeviceAddr != IPAddress::Any) - { - SendCachedPackets(); - } // else wait for mdns discovery + device->Init(mSessionManager, mInetLayer); + } + } -exit: + *out_device = device; - if (err != CHIP_NO_ERROR) +exit: + if (buffer != nullptr) { - if (mSessionManager != nullptr) - { - chip::Platform::Delete(mSessionManager); - mSessionManager = nullptr; - } - mConState = kConnectionState_NotConnected; + chip::Platform::MemoryFree(buffer); } - return err; } -void ChipDeviceController::OnValue(const char * key, const char * value) +CHIP_ERROR DeviceController::ServiceEvents() { CHIP_ERROR err = CHIP_NO_ERROR; - NodeId peer = mRemoteDeviceId.Value(); - VerifyOrExit(key != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); - PERSISTENT_KEY_OP( - peer, kDeviceCredentialsKeyPrefix, expectedKey, if (strcmp(key, expectedKey) == 0) { - SecurePairingSessionSerialized serialized; - size_t length = 0; +#if CONFIG_DEVICE_LAYER + err = DeviceLayer::PlatformMgr().StartEventLoopTask(); + SuccessOrExit(err); +#endif // CONFIG_DEVICE_LAYER - VerifyOrExit(value != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - length = strlen(value) + 1; // account for the null termination - VerifyOrExit(length <= sizeof(serialized.inner), err = CHIP_ERROR_INVALID_ARGUMENT); - memmove(serialized.inner, value, length); - SuccessOrExit(mPairingSession.Deserialize(serialized)); +exit: + return err; +} - mSecurePairingSession = &mPairingSession; - }); +CHIP_ERROR DeviceController::ServiceEventSignal() +{ + CHIP_ERROR err = CHIP_NO_ERROR; - PERSISTENT_KEY_OP( - peer, kDeviceAddressKeyPrefix, expectedKey, if (strcmp(key, expectedKey) == 0) { - VerifyOrExit(value != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(IPAddress::FromString(value, mDeviceAddr), err = CHIP_ERROR_INVALID_ADDRESS); - }); + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); - if (mSecurePairingSession != nullptr && mDeviceAddr != IPAddress::Any) - { - SuccessOrExit(EstablishSecureSession()); - } +#if CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) + DeviceLayer::SystemLayer.WakeSelect(); +#else + err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif // CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) exit: - if (err != CHIP_NO_ERROR) - { - mConState = kConnectionState_NotConnected; - DiscardCachedPackets(); - } + return err; } -void ChipDeviceController::OnStatus(const char * key, Operation op, CHIP_ERROR err) {} +void DeviceController::OnNewConnection(Transport::PeerConnectionState * peerConnection, SecureSessionMgrBase * mgr) {} -CHIP_ERROR ChipDeviceController::TryEstablishingSecureSession(NodeId peer) +void DeviceController::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, + Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, + SecureSessionMgrBase * mgr) { CHIP_ERROR err = CHIP_NO_ERROR; + uint16_t index = 0; + NodeId peer; - if (mState != kState_Initialized || mSessionManager != nullptr || mConState == kConnectionState_SecureConnected) - { - ExitNow(err = CHIP_ERROR_INCORRECT_STATE); - } + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(header.GetSourceNodeId().HasValue(), err = CHIP_ERROR_INVALID_ARGUMENT); - if (mStorageDelegate != nullptr) + peer = header.GetSourceNodeId().Value(); + index = FindDeviceIndex(peer); + VerifyOrExit(index < kNumMaxActiveDevices, err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR); + + mActiveDevices[index].OnMessageReceived(header, payloadHeader, state, msgBuf, mgr); + +exit: + if (err != CHIP_NO_ERROR) { - mSecurePairingSession = nullptr; - mDeviceAddr = IPAddress::Any; - PERSISTENT_KEY_OP(peer, kDeviceCredentialsKeyPrefix, key, mStorageDelegate->GetKeyValue(key)); - PERSISTENT_KEY_OP(peer, kDeviceAddressKeyPrefix, key, mStorageDelegate->GetKeyValue(key)); - mConState = kConnectionState_SecureConnecting; + ChipLogError(Controller, "Failed to process received message: err %d", err); } - else + return; +} + +uint16_t DeviceController::GetInactiveDeviceIndex() +{ + uint16_t i = 0; + while (i < kNumMaxActiveDevices && mActiveDevices[i].IsActive()) + i++; + if (i < kNumMaxActiveDevices) { - ExitNow(err = EstablishSecureSession()); + mActiveDevices[i].SetActive(true); } -exit: + return i; +} - if (err != CHIP_NO_ERROR) - { - DiscardCachedPackets(); - } - return err; +void DeviceController::ReleaseDevice(Device * device) +{ + device->SetActive(false); } -CHIP_ERROR ChipDeviceController::ResumeSecureSession(NodeId peer) +void DeviceController::ReleaseDevice(uint16_t index) { - if (mConState == kConnectionState_SecureConnected) + if (index < kNumMaxActiveDevices) { - mConState = kConnectionState_Connected; + ReleaseDevice(&mActiveDevices[index]); } +} - if (mSessionManager != nullptr) +uint16_t DeviceController::FindDeviceIndex(NodeId id) +{ + uint16_t i = 0; + while (i < kNumMaxActiveDevices) { - chip::Platform::Delete(mSessionManager); - mSessionManager = nullptr; + if (mActiveDevices[i].IsActive() && mActiveDevices[i].GetDeviceId() == id) + { + return i; + } + i++; } + return i; +} - CHIP_ERROR err = TryEstablishingSecureSession(peer); - SuccessOrExit(err); +CHIP_ERROR DeviceController::SetPairedDeviceList(const char * serialized) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + size_t len = strlen(serialized) + 1; + uint16_t lenU16 = static_cast(len); + VerifyOrExit(CanCastTo(len), err = CHIP_ERROR_INVALID_ARGUMENT); + err = mPairedDevices.DeserializeBase64(serialized, lenU16); exit: - if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "ResumeSecureSession returning error %d\n", err); + ChipLogError(Controller, "Failed to recreate the device list\n"); } + else + { + mPairedDevicesInitialized = true; + } + return err; } -bool ChipDeviceController::IsConnected() const -{ - return mState == kState_Initialized && - (mConState == kConnectionState_Connected || mConState == kConnectionState_SecureConnected); -} +void DeviceController::OnValue(const char * key, const char * value) {} -bool ChipDeviceController::IsSecurelyConnected() const +void DeviceController::OnStatus(const char * key, Operation op, CHIP_ERROR err) {} + +DeviceCommissioner::DeviceCommissioner() { - return mState == kState_Initialized && mConState == kConnectionState_SecureConnected; + mPairingDelegate = nullptr; + mRendezvousSession = nullptr; + mDeviceBeingPaired = kNumMaxActiveDevices; + mPairedDevicesUpdated = false; } -bool ChipDeviceController::GetIpAddress(Inet::IPAddress & addr) const +CHIP_ERROR DeviceCommissioner::Init(NodeId localDeviceId, PersistentStorageDelegate * storageDelegate, + DevicePairingDelegate * pairingDelegate, System::Layer * systemLayer, + Inet::InetLayer * inetLayer) { - if (IsConnected()) - addr = mDeviceAddr; - return IsConnected(); + CHIP_ERROR err = DeviceController::Init(localDeviceId, storageDelegate, systemLayer, inetLayer); + SuccessOrExit(err); + + mPairingDelegate = pairingDelegate; + +exit: + return err; } -CHIP_ERROR ChipDeviceController::DisconnectDevice() +CHIP_ERROR DeviceCommissioner::Shutdown() { CHIP_ERROR err = CHIP_NO_ERROR; - if (!IsConnected()) - { - return CHIP_ERROR_INCORRECT_STATE; - } + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); - if (mSessionManager != nullptr) - { - chip::Platform::Delete(mSessionManager); - mSessionManager = nullptr; - } + ChipLogDetail(Controller, "Shutting down the commissioner"); + + PersistDeviceList(); if (mRendezvousSession != nullptr) { @@ -460,273 +438,278 @@ CHIP_ERROR ChipDeviceController::DisconnectDevice() mRendezvousSession = nullptr; } - mConState = kConnectionState_NotConnected; - return err; -} - -CHIP_ERROR ChipDeviceController::CachePacket(System::PacketBuffer * buffer) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - VerifyOrExit(mNumCachedPackets < kPacketCacheMaxSize, err = CHIP_ERROR_INTERNAL); - mCachedPackets[mNumCachedPackets++] = buffer; + DeviceController::Shutdown(); exit: return err; } -CHIP_ERROR ChipDeviceController::SendCachedPackets() +CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParameters & params, uint16_t remotePort, + Inet::InterfaceId interfaceId) { - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; - VerifyOrExit(IsSecurelyConnected(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mDeviceBeingPaired == kNumMaxActiveDevices, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mStorageDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - for (uint16_t i = 0; i < mNumCachedPackets; i++) +#if CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE + if (!params.HasBleLayer()) { - err = mSessionManager->SendMessage(mRemoteDeviceId.Value(), mCachedPackets[i]); - ChipLogDetail(Controller, "SendMessage returned %d", err); + params.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer()); } +#endif // CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE - mNumCachedPackets = 0; - CHIP_ZERO_AT(mCachedPackets); + mDeviceBeingPaired = GetInactiveDeviceIndex(); + VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY); + device = &mActiveDevices[mDeviceBeingPaired]; -exit: - return err; -} + mRendezvousSession = chip::Platform::New(this); + VerifyOrExit(mRendezvousSession != nullptr, err = CHIP_ERROR_NO_MEMORY); + err = mRendezvousSession->Init(params.SetLocalNodeId(mLocalDeviceId)); + SuccessOrExit(err); -void ChipDeviceController::DiscardCachedPackets() -{ - for (uint16_t i = 0; i < mNumCachedPackets; i++) + device->Init(mSessionManager, mInetLayer, remoteDeviceId, remotePort, interfaceId); + +exit: + if (err != CHIP_NO_ERROR) { - PacketBuffer::Free(mCachedPackets[i]); + if (mRendezvousSession != nullptr) + { + chip::Platform::Delete(mRendezvousSession); + mRendezvousSession = nullptr; + } + + if (device != nullptr) + { + ReleaseDevice(device); + mDeviceBeingPaired = kNumMaxActiveDevices; + } } - mNumCachedPackets = 0; - CHIP_ZERO_AT(mCachedPackets); + return err; } -CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer, NodeId peerDevice) +CHIP_ERROR DeviceCommissioner::PairTestDeviceWithoutSecurity(NodeId remoteDeviceId, const Inet::IPAddress & deviceAddr, + SerializedDevice & serialized, uint16_t remotePort, + Inet::InterfaceId interfaceId) { - CHIP_ERROR err = CHIP_NO_ERROR; - bool trySessionResumption = true; + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; - VerifyOrExit(buffer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); + SecurePairingUsingTestSecret * testSecurePairingSecret = nullptr; - mAppReqState = appReqState; + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mDeviceBeingPaired == kNumMaxActiveDevices, err = CHIP_ERROR_INCORRECT_STATE); - if (peerDevice != kUndefinedNodeId) - { - mRemoteDeviceId = Optional::Value(peerDevice); - } - VerifyOrExit(mRemoteDeviceId.HasValue(), err = CHIP_ERROR_INCORRECT_STATE); + testSecurePairingSecret = chip::Platform::New(Optional::Value(remoteDeviceId), + static_cast(0), static_cast(0)); + VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY); - // If there is no secure connection to the device, try establishing it - if (!IsSecurelyConnected()) - { - err = TryEstablishingSecureSession(mRemoteDeviceId.Value()); - SuccessOrExit(err); + mDeviceBeingPaired = GetInactiveDeviceIndex(); + VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY); + device = &mActiveDevices[mDeviceBeingPaired]; - trySessionResumption = false; + testSecurePairingSecret->ToSerializable(device->GetPairing()); - if (mDeviceAddr == IPAddress::Any || mConState == kConnectionState_SecureConnecting) - { - // Cache the packet while connection is being established - ExitNow(err = CachePacket(buffer)); - } - } + device->Init(mSessionManager, mInetLayer, remoteDeviceId, remotePort, interfaceId); + + device->SetAddress(deviceAddr); - // Hold on to the buffer, in case of session resumption and resend is needed - buffer->AddRef(); + device->Serialize(serialized); - err = mSessionManager->SendMessage(mRemoteDeviceId.Value(), buffer); - ChipLogDetail(Controller, "SendMessage returned %d", err); + OnRendezvousComplete(); - // The send could fail due to network timeouts (e.g. broken pipe) - // Try sesion resumption if needed - if (err != CHIP_NO_ERROR && trySessionResumption) +exit: + if (testSecurePairingSecret != nullptr) { - err = ResumeSecureSession(mRemoteDeviceId.Value()); - // If session resumption failed, let's free the extra reference to - // the buffer. If not, SendMessage would free it. - VerifyOrExit(err == CHIP_NO_ERROR, PacketBuffer::Free(buffer)); + chip::Platform::Delete(testSecurePairingSecret); + } - if (mConState == kConnectionState_SecureConnecting) + if (err != CHIP_NO_ERROR) + { + if (device != nullptr) { - // Cache the packet while connection is being established - ExitNow(err = CachePacket(buffer)); + ReleaseDevice(device); + mDeviceBeingPaired = kNumMaxActiveDevices; } - - err = mSessionManager->SendMessage(mRemoteDeviceId.Value(), buffer); - SuccessOrExit(err); - } - else - { - // Free the extra reference to the buffer - PacketBuffer::Free(buffer); } -exit: - return err; } - -CHIP_ERROR ChipDeviceController::ServiceEvents() +CHIP_ERROR DeviceCommissioner::StopPairing(NodeId remoteDeviceId) { - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; - VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_INCORRECT_STATE); -#if CONFIG_DEVICE_LAYER - err = DeviceLayer::PlatformMgr().StartEventLoopTask(); - SuccessOrExit(err); -#endif // CONFIG_DEVICE_LAYER - -exit: - return err; -} - -CHIP_ERROR ChipDeviceController::ServiceEventSignal() -{ - CHIP_ERROR err = CHIP_NO_ERROR; + device = &mActiveDevices[mDeviceBeingPaired]; + VerifyOrExit(device->GetDeviceId() == remoteDeviceId, err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR); - VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); + if (mRendezvousSession != nullptr) + { + chip::Platform::Delete(mRendezvousSession); + mRendezvousSession = nullptr; + } -#if CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) - DeviceLayer::SystemLayer.WakeSelect(); -#else - err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif // CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) + ReleaseDevice(device); + mDeviceBeingPaired = kNumMaxActiveDevices; exit: return err; } -CHIP_ERROR ChipDeviceController::SetDevicePairingDelegate(DevicePairingDelegate * pairingDelegate) +CHIP_ERROR DeviceCommissioner::UnpairDevice(NodeId remoteDeviceId) { - mPairingDelegate = pairingDelegate; - return CHIP_NO_ERROR; -} + // TODO: Send unpairing message to the remote device. -void ChipDeviceController::ClearRequestState() -{ - if (mCurReqMsg != nullptr) + if (mStorageDelegate != nullptr) { - PacketBuffer::Free(mCurReqMsg); - mCurReqMsg = nullptr; + PERSISTENT_KEY_OP(remoteDeviceId, kPairedDeviceKeyPrefix, key, mStorageDelegate->DeleteKeyValue(key)); + mPairedDevices.Remove(remoteDeviceId); + mPairedDevicesUpdated = true; } -} -void ChipDeviceController::OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) {} + return CHIP_NO_ERROR; +} -void ChipDeviceController::OnAddressResolved(CHIP_ERROR error, NodeId nodeId, SecureSessionMgrBase * mgr) +void DeviceCommissioner::RendezvousCleanup(CHIP_ERROR status) { - if (error == CHIP_NO_ERROR && nodeId == mSecurePairingSession->GetPeerNodeId() && mDeviceAddr == IPAddress::Any) + if (mRendezvousSession != nullptr) { - SendCachedPackets(); + chip::Platform::Delete(mRendezvousSession); + mRendezvousSession = nullptr; } -} -void ChipDeviceController::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, - Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, - SecureSessionMgrBase * mgr) -{ - if (header.GetSourceNodeId().HasValue()) + if (mPairingDelegate != nullptr) { - if (!mRemoteDeviceId.HasValue()) - { - ChipLogDetail(Controller, "Learned remote device id"); - mRemoteDeviceId = header.GetSourceNodeId(); - } - else if (mRemoteDeviceId != header.GetSourceNodeId()) - { - ChipLogError(Controller, "Received message from an unexpected source node id."); - } + mPairingDelegate->OnPairingComplete(status); } - if (IsSecurelyConnected() && mOnComplete.Response != nullptr) + + if (mDeviceBeingPaired != kNumMaxActiveDevices) { - mOnComplete.Response(this, mAppReqState, msgBuf); + // Let's release the device that's being paired. + // If pairing was successful, its information is + // already persisted. The application will use GetDevice() + // method to get access to the device, which will fetch + // the device information from the persistent storage. + DeviceController::ReleaseDevice(mDeviceBeingPaired); + mDeviceBeingPaired = kNumMaxActiveDevices; } } -void ChipDeviceController::OnRendezvousError(CHIP_ERROR err) +void DeviceCommissioner::OnRendezvousError(CHIP_ERROR err) { - if (mRendezvousSession != nullptr) + RendezvousCleanup(err); +} + +void DeviceCommissioner::OnRendezvousComplete() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + Device * device = nullptr; + + VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_INVALID_DEVICE_DESCRIPTOR); + device = &mActiveDevices[mDeviceBeingPaired]; + mPairedDevices.Insert(device->GetDeviceId()); + mPairedDevicesUpdated = true; + + // mStorageDelegate would not be null for a typical pairing scenario, as Pair() + // requires a valid storage delegate. However, test pairing usecase, that's used + // mainly by test applications, do not require a storage delegate. This is to + // reduce overheads on these tests. + // Let's make sure the delegate object is available before calling into it. + if (mStorageDelegate != nullptr) { - chip::Platform::Delete(mRendezvousSession); - mRendezvousSession = nullptr; + SerializedDevice serialized; + device->Serialize(serialized); + PERSISTENT_KEY_OP(device->GetDeviceId(), kPairedDeviceKeyPrefix, key, + mStorageDelegate->SetKeyValue(key, Uint8::to_const_char(serialized.inner))); } - if (mPairingDelegate != nullptr) +exit: + if (err == CHIP_NO_ERROR) { - mPairingDelegate->OnPairingComplete(err); + RendezvousCleanup(CHIP_NO_ERROR); + } + else + { + OnRendezvousError(err); } } -void ChipDeviceController::OnRendezvousComplete() -{ - OnRendezvousError(CHIP_NO_ERROR); -} - -void ChipDeviceController::OnRendezvousStatusUpdate(RendezvousSessionDelegate::Status status, CHIP_ERROR err) +void DeviceCommissioner::OnRendezvousStatusUpdate(RendezvousSessionDelegate::Status status, CHIP_ERROR err) { - if (mOnError != nullptr && err != CHIP_NO_ERROR) + Device * device = nullptr; + if (mDeviceBeingPaired >= kNumMaxActiveDevices) { - mOnError(this, mAppReqState, err, nullptr); + ExitNow(); } + device = &mActiveDevices[mDeviceBeingPaired]; switch (status) { case RendezvousSessionDelegate::SecurePairingSuccess: - ChipLogProgress(Controller, "Remote device completed SPAKE2+ handshake\n"); - mPairingSession = mRendezvousSession->GetPairingSession(); - mSecurePairingSession = &mPairingSession; - - if (mOnNewConnection) - { - ChipLogProgress(Controller, "Will Call on mOnNewConnection(%p)\n", mOnNewConnection); - mOnNewConnection(this, nullptr, mAppReqState); - } + ChipLogDetail(Controller, "Remote device completed SPAKE2+ handshake\n"); + mRendezvousSession->GetPairingSession().ToSerializable(device->GetPairing()); if (mPairingDelegate != nullptr) { mPairingDelegate->OnNetworkCredentialsRequested(mRendezvousSession); } + break; - if (mStorageDelegate != nullptr) - { - SecurePairingSessionSerialized serialized; - CHIP_ERROR err = mSecurePairingSession->Serialize(serialized); - if (err == CHIP_NO_ERROR) - { - PERSISTENT_KEY_OP(mSecurePairingSession->GetPeerNodeId(), kDeviceCredentialsKeyPrefix, key, - mStorageDelegate->SetKeyValue(key, Uint8::to_const_char(serialized.inner))); - } - } + case RendezvousSessionDelegate::SecurePairingFailed: + ChipLogDetail(Controller, "Remote device failed in SPAKE2+ handshake\n"); break; case RendezvousSessionDelegate::NetworkProvisioningSuccess: - ChipLogDetail(Controller, "Remote device was assigned an ip address\n"); - mDeviceAddr = mRendezvousSession->GetIPAddress(); - if (mStorageDelegate != nullptr) - { - char addrStr[INET6_ADDRSTRLEN]; - mDeviceAddr.ToString(addrStr, INET6_ADDRSTRLEN); - PERSISTENT_KEY_OP(mRendezvousSession->GetPairingSession().GetPeerNodeId(), kDeviceAddressKeyPrefix, key, - mStorageDelegate->SetKeyValue(key, addrStr)); - } + device->SetAddress(mRendezvousSession->GetIPAddress()); + break; + + case RendezvousSessionDelegate::NetworkProvisioningFailed: + ChipLogDetail(Controller, "Remote device failed in network provisioning\n"); break; default: break; }; - +exit: if (mPairingDelegate != nullptr) { mPairingDelegate->OnStatusUpdate(status); } } -} // namespace DeviceController +void DeviceCommissioner::PersistDeviceList() +{ + if (mStorageDelegate != nullptr && mPairedDevicesUpdated) + { + constexpr uint16_t size = CHIP_MAX_SERIALIZED_SIZE_U64(kNumMaxPairedDevices); + char * serialized = static_cast(chip::Platform::MemoryAlloc(size)); + uint16_t requiredSize = size; + if (serialized != nullptr) + { + const char * value = mPairedDevices.SerializeBase64(serialized, requiredSize); + if (value != nullptr && requiredSize <= size) + { + PERSISTENT_KEY_OP(static_cast(0), kPairedDeviceListKeyPrefix, key, + mStorageDelegate->SetKeyValue(key, value)); + mPairedDevicesUpdated = false; + } + chip::Platform::MemoryFree(serialized); + } + } +} + +void DeviceCommissioner::ReleaseDevice(Device * device) +{ + PersistDeviceList(); + DeviceController::ReleaseDevice(device); +} + +} // namespace Controller } // namespace chip diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index a115288e37752c..1e7ec69befa671 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -28,28 +28,23 @@ #pragma once +#include #include #include #include #include +#include #include #include #include #include namespace chip { -namespace DeviceController { -constexpr uint16_t kPacketCacheMaxSize = 16; +namespace Controller { -class ChipDeviceController; - -typedef void (*NewConnectionHandler)(ChipDeviceController * deviceController, Transport::PeerConnectionState * state, - void * appReqState); -typedef void (*CompleteHandler)(ChipDeviceController * deviceController, void * appReqState); -typedef void (*ErrorHandler)(ChipDeviceController * deviceController, void * appReqState, CHIP_ERROR err, - const Inet::IPPacketInfo * pktInfo); -typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload); +constexpr uint16_t kNumMaxActiveDevices = 64; +constexpr uint16_t kNumMaxPairedDevices = 128; class DLL_EXPORT DevicePairingDelegate { @@ -100,117 +95,57 @@ class DLL_EXPORT DevicePairingDelegate virtual void OnPairingDeleted(CHIP_ERROR error) {} }; -class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, - public RendezvousSessionDelegate, - public PersistentStorageResultDelegate +/** + * @brief + * Controller applications can use this class to communicate with already paired CHIP devices. The + * application is required to provide access to the persistent storage, where the paired device information + * is stored. This object of this class can be initialized with the data from the storage (List of devices, + * and device pairing information for individual devices). Alternatively, this class can retrieve the + * relevant information when the application tries to communicate with the device + */ +class DLL_EXPORT DeviceController : public SecureSessionMgrDelegate, public PersistentStorageResultDelegate { - friend class ChipDeviceControllerCallback; - public: - ChipDeviceController(); - ~ChipDeviceController(); - - void * AppState; + DeviceController(); + virtual ~DeviceController() {} /** * Init function to be used when there exists a device layer that takes care of initializing * System::Layer and InetLayer. */ - CHIP_ERROR Init(NodeId localDeviceId, DevicePairingDelegate * pairingDelegate = nullptr, - PersistentStorageDelegate * storageDelegate = nullptr); - /** - * Init function to be used when already-initialized System::Layer and InetLayer are available. - */ - CHIP_ERROR Init(NodeId localDeviceId, System::Layer * systemLayer, Inet::InetLayer * inetLayer, - DevicePairingDelegate * pairingDelegate = nullptr, PersistentStorageDelegate * storageDelegate = nullptr); - CHIP_ERROR Shutdown(); + CHIP_ERROR Init(NodeId localDeviceId, PersistentStorageDelegate * storageDelegate = nullptr, + System::Layer * systemLayer = nullptr, Inet::InetLayer * inetLayer = nullptr); - CHIP_ERROR SetUdpListenPort(uint16_t listenPort); + virtual CHIP_ERROR Shutdown(); - // ----- Connection Management ----- /** * @brief - * Connect to a CHIP device with the provided Rendezvous connection parameters + * This function deserializes the provided deviceInfo object, and initializes and outputs the + * corresponding Device object. The lifetime of the output object is tied to that of the DeviceController + * object. The caller must not use the Device object If they free the DeviceController object, or + * after they call ReleaseDevice() on the returned device object. * - * @param[in] remoteDeviceId The remote device Id. - * @param[in] params The Rendezvous connection parameters - * @param[in] appReqState Application specific context to be passed back when a message is received or on error - * @param[in] onConnected Callback for when the connection is established - * @param[in] onMessageReceived Callback for when a message is received - * @param[in] onError Callback for when an error occurs - * @param[in] devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT - * @param[in] interfaceId [Optional] The interface indicator to use + * @param[in] deviceId Node ID for the CHIP device + * @param[in] deviceInfo Serialized device info for the device + * @param[out] device The output device object * - * @return CHIP_ERROR The connection status + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. */ - CHIP_ERROR ConnectDevice(NodeId remoteDeviceId, RendezvousParameters & params, void * appReqState, - NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, ErrorHandler onError, - uint16_t devicePort = CHIP_PORT, Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); + CHIP_ERROR GetDevice(NodeId deviceId, const SerializedDevice & deviceInfo, Device ** device); /** * @brief - * Connect to a CHIP device at a given address and an optional port. This is a test only API - * that bypasses Rendezvous and Secure Pairing process. + * This function is similar to the other GetDevice object, except it reads the serialized object from + * the persistent storage. * - * @param[in] remoteDeviceId The remote device Id. - * @param[in] deviceAddr The IPAddress of the requested Device - * @param[in] appReqState Application specific context to be passed back when a message is received or on error - * @param[in] onConnected Callback for when the connection is established - * @param[in] onMessageReceived Callback for when a message is received - * @param[in] onError Callback for when an error occurs - * @param[in] devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT - * @param[in] interfaceId [Optional] The interface indicator to use - * @return CHIP_ERROR The connection status - */ - [[deprecated("Available until Rendezvous is implemented")]] CHIP_ERROR - ConnectDeviceWithoutSecurePairing(NodeId remoteDeviceId, const Inet::IPAddress & deviceAddr, void * appReqState, - NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, - ErrorHandler onError, uint16_t devicePort = CHIP_PORT, - Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); - - /** - * @brief - * Disconnect from a connected device - * - * @return CHIP_ERROR If the device was disconnected successfully - */ - CHIP_ERROR DisconnectDevice(); - - /** - * @brief - * Check if there's an active connection + * @param[in] deviceId Node ID for the CHIP device + * @param[out] device The output device object * - * @return bool If there is an active connection + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code. */ - bool IsConnected() const; + CHIP_ERROR GetDevice(NodeId deviceId, Device ** device); - /** - * @brief - * Check if the connection is active and security context is established - * - * @return bool If the connection is active and security context is established - */ - bool IsSecurelyConnected() const; - - /** - * @brief - * Get IP Address of the peer if the connection is active - * - * @return bool If IP Address was returned - */ - bool GetIpAddress(Inet::IPAddress & addr) const; - - // ----- Messaging ----- - /** - * @brief - * Send a message to a connected CHIP device - * - * @param[in] appReqState Application specific context to be passed back when a message is received or on error - * @param[in] buffer The Data Buffer to trasmit to the device - * @param[in] peerDevice Device ID of the peer device - * @return CHIP_ERROR The return status - */ - CHIP_ERROR SendMessage(void * appReqState, System::PacketBuffer * buffer, NodeId peerDevice = kUndefinedNodeId); + virtual void ReleaseDevice(Device * device); // ----- IO ----- /** @@ -220,14 +155,6 @@ class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, */ CHIP_ERROR ServiceEvents(); - // ----- Pairing ----- - /** - * @brief - * Set device pairing delegate after init, pass nullptr remove device delegate. - * @return CHIP_ERROR The return status - */ - CHIP_ERROR SetDevicePairingDelegate(DevicePairingDelegate * pairingDelegate); - /** * @brief * Allow the CHIP Stack to process any pending events @@ -236,86 +163,142 @@ class DLL_EXPORT ChipDeviceController : public SecureSessionMgrDelegate, */ CHIP_ERROR ServiceEventSignal(); +protected: + enum class State + { + NotInitialized, + Initialized + }; + + State mState; + + /* A list of device objects that can be used for communicating with corresponding + CHIP devices. The list does not contain all the paired devices, but only the ones + which the controller application is currently accessing. + */ + Device mActiveDevices[kNumMaxActiveDevices]; + + SerializableU64Set mPairedDevices; + bool mPairedDevicesInitialized; + + NodeId mLocalDeviceId; + SecureSessionMgr * mSessionManager; + PersistentStorageDelegate * mStorageDelegate; + Inet::InetLayer * mInetLayer; + + uint16_t GetInactiveDeviceIndex(); + uint16_t FindDeviceIndex(NodeId id); + void ReleaseDevice(uint16_t index); + CHIP_ERROR SetPairedDeviceList(const char * pairedDeviceSerializedSet); + +private: + //////////// SecureSessionMgrDelegate Implementation /////////////// void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, Transport::PeerConnectionState * state, System::PacketBuffer * msgBuf, SecureSessionMgrBase * mgr) override; void OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) override; - void OnAddressResolved(CHIP_ERROR error, NodeId nodeId, SecureSessionMgrBase * mgr) override; - - //////////// RendezvousSessionDelegate Implementation /////////////// - void OnRendezvousError(CHIP_ERROR err) override; - void OnRendezvousComplete() override; - void OnRendezvousStatusUpdate(RendezvousSessionDelegate::Status status, CHIP_ERROR err) override; - //////////// PersistentStorageResultDelegate Implementation /////////////// void OnValue(const char * key, const char * value) override; void OnStatus(const char * key, Operation op, CHIP_ERROR err) override; -private: - enum - { - kState_NotInitialized = 0, - kState_Initialized = 1 - } mState; + System::Layer * mSystemLayer; +}; - enum ConnectionState - { - kConnectionState_NotConnected = 0, - kConnectionState_Connected = 1, - kConnectionState_SecureConnecting = 2, - kConnectionState_SecureConnected = 3, - }; +/** + * @brief + * The commissioner applications can use this class to pair new/unpaired CHIP devices. The application is + * required to provide write access to the persistent storage, where the paired device information + * will be stored. + */ +class DLL_EXPORT DeviceCommissioner : public DeviceController, public RendezvousSessionDelegate +{ +public: + DeviceCommissioner(); + ~DeviceCommissioner() {} - System::Layer * mSystemLayer; - Inet::InetLayer * mInetLayer; + /** + * Init function to be used when there exists a device layer that takes care of initializing + * System::Layer and InetLayer. + */ + CHIP_ERROR Init(NodeId localDeviceId, PersistentStorageDelegate * storageDelegate = nullptr, + DevicePairingDelegate * pairingDelegate = nullptr, System::Layer * systemLayer = nullptr, + Inet::InetLayer * inetLayer = nullptr); - SecureSessionMgr * mSessionManager; - RendezvousSession * mRendezvousSession; + void SetDevicePairingDelegate(DevicePairingDelegate * pairingDelegate) { mPairingDelegate = pairingDelegate; } - ConnectionState mConState; - void * mAppReqState; + CHIP_ERROR Shutdown() override; - union - { - CompleteHandler General; - MessageReceiveHandler Response; - } mOnComplete; + // ----- Connection Management ----- + /** + * @brief + * Pair a CHIP device with the provided Rendezvous connection parameters. + * 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] params The Rendezvous connection parameters + * @param[in] devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT + * @param[in] interfaceId [Optional] The local inet interface to use to communicate with the device. + * + * @return CHIP_ERROR The connection status + */ + CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & params, uint16_t devicePort = CHIP_PORT, + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); - ErrorHandler mOnError; - NewConnectionHandler mOnNewConnection; - System::PacketBuffer * mCurReqMsg; + [[deprecated("Available until Rendezvous is implemented")]] CHIP_ERROR + PairTestDeviceWithoutSecurity(NodeId remoteDeviceId, const Inet::IPAddress & deviceAddr, SerializedDevice & serialized, + uint16_t devicePort = CHIP_PORT, Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); - NodeId mLocalDeviceId; - uint16_t mListenPort; - Inet::IPAddress mDeviceAddr; - uint16_t mDevicePort; - Inet::InterfaceId mInterface; - Optional mRemoteDeviceId; + /** + * @brief + * This function stops a pairing process that's in progress. It does not delete the pairing of a previously + * paired device. + * + * @param[in] remoteDeviceId The remote device Id. + * + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error + */ + CHIP_ERROR StopPairing(NodeId remoteDeviceId); - SecurePairingSession mPairingSession; - SecurePairingUsingTestSecret * mTestSecurePairingSecret = nullptr; + /** + * @brief + * Remove pairing for a paired device. If the device is currently being paired, it'll stop the pairing process. + * + * @param[in] remoteDeviceId The remote device Id. + * + * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error + */ + CHIP_ERROR UnpairDevice(NodeId remoteDeviceId); - SecurePairingSession * mSecurePairingSession = nullptr; + //////////// RendezvousSessionDelegate Implementation /////////////// + void OnRendezvousError(CHIP_ERROR err) override; + void OnRendezvousComplete() override; + void OnRendezvousStatusUpdate(RendezvousSessionDelegate::Status status, CHIP_ERROR err) override; - DevicePairingDelegate * mPairingDelegate = nullptr; + void RendezvousCleanup(CHIP_ERROR status); - PersistentStorageDelegate * mStorageDelegate; + void ReleaseDevice(Device * device) override; - System::PacketBuffer * mCachedPackets[kPacketCacheMaxSize]; - uint16_t mNumCachedPackets; +private: + DevicePairingDelegate * mPairingDelegate; + RendezvousSession * mRendezvousSession; - void ClearRequestState(); - void ClearOpState(); + /* This field is an index in mActiveDevices list. The object at this index in the list + contains the device object that's tracking the state of the device that's being paired. + If no device is currently being paired, this value will be kNumMaxPairedDevices. */ + uint16_t mDeviceBeingPaired; - CHIP_ERROR EstablishSecureSession(); - CHIP_ERROR TryEstablishingSecureSession(NodeId peer); - CHIP_ERROR ResumeSecureSession(NodeId peer); + /* This field is true when device pairing information changes, e.g. a new device is paired, or + the pairing for a device is removed. The DeviceCommissioner uses this to decide when to + persist the device list */ + bool mPairedDevicesUpdated; - CHIP_ERROR CachePacket(System::PacketBuffer * buffer); - CHIP_ERROR SendCachedPackets(); - void DiscardCachedPackets(); + void PersistDeviceList(); }; -} // namespace DeviceController +} // namespace Controller } // namespace chip diff --git a/src/controller/CHIPDeviceController_deprecated.cpp b/src/controller/CHIPDeviceController_deprecated.cpp new file mode 100644 index 00000000000000..eaaa237488b251 --- /dev/null +++ b/src/controller/CHIPDeviceController_deprecated.cpp @@ -0,0 +1,239 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-2017 Nest Labs, Inc. + * 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 CHIP Device Controller, a common class + * that implements discovery, pairing and provisioning of CHIP + * devices. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +// module header, comes first +#include + +#if CONFIG_DEVICE_LAYER +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace chip::Inet; +using namespace chip::System; +using namespace chip::Controller; + +namespace chip { +namespace DeviceController { + +using namespace chip::Encoding; + +ChipDeviceController::ChipDeviceController() +{ + mState = kState_NotInitialized; + AppState = nullptr; + mCurReqMsg = nullptr; + mOnError = nullptr; + mOnNewConnection = nullptr; + mListenPort = CHIP_PORT; + mLocalDeviceId = kUndefinedNodeId; + mRemoteDeviceId = kUndefinedNodeId; + mDevice = nullptr; + mPairingWithoutSecurity = false; + CHIP_ZERO_AT(mOnComplete); +} + +ChipDeviceController::~ChipDeviceController() {} + +CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, DevicePairingDelegate * pairingDelegate, + PersistentStorageDelegate * storageDelegate) +{ + return mCommissioner.Init(localNodeId, storageDelegate, pairingDelegate); +} + +CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, System::Layer * systemLayer, InetLayer * inetLayer, + DevicePairingDelegate * pairingDelegate, PersistentStorageDelegate * storageDelegate) +{ + return mCommissioner.Init(localNodeId, storageDelegate, pairingDelegate, systemLayer, inetLayer); +} + +CHIP_ERROR ChipDeviceController::Shutdown() +{ + return mCommissioner.Shutdown(); +} + +CHIP_ERROR ChipDeviceController::ConnectDevice(NodeId remoteDeviceId, RendezvousParameters & params, void * appReqState, + NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, + ErrorHandler onError, uint16_t devicePort, Inet::InterfaceId interfaceId) +{ + CHIP_ERROR err = mCommissioner.PairDevice(remoteDeviceId, params, devicePort, interfaceId); + SuccessOrExit(err); + + mRemoteDeviceId = remoteDeviceId; + mAppReqState = appReqState; + mOnNewConnection = onConnected; + + mOnComplete.Response = onMessageReceived; + mOnError = onError; + +exit: + return err; +} + +CHIP_ERROR ChipDeviceController::ConnectDeviceWithoutSecurePairing(NodeId remoteDeviceId, const IPAddress & deviceAddr, + void * appReqState, NewConnectionHandler onConnected, + MessageReceiveHandler onMessageReceived, ErrorHandler onError, + uint16_t devicePort, Inet::InterfaceId interfaceId) +{ + CHIP_ERROR err = + mCommissioner.PairTestDeviceWithoutSecurity(remoteDeviceId, deviceAddr, mSerializedTestDevice, devicePort, interfaceId); + SuccessOrExit(err); + + mPairingWithoutSecurity = true; + + mRemoteDeviceId = remoteDeviceId; + mAppReqState = appReqState; + mOnNewConnection = onConnected; + + mOnComplete.Response = onMessageReceived; + mOnError = onError; + + if (mOnNewConnection) + { + mOnNewConnection(this, nullptr, mAppReqState); + } + +exit: + return err; +} + +CHIP_ERROR ChipDeviceController::SetUdpListenPort(uint16_t listenPort) +{ + if (mState != kState_Initialized) + return CHIP_ERROR_INCORRECT_STATE; + mListenPort = listenPort; + return CHIP_NO_ERROR; +} + +CHIP_ERROR ChipDeviceController::ServiceEvents() +{ + return mCommissioner.ServiceEvents(); +} + +CHIP_ERROR ChipDeviceController::ServiceEventSignal() +{ + return mCommissioner.ServiceEventSignal(); +} + +bool ChipDeviceController::IsConnected() const +{ + return mState == kState_Initialized; +} + +bool ChipDeviceController::GetIpAddress(Inet::IPAddress & addr) const +{ + if (IsConnected() && mDevice != nullptr) + return mDevice->GetIpAddress(addr); + + return false; +} + +CHIP_ERROR ChipDeviceController::DisconnectDevice() +{ + if (mDevice != nullptr) + { + mCommissioner.ReleaseDevice(mDevice); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer, NodeId peerDevice) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(buffer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + + mAppReqState = appReqState; + + if (peerDevice != kUndefinedNodeId) + { + mRemoteDeviceId = peerDevice; + } + VerifyOrExit(mRemoteDeviceId != kUndefinedNodeId, err = CHIP_ERROR_INCORRECT_STATE); + + if (mDevice == nullptr) + { + if (mPairingWithoutSecurity) + { + err = mCommissioner.GetDevice(mRemoteDeviceId, mSerializedTestDevice, &mDevice); + } + else + { + err = mCommissioner.GetDevice(mRemoteDeviceId, &mDevice); + } + SuccessOrExit(err); + } + + VerifyOrExit(mDevice != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + mDevice->SetDelegate(this); + + err = mDevice->SendMessage(buffer); + +exit: + + return err; +} + +CHIP_ERROR ChipDeviceController::SetDevicePairingDelegate(DevicePairingDelegate * pairingDelegate) +{ + mCommissioner.SetDevicePairingDelegate(pairingDelegate); + return CHIP_NO_ERROR; +} + +void ChipDeviceController::OnMessage(System::PacketBuffer * msgBuf) +{ + if (mOnComplete.Response != nullptr) + { + mOnComplete.Response(this, mAppReqState, msgBuf); + } +} + +} // namespace DeviceController +} // namespace chip diff --git a/src/controller/CHIPDeviceController_deprecated.h b/src/controller/CHIPDeviceController_deprecated.h new file mode 100644 index 00000000000000..d1bf8369893327 --- /dev/null +++ b/src/controller/CHIPDeviceController_deprecated.h @@ -0,0 +1,220 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2013-2017 Nest Labs, Inc. + * 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 CHIP Device Controller, a common class + * that implements connecting and messaging and will later + * be expanded to support discovery, pairing and + * provisioning of CHIP devices. + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace DeviceController { + +constexpr uint16_t kPacketCacheMaxSize = 16; + +class ChipDeviceController; + +typedef void (*NewConnectionHandler)(ChipDeviceController * deviceController, Transport::PeerConnectionState * state, + void * appReqState); +typedef void (*CompleteHandler)(ChipDeviceController * deviceController, void * appReqState); +typedef void (*ErrorHandler)(ChipDeviceController * deviceController, void * appReqState, CHIP_ERROR err, + const Inet::IPPacketInfo * pktInfo); +typedef void (*MessageReceiveHandler)(ChipDeviceController * deviceController, void * appReqState, System::PacketBuffer * payload); + +class DLL_EXPORT ChipDeviceController : public Controller::DeviceStatusDelegate +{ + friend class ChipDeviceControllerCallback; + +public: + ChipDeviceController(); + ~ChipDeviceController(); + + void * AppState; + + /** + * Init function to be used when there exists a device layer that takes care of initializing + * System::Layer and InetLayer. + */ + CHIP_ERROR Init(NodeId localDeviceId, Controller::DevicePairingDelegate * pairingDelegate = nullptr, + Controller::PersistentStorageDelegate * storageDelegate = nullptr); + /** + * Init function to be used when already-initialized System::Layer and InetLayer are available. + */ + CHIP_ERROR Init(NodeId localDeviceId, System::Layer * systemLayer, Inet::InetLayer * inetLayer, + Controller::DevicePairingDelegate * pairingDelegate = nullptr, + Controller::PersistentStorageDelegate * storageDelegate = nullptr); + CHIP_ERROR Shutdown(); + + CHIP_ERROR SetUdpListenPort(uint16_t listenPort); + + // ----- Connection Management ----- + /** + * @brief + * Connect to a CHIP device with the provided Rendezvous connection parameters + * + * @param[in] remoteDeviceId The remote device Id. + * @param[in] params The Rendezvous connection parameters + * @param[in] appReqState Application specific context to be passed back when a message is received or on error + * @param[in] onConnected Callback for when the connection is established + * @param[in] onMessageReceived Callback for when a message is received + * @param[in] onError Callback for when an error occurs + * @param[in] devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT + * @param[in] interfaceId [Optional] The interface indicator to use + * + * @return CHIP_ERROR The connection status + */ + [[deprecated("Available until controller apps move to DeviceController/DeviceCommissioner API")]] CHIP_ERROR + ConnectDevice(NodeId remoteDeviceId, RendezvousParameters & params, void * appReqState, NewConnectionHandler onConnected, + MessageReceiveHandler onMessageReceived, ErrorHandler onError, uint16_t devicePort = CHIP_PORT, + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); + + /** + * @brief + * Connect to a CHIP device at a given address and an optional port. This is a test only API + * that bypasses Rendezvous and Secure Pairing process. + * + * @param[in] remoteDeviceId The remote device Id. + * @param[in] deviceAddr The IPAddress of the requested Device + * @param[in] appReqState Application specific context to be passed back when a message is received or on error + * @param[in] onConnected Callback for when the connection is established + * @param[in] onMessageReceived Callback for when a message is received + * @param[in] onError Callback for when an error occurs + * @param[in] devicePort [Optional] The CHIP Device's port, defaults to CHIP_PORT + * @param[in] interfaceId [Optional] The interface indicator to use + * @return CHIP_ERROR The connection status + */ + [[deprecated("Available until Rendezvous is implemented")]] CHIP_ERROR + ConnectDeviceWithoutSecurePairing(NodeId remoteDeviceId, const Inet::IPAddress & deviceAddr, void * appReqState, + NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, + ErrorHandler onError, uint16_t devicePort = CHIP_PORT, + Inet::InterfaceId interfaceId = INET_NULL_INTERFACEID); + + /** + * @brief + * Disconnect from a connected device + * + * @return CHIP_ERROR If the device was disconnected successfully + */ + CHIP_ERROR DisconnectDevice(); + + /** + * @brief + * Check if there's an active connection + * + * @return bool If there is an active connection + */ + bool IsConnected() const; + + /** + * @brief + * Get IP Address of the peer if the connection is active + * + * @return bool If IP Address was returned + */ + bool GetIpAddress(Inet::IPAddress & addr) const; + + // ----- Messaging ----- + /** + * @brief + * Send a message to a connected CHIP device + * + * @param[in] appReqState Application specific context to be passed back when a message is received or on error + * @param[in] buffer The Data Buffer to trasmit to the device + * @param[in] peerDevice Device ID of the peer device + * @return CHIP_ERROR The return status + */ + CHIP_ERROR SendMessage(void * appReqState, System::PacketBuffer * buffer, NodeId peerDevice = kUndefinedNodeId); + + // ----- IO ----- + /** + * @brief + * Start the event loop task within the CHIP stack + * @return CHIP_ERROR The return status + */ + CHIP_ERROR ServiceEvents(); + + /** + * @brief + * Allow the CHIP Stack to process any pending events + * This can be called in an event handler loop to tigger callbacks within the CHIP stack + * @return CHIP_ERROR The return status + */ + CHIP_ERROR ServiceEventSignal(); + + // ----- Pairing ----- + /** + * @brief + * Set device pairing delegate after init, pass nullptr remove device delegate. + * @return CHIP_ERROR The return status + */ + CHIP_ERROR SetDevicePairingDelegate(Controller::DevicePairingDelegate * pairingDelegate); + + //////////// DeviceStatusDelegate Implementation /////////////// + void OnMessage(System::PacketBuffer * msg) override; + +private: + enum + { + kState_NotInitialized = 0, + kState_Initialized = 1 + } mState; + + Controller::DeviceCommissioner mCommissioner; + Controller::Device * mDevice; + + void * mAppReqState; + + union + { + CompleteHandler General; + MessageReceiveHandler Response; + } mOnComplete; + + ErrorHandler mOnError; + NewConnectionHandler mOnNewConnection; + System::PacketBuffer * mCurReqMsg; + + NodeId mLocalDeviceId; + NodeId mRemoteDeviceId; + uint16_t mListenPort; + + Controller::SerializedDevice mSerializedTestDevice; + bool mPairingWithoutSecurity; + + void ClearRequestState(); + void ClearOpState(); +}; + +} // namespace DeviceController +} // namespace chip diff --git a/src/controller/CHIPPersistentStorageDelegate.h b/src/controller/CHIPPersistentStorageDelegate.h index 141447795179f5..a2176f2bc63b80 100644 --- a/src/controller/CHIPPersistentStorageDelegate.h +++ b/src/controller/CHIPPersistentStorageDelegate.h @@ -22,7 +22,7 @@ #include namespace chip { -namespace DeviceController { +namespace Controller { class DLL_EXPORT PersistentStorageResultDelegate { @@ -79,6 +79,21 @@ class DLL_EXPORT PersistentStorageDelegate */ virtual void GetKeyValue(const char * key) = 0; + /** + * @brief + * This is a synchronous Get API, where the value is returned via the output + * buffer. This API should be used sparingly, since it may block for + * some duration. + * + * @param[in] key Key to lookup + * @param[out] value Value for the key + * @param[in, out] size Input value buffer size, output length of value. + * The output length could be larger than input value. In + * such cases, the user should allocate the buffer large + * enough (>= output length), and call the API again. + */ + virtual CHIP_ERROR GetKeyValue(const char * key, char * value, uint16_t & size) { return CHIP_ERROR_NOT_IMPLEMENTED; } + /** * @brief * Set the value for the key @@ -97,5 +112,5 @@ class DLL_EXPORT PersistentStorageDelegate virtual void DeleteKeyValue(const char * key) = 0; }; -} // namespace DeviceController +} // namespace Controller } // namespace chip diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index a2715f85d52d4f..59eb1febcfb058 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -21,7 +21,7 @@ #include -#include +#include /** * This class contains all relevant information for the JNI view of CHIPDeviceController @@ -29,7 +29,7 @@ * * Generally it contains the DeviceController class itself, plus any related delegates/callbacks. */ -class AndroidDeviceControllerWrapper : public chip::DeviceController::DevicePairingDelegate +class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDelegate { public: ~AndroidDeviceControllerWrapper(); diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 007e53e95938d0..721d8a78300096 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -28,7 +28,7 @@ #include "AndroidDeviceControllerWrapper.h" #include -#include +#include #include #include #include diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index dd9407ada2aec2..84b22a14e87614 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -23,7 +23,8 @@ config("controller_wno_deprecate") { } config("includes") { - include_dirs = [ "${chip_root}/src/controller/CHIPDeviceController.h" ] + include_dirs = + [ "${chip_root}/src/controller/CHIPDeviceController_deprecated.h" ] } shared_library("ChipDeviceCtrl") { diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 18f6c0268510ae..8e9e927815036e 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -45,7 +45,7 @@ #include "ChipDeviceController-ScriptDevicePairingDelegate.h" -#include +#include #include #include #include @@ -178,7 +178,7 @@ CHIP_ERROR nl_Chip_ScriptDevicePairingDelegate_SetWifiCredential(chip::DeviceController::ScriptDevicePairingDelegate * pairingDelegate, const char * ssid, const char * password); CHIP_ERROR nl_Chip_DeviceController_SetDevicePairingDelegate(chip::DeviceController::ChipDeviceController * devCtrl, - chip::DeviceController::DevicePairingDelegate * pairingDelegate); + chip::Controller::DevicePairingDelegate * pairingDelegate); #if CONFIG_NETWORK_LAYER_BLE CHIP_ERROR nl_Chip_DeviceController_ValidateBTP(chip::DeviceController::ChipDeviceController * devCtrl, @@ -583,7 +583,7 @@ nl_Chip_ScriptDevicePairingDelegate_SetWifiCredential(chip::DeviceController::Sc return err; } CHIP_ERROR nl_Chip_DeviceController_SetDevicePairingDelegate(chip::DeviceController::ChipDeviceController * devCtrl, - chip::DeviceController::DevicePairingDelegate * pairingDelegate) + chip::Controller::DevicePairingDelegate * pairingDelegate) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h index 17b51a62c21ca2..3a821bf45bc065 100644 --- a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h +++ b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h @@ -25,7 +25,7 @@ #pragma once -#include +#include #include #include @@ -33,7 +33,7 @@ namespace chip { namespace DeviceController { -class ScriptDevicePairingDelegate final : public DevicePairingDelegate +class ScriptDevicePairingDelegate final : public Controller::DevicePairingDelegate { public: ~ScriptDevicePairingDelegate() = default; diff --git a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m index be0c0fc7d91ff9..fcc9d0545a7926 100644 --- a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m +++ b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m @@ -48,9 +48,17 @@ @implementation CHIPToolPersistentStorageDelegate - (void)GetKeyValue:(NSString *)key handler:(SendKeyValue)completionHandler { NSString * value = CHIPGetDomainValueForKey(kCHIPToolDefaultsDomain, key); + NSLog(@"CHIPPersistentStorageDelegate Get Value for Key: %@, value %@", key, value); completionHandler(key, value); } +- (NSString *)GetKeyValue:(NSString *)key +{ + NSString * value = CHIPGetDomainValueForKey(kCHIPToolDefaultsDomain, key); + NSLog(@"CHIPPersistentStorageDelegate Get Value for Key: %@, value %@", key, value); + return value; +} + - (void)SetKeyValue:(NSString *)key value:(NSString *)value handler:(SendStatus)completionHandler { CHIPSetDomainValueForKey(kCHIPToolDefaultsDomain, key, value); diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController.mm b/src/darwin/Framework/CHIP/CHIPDeviceController.mm index 3d57db3c9149fb..faa2d5687bffad 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceController.mm @@ -25,7 +25,7 @@ #import "CHIPLogging.h" #import "CHIPPersistentStorageDelegateBridge.h" -#include +#include #include #include #include @@ -95,6 +95,11 @@ - (instancetype)init return nil; } + if (CHIP_NO_ERROR != chip::Platform::MemoryInit()) { + CHIP_LOG_ERROR("Error: Failed in memory init"); + return nil; + } + _cppController = new chip::DeviceController::ChipDeviceController(); if (!_cppController) { CHIP_LOG_ERROR("Error: couldn't create c++ controller"); @@ -129,17 +134,6 @@ - (instancetype)init _persistentStorageDelegateBridge = NULL; return nil; } - - if (CHIP_NO_ERROR != chip::Platform::MemoryInit()) { - CHIP_LOG_ERROR("Error: couldn't initialize c++ controller"); - delete _cppController; - _cppController = NULL; - delete _pairingDelegateBridge; - _pairingDelegateBridge = NULL; - delete _persistentStorageDelegateBridge; - _persistentStorageDelegateBridge = NULL; - return nil; - } } return self; } diff --git a/src/darwin/Framework/CHIP/CHIPDevicePairingDelegateBridge.h b/src/darwin/Framework/CHIP/CHIPDevicePairingDelegateBridge.h index b448c06b5e94dc..884c17bfd5f4db 100644 --- a/src/darwin/Framework/CHIP/CHIPDevicePairingDelegateBridge.h +++ b/src/darwin/Framework/CHIP/CHIPDevicePairingDelegateBridge.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN -class CHIPDevicePairingDelegateBridge : public chip::DeviceController::DevicePairingDelegate +class CHIPDevicePairingDelegateBridge : public chip::Controller::DevicePairingDelegate { public: CHIPDevicePairingDelegateBridge(); diff --git a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegate.h b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegate.h index 916b1f40e2b850..b59cce262adab0 100644 --- a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegate.h +++ b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegate.h @@ -43,6 +43,12 @@ typedef void (^SendStatus)(NSString * key, Operation operation, NSError * status */ - (void)GetKeyValue:(NSString *)key handler:(SendKeyValue)completionHandler; +/** + * Get the value for the given key + * + */ +- (NSString *)GetKeyValue:(NSString *)key; + /** * Set the value of the key to the given value * diff --git a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h index fe9645bfa18a31..bb689a0094d304 100644 --- a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h +++ b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN -class CHIPPersistentStorageDelegateBridge : public chip::DeviceController::PersistentStorageDelegate +class CHIPPersistentStorageDelegateBridge : public chip::Controller::PersistentStorageDelegate { public: CHIPPersistentStorageDelegateBridge(); @@ -30,10 +30,12 @@ class CHIPPersistentStorageDelegateBridge : public chip::DeviceController::Persi void setFrameworkDelegate(id delegate, dispatch_queue_t queue); - void SetDelegate(chip::DeviceController::PersistentStorageResultDelegate * delegate); + void SetDelegate(chip::Controller::PersistentStorageResultDelegate * delegate); void GetKeyValue(const char * key) override; + CHIP_ERROR GetKeyValue(const char * key, char * value, uint16_t & size) override; + void SetKeyValue(const char * key, const char * value) override; void DeleteKeyValue(const char * key) override; @@ -42,7 +44,7 @@ class CHIPPersistentStorageDelegateBridge : public chip::DeviceController::Persi id mDelegate; dispatch_queue_t mQueue; - chip::DeviceController::PersistentStorageResultDelegate * mCallback; + chip::Controller::PersistentStorageResultDelegate * mCallback; SendKeyValue mCompletionHandler; SendStatus mStatusHandler; NSUserDefaults * mDefaultPersistentStorage; diff --git a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm index 51a74449ac1e76..92f3862eedd37c 100644 --- a/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/CHIPPersistentStorageDelegateBridge.mm @@ -39,7 +39,7 @@ } } -void CHIPPersistentStorageDelegateBridge::SetDelegate(chip::DeviceController::PersistentStorageResultDelegate * delegate) +void CHIPPersistentStorageDelegateBridge::SetDelegate(chip::Controller::PersistentStorageResultDelegate * delegate) { if (delegate) { mCallback = delegate; @@ -49,17 +49,17 @@ }; mStatusHandler = ^(NSString * key, Operation operation, NSError * status) { - chip::DeviceController::PersistentStorageResultDelegate::Operation op - = chip::DeviceController::PersistentStorageResultDelegate::Operation::kGET; + chip::Controller::PersistentStorageResultDelegate::Operation op + = chip::Controller::PersistentStorageResultDelegate::Operation::kGET; switch (operation) { case kGet: - op = chip::DeviceController::PersistentStorageResultDelegate::Operation::kGET; + op = chip::Controller::PersistentStorageResultDelegate::Operation::kGET; break; case kSet: - op = chip::DeviceController::PersistentStorageResultDelegate::Operation::kSET; + op = chip::Controller::PersistentStorageResultDelegate::Operation::kSET; break; case kDelete: - op = chip::DeviceController::PersistentStorageResultDelegate::Operation::kDELETE; + op = chip::Controller::PersistentStorageResultDelegate::Operation::kDELETE; break; } mCallback->OnStatus([key UTF8String], op, [CHIPError errorToCHIPErrorCode:status]); @@ -84,16 +84,41 @@ } else { dispatch_async(mDefaultCallbackQueue, ^{ NSString * value = [mDefaultPersistentStorage objectForKey:keyString]; + NSLog(@"PersistentStorageDelegate Get Value for Key: %@, value %@", keyString, value); mCompletionHandler(keyString, value); }); } } +CHIP_ERROR CHIPPersistentStorageDelegateBridge::GetKeyValue(const char * key, char * value, uint16_t & size) +{ + NSString * keyString = [NSString stringWithUTF8String:key]; + NSLog(@"PersistentStorageDelegate Sync Get Value for Key: %@", keyString); + + NSString * valueString = nil; + + id strongDelegate = mDelegate; + if (strongDelegate) { + valueString = [strongDelegate GetKeyValue:keyString]; + } else { + valueString = [mDefaultPersistentStorage objectForKey:keyString]; + } + + if (value != nullptr) { + size = strlcpy(value, [valueString UTF8String], size); + } else { + size = [valueString length]; + } + // Increment size to account for null termination + size += 1; + return CHIP_NO_ERROR; +} + void CHIPPersistentStorageDelegateBridge::SetKeyValue(const char * key, const char * value) { NSString * keyString = [NSString stringWithUTF8String:key]; NSString * valueString = [NSString stringWithUTF8String:value]; - NSLog(@"PersistentStorageDelegate Set Key %@", keyString); + NSLog(@"PersistentStorageDelegate Set Key %@, Value %@", keyString, valueString); id strongDelegate = mDelegate; if (strongDelegate && mQueue) { diff --git a/src/lib/support/SerializableIntegerSet.h b/src/lib/support/SerializableIntegerSet.h index 0fe6e0d368a7de..6e59f7751c76bb 100644 --- a/src/lib/support/SerializableIntegerSet.h +++ b/src/lib/support/SerializableIntegerSet.h @@ -34,6 +34,8 @@ #include #include +#define CHIP_MAX_SERIALIZED_SIZE_U64(count) static_cast(BASE64_ENCODED_LEN(sizeof(uint64_t) * (count))) + namespace chip { class SerializableU64SetBase @@ -78,13 +80,13 @@ class SerializableU64SetBase * @brief * Get the length of string if the array is serialized. */ - uint16_t SerializedSize() { return static_cast(BASE64_ENCODED_LEN(sizeof(uint64_t) * mNextAvailable)); } + uint16_t SerializedSize() { return CHIP_MAX_SERIALIZED_SIZE_U64(mNextAvailable); } /** * @brief * Get the maximum length of string if the array were full and serialized. */ - uint16_t MaxSerializedSize() { return static_cast(BASE64_ENCODED_LEN(sizeof(uint64_t) * mCapacity)); } + uint16_t MaxSerializedSize() { return CHIP_MAX_SERIALIZED_SIZE_U64(mCapacity); } /** * @brief diff --git a/src/transport/RendezvousSession.cpp b/src/transport/RendezvousSession.cpp index 838d4d0c5603a9..8e66d74919d771 100644 --- a/src/transport/RendezvousSession.cpp +++ b/src/transport/RendezvousSession.cpp @@ -213,19 +213,33 @@ void RendezvousSession::OnRendezvousError(CHIP_ERROR err) break; }; mDelegate->OnRendezvousError(err); - UpdateState(State::kInit); + UpdateState(State::kInit, err); } -void RendezvousSession::UpdateState(RendezvousSession::State newState) +void RendezvousSession::UpdateState(RendezvousSession::State newState, CHIP_ERROR err) { switch (mCurrentState) { case State::kSecurePairing: - mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess, CHIP_NO_ERROR); + if (newState != State::kInit) + { + mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess, err); + } + else + { + mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingFailed, err); + } break; case State::kNetworkProvisioning: - mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess, CHIP_NO_ERROR); + if (newState != State::kInit) + { + mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess, err); + } + else + { + mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningFailed, err); + } break; default: diff --git a/src/transport/RendezvousSession.h b/src/transport/RendezvousSession.h index 3a0b71870cb570..ed0415f2bec021 100644 --- a/src/transport/RendezvousSession.h +++ b/src/transport/RendezvousSession.h @@ -138,7 +138,7 @@ class RendezvousSession : public SecurePairingSessionDelegate, uint16_t mNextKeyId = 0; RendezvousSession::State mCurrentState = State::kInit; - void UpdateState(RendezvousSession::State newState); + void UpdateState(RendezvousSession::State newState, CHIP_ERROR err = CHIP_NO_ERROR); }; } // namespace chip diff --git a/src/transport/SecurePairingSession.cpp b/src/transport/SecurePairingSession.cpp index 61335c1fb3a8f0..780654bd82676d 100644 --- a/src/transport/SecurePairingSession.cpp +++ b/src/transport/SecurePairingSession.cpp @@ -57,37 +57,20 @@ SecurePairingSession::~SecurePairingSession() CHIP_ERROR SecurePairingSession::Serialize(SecurePairingSessionSerialized & output) { - CHIP_ERROR error = CHIP_NO_ERROR; + CHIP_ERROR error = CHIP_NO_ERROR; + uint16_t serializedLen = 0; + SecurePairingSessionSerializable serializable; - const NodeId localNodeId = (mLocalNodeId.HasValue()) ? mLocalNodeId.Value() : kUndefinedNodeId; - const NodeId peerNodeId = (mPeerNodeId.HasValue()) ? mPeerNodeId.Value() : kUndefinedNodeId; - VerifyOrExit(CanCastTo(mKeLen), error = CHIP_ERROR_INTERNAL); - VerifyOrExit(CanCastTo(localNodeId), error = CHIP_ERROR_INTERNAL); - VerifyOrExit(CanCastTo(peerNodeId), error = CHIP_ERROR_INTERNAL); - VerifyOrExit(CanCastTo(sizeof(SecurePairingSessionSerializable)), error = CHIP_ERROR_INTERNAL); + VerifyOrExit(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT); - { - SecurePairingSessionSerializable serializable; - memset(&serializable, 0, sizeof(serializable)); - serializable.mKeLen = static_cast(mKeLen); - serializable.mPairingComplete = (mPairingComplete) ? 1 : 0; - serializable.mLocalNodeId = localNodeId; - serializable.mPeerNodeId = peerNodeId; - serializable.mLocalKeyId = mLocalKeyId; - serializable.mPeerKeyId = mPeerKeyId; - - memcpy(serializable.mKe, mKe, mKeLen); - - uint16_t serializedLen = 0; - - VerifyOrExit(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT); - - serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast(&serializable)), - static_cast(sizeof(serializable)), Uint8::to_char(output.inner)); - VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT); - output.inner[serializedLen] = '\0'; - } + error = ToSerializable(serializable); + SuccessOrExit(error); + + serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast(&serializable)), + static_cast(sizeof(serializable)), Uint8::to_char(output.inner)); + VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT); + output.inner[serializedLen] = '\0'; exit: return error; @@ -107,9 +90,44 @@ CHIP_ERROR SecurePairingSession::Deserialize(SecurePairingSessionSerialized & in memset(&serializable, 0, sizeof(serializable)); deserializedLen = Base64Decode(Uint8::to_const_char(input.inner), static_cast(len), Uint8::to_uchar((uint8_t *) &serializable)); + VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT); + error = FromSerializable(serializable); + +exit: + return error; +} + +CHIP_ERROR SecurePairingSession::ToSerializable(SecurePairingSessionSerializable & serializable) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + const NodeId localNodeId = (mLocalNodeId.HasValue()) ? mLocalNodeId.Value() : kUndefinedNodeId; + const NodeId peerNodeId = (mPeerNodeId.HasValue()) ? mPeerNodeId.Value() : kUndefinedNodeId; + VerifyOrExit(CanCastTo(mKeLen), error = CHIP_ERROR_INTERNAL); + VerifyOrExit(CanCastTo(localNodeId), error = CHIP_ERROR_INTERNAL); + VerifyOrExit(CanCastTo(peerNodeId), error = CHIP_ERROR_INTERNAL); + + memset(&serializable, 0, sizeof(serializable)); + serializable.mKeLen = static_cast(mKeLen); + serializable.mPairingComplete = (mPairingComplete) ? 1 : 0; + serializable.mLocalNodeId = localNodeId; + serializable.mPeerNodeId = peerNodeId; + serializable.mLocalKeyId = mLocalKeyId; + serializable.mPeerKeyId = mPeerKeyId; + + memcpy(serializable.mKe, mKe, mKeLen); + +exit: + return error; +} + +CHIP_ERROR SecurePairingSession::FromSerializable(const SecurePairingSessionSerializable & serializable) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + mPairingComplete = (serializable.mPairingComplete == 1); mKeLen = static_cast(serializable.mKeLen); diff --git a/src/transport/SecurePairingSession.h b/src/transport/SecurePairingSession.h index dfe3857c5d6863..d811c2e22b3c94 100644 --- a/src/transport/SecurePairingSession.h +++ b/src/transport/SecurePairingSession.h @@ -74,6 +74,17 @@ class DLL_EXPORT SecurePairingSessionDelegate struct SecurePairingSessionSerialized; +struct SecurePairingSessionSerializable +{ + uint16_t mKeLen; + uint8_t mKe[kMAX_Hash_Length]; + uint8_t mPairingComplete; + uint64_t mLocalNodeId; + uint64_t mPeerNodeId; + uint16_t mLocalKeyId; + uint16_t mPeerKeyId; +}; + class DLL_EXPORT SecurePairingSession { public: @@ -178,6 +189,18 @@ class DLL_EXPORT SecurePairingSession **/ CHIP_ERROR Deserialize(SecurePairingSessionSerialized & input); + /** @brief Serialize the SecurePairingSession to the given serializable data structure for secure pairing + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR ToSerializable(SecurePairingSessionSerializable & output); + + /** @brief Reconstruct secure pairing class from the serializable data structure. + * + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR FromSerializable(const SecurePairingSessionSerializable & output); + private: CHIP_ERROR Init(uint32_t setupCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen, Optional myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate); @@ -209,12 +232,6 @@ class DLL_EXPORT SecurePairingSession /* w0s and w1s */ uint8_t mWS[2][kSpake2p_WS_Length]; - uint8_t mKe[kMAX_Hash_Length]; - - size_t mKeLen = sizeof(mKe); - - bool mPairingComplete = false; - protected: Optional mLocalNodeId = Optional::Value(kUndefinedNodeId); @@ -223,6 +240,12 @@ class DLL_EXPORT SecurePairingSession uint16_t mLocalKeyId; uint16_t mPeerKeyId; + + uint8_t mKe[kMAX_Hash_Length]; + + size_t mKeLen = sizeof(mKe); + + bool mPairingComplete = false; }; /* @@ -234,12 +257,25 @@ class DLL_EXPORT SecurePairingSession class SecurePairingUsingTestSecret : public SecurePairingSession { public: - SecurePairingUsingTestSecret() {} + SecurePairingUsingTestSecret() + { + const char * secret = "Test secret for key derivation"; + size_t secretLen = strlen(secret); + mKeLen = secretLen; + memmove(mKe, secret, mKeLen); + mPairingComplete = true; + } + SecurePairingUsingTestSecret(Optional peerNodeId, uint16_t peerKeyId, uint16_t localKeyId) { - mPeerNodeId = peerNodeId; - mPeerKeyId = peerKeyId; - mLocalKeyId = localKeyId; + const char * secret = "Test secret for key derivation"; + size_t secretLen = strlen(secret); + mPeerNodeId = peerNodeId; + mPeerKeyId = peerKeyId; + mLocalKeyId = localKeyId; + mKeLen = secretLen; + memmove(mKe, secret, mKeLen); + mPairingComplete = true; } ~SecurePairingUsingTestSecret() override {} @@ -256,28 +292,9 @@ class SecurePairingUsingTestSecret : public SecurePairingSession return CHIP_NO_ERROR; } - CHIP_ERROR DeriveSecureSession(const uint8_t * info, size_t info_len, SecureSession & session) override - { - const char * secret = "Test secret for key derivation"; - size_t secretLen = strlen(secret); - return session.InitFromSecret(reinterpret_cast(secret), secretLen, reinterpret_cast(""), - 0, reinterpret_cast(secret), secretLen); - } - CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, System::PacketBuffer * msg) override { return CHIP_NO_ERROR; } }; -typedef struct SecurePairingSessionSerializable -{ - uint16_t mKeLen; - uint8_t mKe[kMAX_Hash_Length]; - uint8_t mPairingComplete; - uint64_t mLocalNodeId; - uint64_t mPeerNodeId; - uint16_t mLocalKeyId; - uint16_t mPeerKeyId; -} SecurePairingSessionSerializable; - typedef struct SecurePairingSessionSerialized { // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads) diff --git a/src/transport/SecureSessionMgr.cpp b/src/transport/SecureSessionMgr.cpp index 4e41dc49620e26..a8dea8e4b15bd7 100644 --- a/src/transport/SecureSessionMgr.cpp +++ b/src/transport/SecureSessionMgr.cpp @@ -65,6 +65,8 @@ CHIP_ERROR SecureSessionMgrBase::InitInternal(NodeId localNodeId, System::Layer mSystemLayer = systemLayer; mTransport = transport; + ChipLogProgress(Inet, "local node id is %llu\n", mLocalNodeId); + mTransport->SetMessageReceiveHandler(HandleDataReceived, this); mPeerConnections.SetConnectionExpiredHandler(HandleConnectionExpired, this); @@ -124,6 +126,8 @@ CHIP_ERROR SecureSessionMgrBase::SendMessage(PayloadHeader & payloadHeader, Node .SetEncryptionKeyID(state->GetLocalKeyID()) // .SetPayloadLength(static_cast(payloadLength)); + ChipLogProgress(Inet, "Sending msg from %llu to %llu\n", mLocalNodeId, peerNodeId); + VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY); msgBuf->SetStart(msgBuf->Start() - headerSize); diff --git a/src/transport/SecureSessionMgr.h b/src/transport/SecureSessionMgr.h index ac66baf2e4c06c..553671537fd460 100644 --- a/src/transport/SecureSessionMgr.h +++ b/src/transport/SecureSessionMgr.h @@ -224,6 +224,12 @@ class SecureSessionMgr : public SecureSessionMgrBase return err; } + template + CHIP_ERROR ResetTransport(Args &&... transportInitArgs) + { + return mTransport.Init(std::forward(transportInitArgs)...); + } + private: Transport::Tuple mTransport; }; diff --git a/src/transport/raw/Base.h b/src/transport/raw/Base.h index fe1dc4fd30dccf..f374bffbaadd13 100644 --- a/src/transport/raw/Base.h +++ b/src/transport/raw/Base.h @@ -82,6 +82,11 @@ class Base */ virtual void Disconnect(const PeerAddress & address) {} + /** + * Close the open endpoint without destroying the object + */ + virtual void Close(){}; + protected: /** * Method used by subclasses to notify that a packet has been received after diff --git a/src/transport/raw/UDP.cpp b/src/transport/raw/UDP.cpp index ce065b62be172a..aa5621a91856c5 100644 --- a/src/transport/raw/UDP.cpp +++ b/src/transport/raw/UDP.cpp @@ -34,20 +34,17 @@ namespace Transport { UDP::~UDP() { - if (mUDPEndPoint) - { - // Udp endpoint is only non null if udp endpoint is initialized and listening - mUDPEndPoint->Close(); - mUDPEndPoint->Free(); - mUDPEndPoint = nullptr; - } + Close(); } CHIP_ERROR UDP::Init(UdpListenParameters & params) { CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(mState == State::kNotReady, err = CHIP_ERROR_INCORRECT_STATE); + if (mState != State::kNotReady) + { + Close(); + } err = params.GetInetLayer()->NewUDPEndPoint(&mUDPEndPoint); SuccessOrExit(err); @@ -78,6 +75,18 @@ CHIP_ERROR UDP::Init(UdpListenParameters & params) return err; } +void UDP::Close() +{ + if (mUDPEndPoint) + { + // Udp endpoint is only non null if udp endpoint is initialized and listening + mUDPEndPoint->Close(); + mUDPEndPoint->Free(); + mUDPEndPoint = nullptr; + } + mState = State::kNotReady; +} + CHIP_ERROR UDP::SendMessage(const PacketHeader & header, Header::Flags payloadFlags, const Transport::PeerAddress & address, System::PacketBuffer * msgBuf) { diff --git a/src/transport/raw/UDP.h b/src/transport/raw/UDP.h index d2dfcc36ad5812..2cfbf7646a400f 100644 --- a/src/transport/raw/UDP.h +++ b/src/transport/raw/UDP.h @@ -105,6 +105,11 @@ class DLL_EXPORT UDP : public Base */ CHIP_ERROR Init(UdpListenParameters & params); + /** + * Close the open endpoint without destroying the object + */ + void Close() override; + CHIP_ERROR SendMessage(const PacketHeader & header, Header::Flags payloadFlags, const Transport::PeerAddress & address, System::PacketBuffer * msgBuf) override;