| /* |
| * |
| * 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 |
| // module header, comes first |
| #include <controller/CHIPDeviceController.h> |
| |
| #if CONFIG_DEVICE_LAYER |
| #include <platform/CHIPDeviceLayer.h> |
| #endif |
| |
| #include <core/CHIPCore.h> |
| #include <core/CHIPEncoding.h> |
| #include <support/Base64.h> |
| #include <support/CodeUtils.h> |
| #include <support/ErrorStr.h> |
| #include <support/TimeUtils.h> |
| #include <support/logging/CHIPLogging.h> |
| |
| #include <errno.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <time.h> |
| |
| namespace chip { |
| namespace DeviceController { |
| |
| using namespace chip::Encoding; |
| |
| static constexpr uint32_t kSpake2p_Iteration_Count = 50000; |
| static const char * kSpake2pKeyExchangeSalt = "SPAKE2P Key Exchange Salt"; |
| |
| ChipDeviceController::ChipDeviceController() |
| { |
| mState = kState_NotInitialized; |
| AppState = NULL; |
| mConState = kConnectionState_NotConnected; |
| mSessionManager = NULL; |
| mCurReqMsg = NULL; |
| mOnError = NULL; |
| mOnNewConnection = NULL; |
| mDeviceAddr = IPAddress::Any; |
| mDevicePort = CHIP_PORT; |
| mLocalDeviceId = 0; |
| memset(&mOnComplete, 0, sizeof(mOnComplete)); |
| } |
| |
| CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE); |
| |
| #if CONFIG_DEVICE_LAYER |
| err = DeviceLayer::PlatformMgr().InitChipStack(); |
| SuccessOrExit(err); |
| |
| err = Init(localNodeId, &DeviceLayer::SystemLayer, &DeviceLayer::InetLayer); |
| #endif // CONFIG_DEVICE_LAYER |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::Init(NodeId localNodeId, System::Layer * systemLayer, InetLayer * inetLayer) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE); |
| |
| mSystemLayer = systemLayer; |
| mInetLayer = inetLayer; |
| |
| mState = kState_Initialized; |
| mLocalDeviceId = localNodeId; |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::Shutdown() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); |
| |
| mState = kState_NotInitialized; |
| |
| #if CONFIG_DEVICE_LAYER |
| err = DeviceLayer::PlatformMgr().Shutdown(); |
| SuccessOrExit(err); |
| #else |
| mSystemLayer->Shutdown(); |
| mInetLayer->Shutdown(); |
| delete mSystemLayer; |
| delete mInetLayer; |
| #endif // CONFIG_DEVICE_LAYER |
| |
| mSystemLayer = NULL; |
| mInetLayer = NULL; |
| |
| if (mSessionManager != NULL) |
| { |
| delete mSessionManager; |
| mSessionManager = NULL; |
| } |
| |
| if (mUnsecuredTransport != NULL) |
| { |
| mUnsecuredTransport->Release(); |
| delete mUnsecuredTransport; |
| mUnsecuredTransport = NULL; |
| } |
| |
| mConState = kConnectionState_NotConnected; |
| memset(&mOnComplete, 0, sizeof(mOnComplete)); |
| mOnError = NULL; |
| mOnNewConnection = NULL; |
| mMessageNumber = 0; |
| mRemoteDeviceId.ClearValue(); |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::OnNewMessageForPeer(System::PacketBuffer * msgBuf) |
| { |
| return SendMessage(mAppReqState, msgBuf); |
| } |
| |
| void ChipDeviceController::OnPairingError(CHIP_ERROR error) |
| { |
| ChipLogError(Controller, "Failed to pair with accessory. Error %d", error); |
| mPairingInProgress = false; |
| |
| if (mOnError != nullptr) |
| { |
| mOnError(this, mAppReqState, error, nullptr); |
| } |
| } |
| |
| void ChipDeviceController::OnPairingComplete(Optional<NodeId> peerNodeId, uint16_t peerKeyId, uint16_t localKeyId) |
| { |
| ChipLogProgress(Controller, "Successfully paired with accessory. Key Id %d", peerKeyId); |
| mPairingInProgress = false; |
| |
| if (mPairingComplete != nullptr) |
| { |
| mPeerKeyId = peerKeyId; |
| mLocalPairedKeyId = localKeyId; |
| ChipLogProgress(Controller, "Calling mPairingComplete"); |
| mPairingComplete(this, nullptr, mAppReqState); |
| } |
| } |
| |
| void ChipDeviceController::PairingMessageHandler(ChipDeviceController * controller, void * appReqState, |
| System::PacketBuffer * payload) |
| { |
| if (controller->mPairingInProgress) |
| { |
| MessageHeader header; |
| size_t headerSize = 0; |
| CHIP_ERROR err = header.Decode(payload->Start(), payload->DataLength(), &headerSize); |
| SuccessOrExit(err); |
| |
| payload->ConsumeHead(headerSize); |
| controller->mPairingSession.HandlePeerMessage(header, payload); |
| } |
| else if (controller->mAppMsgHandler != nullptr) |
| { |
| controller->mAppMsgHandler(controller, appReqState, payload); |
| } |
| |
| exit: |
| return; |
| } |
| |
| void ChipDeviceController::BLEConnectionHandler(ChipDeviceController * controller, Transport::PeerConnectionState * state, |
| void * appReqState) |
| { |
| ChipLogProgress(Controller, "Starting pairing session"); |
| controller->mPairingInProgress = true; |
| CHIP_ERROR err = controller->mPairingSession.Pair( |
| controller->mSetupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt, |
| strlen(kSpake2pKeyExchangeSalt), Optional<NodeId>::Value(controller->mLocalDeviceId), controller->mNextKeyId++, controller); |
| SuccessOrExit(err); |
| |
| exit: |
| return; |
| } |
| |
| CHIP_ERROR ChipDeviceController::ConnectDevice(NodeId remoteDeviceId, const uint16_t discriminator, const uint32_t setupPINCode, |
| void * appReqState, NewConnectionHandler onConnected, |
| MessageReceiveHandler onMessageReceived, ErrorHandler onError) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| #if CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE |
| Transport::BLE * transport; |
| |
| ChipLogProgress(Controller, "Received new pairing request"); |
| ChipLogProgress(Controller, "mState %d. mConState %d", mState, mConState); |
| VerifyOrExit(mState == kState_Initialized && mConState == kConnectionState_NotConnected, err = CHIP_ERROR_INCORRECT_STATE); |
| |
| if (mPairingInProgress) |
| { |
| ChipLogError(Controller, "Pairing was already is progress. This will restart pairing."); |
| } |
| |
| mRemoteDeviceId = Optional<NodeId>::Value(remoteDeviceId); |
| mAppReqState = appReqState; |
| mPairingComplete = onConnected; |
| mOnNewConnection = BLEConnectionHandler; |
| mAppMsgHandler = onMessageReceived; |
| |
| mSetupPINCode = setupPINCode; |
| |
| transport = new Transport::BLE(); |
| err = transport->Init(Transport::BleConnectionParameters(this, DeviceLayer::ConnectivityMgr().GetBleLayer()) |
| .SetDiscriminator(discriminator) |
| .SetSetupPINCode(setupPINCode)); |
| SuccessOrExit(err); |
| |
| mUnsecuredTransport = transport->Retain(); |
| |
| // connected state before 'OnConnect' |
| mConState = kConnectionState_Connected; |
| |
| mOnComplete.Response = PairingMessageHandler; |
| mOnError = onError; |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| mConState = kConnectionState_NotConnected; |
| } |
| #else |
| err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; |
| #endif // CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE |
| |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::ConnectDevice(NodeId remoteDeviceId, IPAddress deviceAddr, void * appReqState, |
| NewConnectionHandler onConnected, MessageReceiveHandler onMessageReceived, |
| ErrorHandler onError, uint16_t devicePort) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| if (mState != kState_Initialized || mSessionManager != NULL || mConState != kConnectionState_NotConnected) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| mRemoteDeviceId = Optional<NodeId>::Value(remoteDeviceId); |
| mDeviceAddr = deviceAddr; |
| mDevicePort = devicePort; |
| mAppReqState = appReqState; |
| mOnNewConnection = onConnected; |
| |
| mSessionManager = new SecureSessionMgr<Transport::UDP>(); |
| |
| err = mSessionManager->Init(mLocalDeviceId, mSystemLayer, |
| Transport::UdpListenParameters(mInetLayer).SetAddressType(deviceAddr.Type())); |
| SuccessOrExit(err); |
| |
| mSessionManager->SetDelegate(this); |
| |
| mConState = kConnectionState_SecureConnected; |
| |
| mOnComplete.Response = onMessageReceived; |
| mOnError = onError; |
| |
| err = mSessionManager->NewPairing(mRemoteDeviceId, |
| Optional<Transport::PeerAddress>::Value(Transport::PeerAddress::UDP(deviceAddr, devicePort)), |
| mPeerKeyId, mLocalPairedKeyId, &mPairingSession); |
| SuccessOrExit(err); |
| |
| mMessageNumber = 1; |
| |
| exit: |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| if (mSessionManager != NULL) |
| { |
| delete mSessionManager; |
| mSessionManager = NULL; |
| } |
| mConState = kConnectionState_NotConnected; |
| } |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::PopulatePeerAddress(Transport::PeerAddress & peerAddress) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(IsSecurelyConnected(), err = CHIP_ERROR_INCORRECT_STATE); |
| |
| peerAddress.SetIPAddress(mDeviceAddr); |
| peerAddress.SetPort(mDevicePort); |
| peerAddress.SetTransportType(Transport::Type::kUdp); |
| |
| exit: |
| return err; |
| } |
| |
| bool ChipDeviceController::IsConnected() |
| { |
| return kState_Initialized && (mConState == kConnectionState_Connected || mConState == kConnectionState_SecureConnected); |
| } |
| |
| bool ChipDeviceController::IsSecurelyConnected() |
| { |
| return kState_Initialized && mConState == kConnectionState_SecureConnected; |
| } |
| |
| CHIP_ERROR ChipDeviceController::DisconnectDevice() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| if (!IsConnected()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| if (mSessionManager != NULL) |
| { |
| delete mSessionManager; |
| mSessionManager = NULL; |
| } |
| |
| if (mUnsecuredTransport != NULL) |
| { |
| mUnsecuredTransport->Release(); |
| delete mUnsecuredTransport; |
| mUnsecuredTransport = NULL; |
| } |
| |
| mConState = kConnectionState_NotConnected; |
| return err; |
| }; |
| |
| CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(mRemoteDeviceId.HasValue(), err = CHIP_ERROR_INCORRECT_STATE); |
| |
| mAppReqState = appReqState; |
| |
| if (mUnsecuredTransport != NULL) |
| { |
| VerifyOrExit(IsConnected(), err = CHIP_ERROR_INCORRECT_STATE); |
| // Unsecured transport does not use a MessageHeader, but the Transport::Base API expects one, so |
| // let build an empty one for now. |
| MessageHeader header; |
| Transport::PeerAddress peerAddress = Transport::PeerAddress::BLE(); |
| err = mUnsecuredTransport->SendMessage(header, peerAddress, buffer); |
| } |
| else |
| { |
| VerifyOrExit(IsSecurelyConnected(), err = CHIP_ERROR_INCORRECT_STATE); |
| err = mSessionManager->SendMessage(mRemoteDeviceId.Value(), buffer); |
| } |
| exit: |
| |
| return err; |
| } |
| |
| CHIP_ERROR ChipDeviceController::ServiceEvents() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(mState == kState_Initialized, 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; |
| |
| VerifyOrExit(mState == kState_Initialized, err = CHIP_ERROR_INCORRECT_STATE); |
| |
| #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: |
| return err; |
| } |
| |
| void ChipDeviceController::ClearRequestState() |
| { |
| if (mCurReqMsg != NULL) |
| { |
| PacketBuffer::Free(mCurReqMsg); |
| mCurReqMsg = NULL; |
| } |
| } |
| |
| void ChipDeviceController::OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr) {} |
| |
| void ChipDeviceController::OnMessageReceived(const MessageHeader & header, Transport::PeerConnectionState * state, |
| System::PacketBuffer * msgBuf, SecureSessionMgrBase * mgr) |
| { |
| if (header.GetSourceNodeId().HasValue()) |
| { |
| if (!mRemoteDeviceId.HasValue()) |
| { |
| ChipLogProgress(Controller, "Learned remote device id"); |
| mRemoteDeviceId = header.GetSourceNodeId(); |
| } |
| else if (mRemoteDeviceId != header.GetSourceNodeId()) |
| { |
| ChipLogError(Controller, "Received message from an unexpected source node id."); |
| } |
| } |
| if (IsSecurelyConnected() && mOnComplete.Response != NULL) |
| { |
| mOnComplete.Response(this, mAppReqState, msgBuf); |
| } |
| } |
| |
| void ChipDeviceController::OnBLEConnectionError(BLE_ERROR err) |
| { |
| if (mOnError) |
| { |
| mOnError(this, mAppReqState, err, NULL); |
| } |
| } |
| |
| void ChipDeviceController::OnBLEConnectionComplete(BLE_ERROR err) |
| { |
| ChipLogDetail(Controller, "BLE Connection complete"); |
| |
| if (mOnNewConnection) |
| { |
| mOnNewConnection(this, NULL, mAppReqState); |
| } |
| } |
| |
| void ChipDeviceController::OnBLEConnectionClosed(BLE_ERROR err) |
| { |
| ChipLogDetail(Controller, "BLE Connection closed"); |
| |
| // TODO: determine if connection closed is really to be treated as an error. |
| if (mOnError) |
| { |
| mOnError(this, mAppReqState, err, NULL); |
| } |
| } |
| |
| void ChipDeviceController::OnBLEPacketReceived(PacketBuffer * buffer) |
| { |
| if (mOnComplete.Response) |
| { |
| mOnComplete.Response(this, mAppReqState, buffer); |
| } |
| } |
| |
| } // namespace DeviceController |
| } // namespace chip |