| /* |
| * |
| * Copyright (c) 2016-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 Weave Binding and related classes. |
| * |
| */ |
| |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS |
| #endif // __STDC_FORMAT_MACROS |
| |
| #include <Weave/Core/WeaveCore.h> |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Support/WeaveFaultInjection.h> |
| #include <SystemLayer/SystemStats.h> |
| |
| namespace nl { |
| namespace Weave { |
| |
| /** |
| * @fn Binding::State Binding::GetState(void) const |
| * |
| * Retrieve the current state of the binding. |
| * |
| * @return The binding state. |
| */ |
| |
| /** |
| * @fn bool Binding::IsPreparing() const |
| * |
| * Returns true if the Binding is currently being prepared. |
| */ |
| |
| /** |
| * @fn bool Binding::IsReady() const |
| * |
| * Returns true if the Binding is in the Ready state. |
| */ |
| |
| /** |
| * @fn uint64_t Binding::GetPeerNodeId() const |
| * |
| * Retrieve the node id of the binding peer. |
| * |
| * Only valid once the binding object has been prepared. |
| * |
| * @return Weave node ID of the peer |
| */ |
| |
| /** |
| * @fn uint32_t Binding::GetKeyId() const |
| * |
| * Retrieve the id of the message encryption key to be used when encrypting messages to/from to the peer. |
| */ |
| |
| /** |
| * @fn uint8_t Binding::GetEncryptionType() const |
| * |
| * Retrieve the message encryption type to be used when encrypting messages to/from the peer. |
| */ |
| |
| /** |
| * @fn uint32_t Binding::GetDefaultResponseTimeout() const |
| * |
| * Get the default exchange response timeout to be used when communicating with the peer. |
| * |
| * @return Response timeout in ms. |
| */ |
| |
| /** |
| * @fn void Binding::SetDefaultResponseTimeout(uint32_t timeout) |
| * |
| * Set the default exchange response timeout to be used when communicating with the peer. |
| * |
| * @param[in] timeout The new response timeout in ms. |
| */ |
| |
| /** |
| * @fn const nl::Weave::WRMPConfig& Binding::GetDefaultWRMPConfig(void) const |
| * |
| * Get the default WRMP configuration to be used when communicating with the peer. |
| * |
| * @return A reference to a WRMPConfig structure containing |
| * the default configuration values. |
| */ |
| |
| /** |
| * @fn void Binding::SetDefaultWRMPConfig(const nl::Weave::WRMPConfig& aWRMPConfig) |
| * |
| * Set the default WRMP configuration to be used when communicating with the peer. |
| * |
| * @param[in] aWRMPConfig A reference to a WRMPConfig structure containing |
| * the new default configuration. |
| */ |
| |
| /** |
| * @fn Binding::EventCallback Binding::GetEventCallback() const |
| * |
| * Get the function that will be called when an API event occurs for the Binding. |
| * |
| * @return A pointer to the callback function. |
| */ |
| |
| /** |
| * @fn Binding::SetEventCallback(EventCallback aEventCallback) |
| * |
| * Set the application-defined function to be called when an API event occurs for the Binding. |
| * |
| * @param[in] aEventCallback A pointer to the callback function. |
| */ |
| |
| /** |
| * @fn void Binding::SetProtocolLayerCallback(EventCallback callback, void *state) |
| * |
| * Set an event callback function for protocol layer code using the Binding on behalf of an |
| * application. This function will be called in addition to the application-defined callback |
| * function when API events occur for the Binding. |
| * |
| * @param[in] callback A pointer to the callback function. |
| * @param[in] state A pointer to a state object that will be supplied to the |
| * protocol layer code when a protocol layer callback occurs. |
| */ |
| |
| /** |
| * @fn Binding::Configuration Binding::BeginConfiguration() |
| * |
| * Being the process of configuring the Binding. Applications must call BeginConfiguration() to |
| * configure the Binding prior to preparing it for communicating with the peer. |
| * |
| * @return A Binding::Configuration object that can be used to configure |
| * the binding. |
| */ |
| |
| /** |
| * @fn WEAVE_ERROR Binding::Configuration::PrepareBinding(void) |
| * |
| * Being the process of preparing the Binding for communication with the peer. |
| */ |
| |
| /** |
| * @fn WEAVE_ERROR Binding::Configuration::GetError(void) const |
| * |
| * Return any error that has occurred while configuring the Binding. |
| */ |
| |
| /** |
| * Reserve a reference to the binding object. |
| */ |
| void Binding::AddRef() |
| { |
| VerifyOrDie(mState != kState_NotAllocated); |
| VerifyOrDie(mRefCount > 0); |
| |
| ++mRefCount; |
| } |
| |
| /** |
| * Release a reference to the binding object. |
| * |
| * If there are no more references to the binding object, the binding is closed and freed. |
| */ |
| void Binding::Release() |
| { |
| VerifyOrDie(mState != kState_NotAllocated); |
| VerifyOrDie(mRefCount > 0); |
| |
| if (mRefCount > 1) |
| { |
| --mRefCount; |
| } |
| else |
| { |
| DoClose(); |
| mRefCount = 0; |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Freed", GetLogId(), mRefCount); |
| mExchangeManager->FreeBinding(this); |
| } |
| } |
| |
| /** |
| * Close the binding object and release a reference. |
| * |
| * When called, this method causes the binding to enter the Closed state. Any in-progress prepare actions |
| * for the binding are canceled and all external communications resources held by the binding are released. |
| * |
| * Calling Close() decrements the reference count associated with the binding, freeing the object if the |
| * reference count becomes zero. |
| */ |
| void Binding::Close(void) |
| { |
| VerifyOrDie(mState != kState_NotAllocated); |
| VerifyOrDie(mRefCount > 0); |
| |
| DoClose(); |
| Release(); |
| } |
| |
| /** |
| * Reset the binding back to an unconfigured state. |
| * |
| * When Reset() is called, any in-progress prepare actions for the binding are canceled and all external |
| * communications resources held by the binding are released. Reset() places the binding in the |
| * Unconfigured state, after which it may be configured and prepared again. |
| * |
| * Reset() does not alter the reference count of the binding. |
| */ |
| void Binding::Reset() |
| { |
| VerifyOrDie(mState != kState_NotAllocated); |
| VerifyOrDie(mRefCount > 0); |
| |
| DoReset(kState_NotConfigured); |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Reset", GetLogId(), mRefCount); |
| } |
| |
| /** |
| * Get a unique id for the binding. |
| */ |
| uint16_t Binding::GetLogId(void) const |
| { |
| return mExchangeManager->GetBindingLogId(this); |
| } |
| |
| /** |
| * Default handler for binding API events. |
| * |
| * Applications are required to call this method for any API events that they don't recognize or handle. |
| * Supplied parameters must be the same as those passed by the binding to the application's event handler |
| * function. |
| * |
| * @param[in] apAppState A pointer to application-defined state information associated with the binding. |
| * @param[in] aEvent Event ID passed by the event callback |
| * @param[in] aInParam Reference of input event parameters passed by the event callback |
| * @param[in] aOutParam Reference of output event parameters passed by the event callback |
| * |
| */ |
| void Binding::DefaultEventHandler(void *apAppState, EventType aEvent, const InEventParam& aInParam, OutEventParam& aOutParam) |
| { |
| // No actions required for current implementation |
| aOutParam.DefaultHandlerCalled = true; |
| } |
| |
| /** |
| * Initialize this Binding object |
| * |
| * @param[in] apAppState A pointer to some context which would be carried in event callback later |
| * @param[in] aEventCallback A function pointer to be used for event callback |
| * |
| */ |
| WEAVE_ERROR Binding::Init(void *apAppState, EventCallback aEventCallback) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| VerifyOrExit(aEventCallback != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| mState = kState_NotConfigured; |
| mRefCount = 1; |
| AppState = apAppState; |
| SetEventCallback(aEventCallback); |
| mProtocolLayerCallback = NULL; |
| mProtocolLayerState = NULL; |
| |
| ResetConfig(); |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Allocated", GetLogId(), mRefCount); |
| |
| #if DEBUG |
| // Verify that the application's event callback function correctly calls the default handler. |
| // |
| // NOTE: If your code receives WEAVE_ERROR_DEFAULT_EVENT_HANDLER_NOT_CALLED it means that the event hander |
| // function you supplied for a binding does not properly call Binding::DefaultEventHandler for unrecognized/ |
| // unhandled events. |
| // |
| { |
| InEventParam inParam; |
| OutEventParam outParam; |
| inParam.Clear(); |
| inParam.Source = this; |
| outParam.Clear(); |
| aEventCallback(apAppState, kEvent_DefaultCheck, inParam, outParam); |
| VerifyOrExit(outParam.DefaultHandlerCalled, err = WEAVE_ERROR_DEFAULT_EVENT_HANDLER_NOT_CALLED); |
| } |
| #endif |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| mState = kState_NotAllocated; |
| mRefCount = 0; |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Freed", GetLogId(), mRefCount); |
| } |
| WeaveLogFunctError(err); |
| return err; |
| } |
| |
| /** |
| * Reset the state of the binding, canceling any outstanding activities and releasing all external resources. |
| */ |
| void Binding::DoReset(State newState) |
| { |
| VerifyOrDie(mState != kState_NotAllocated); |
| |
| WeaveSecurityManager *sm = mExchangeManager->MessageLayer->SecurityMgr; |
| State origState = mState; |
| |
| // Temporarily enter the resetting state. This has the effect of suppressing any callbacks |
| // from lower layers that might result from the effort of resetting the binding. |
| mState = kState_Resetting; |
| |
| // Release any reservation held on the message encryption key. In the case of |
| // locally-initiated, non-shared session keys, this will result in the session |
| // being removed. |
| if (GetFlag(kFlag_KeyReserved)) |
| { |
| sm->ReleaseKey(mPeerNodeId, mKeyId); |
| } |
| |
| // If a session establishment was in progress, cancel it. |
| if (origState == kState_PreparingSecurity_EstablishSession) |
| { |
| sm->CancelSessionEstablishment(this); |
| } |
| |
| // Reset the configuration state of the binding. |
| ResetConfig(); |
| |
| // Advance to the new state. |
| mState = newState; |
| } |
| |
| /** |
| * Transition the binding to the Closed state if not already closed. |
| */ |
| void Binding::DoClose(void) |
| { |
| // If not already closed... |
| if (mState != kState_Closed) |
| { |
| // Clear pointers to application state/code to prevent any further use. |
| AppState = NULL; |
| SetEventCallback(NULL); |
| SetProtocolLayerCallback(NULL, NULL); |
| |
| // Reset the binding and enter the Closed state. |
| DoReset(kState_Closed); |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Closed", GetLogId(), mRefCount); |
| } |
| } |
| |
| /** |
| * Reset the configuration parameters to their default values. |
| */ |
| void Binding::ResetConfig() |
| { |
| mPeerNodeId = kNodeIdNotSpecified; |
| |
| mAddressingOption = kAddressing_NotSpecified; |
| mPeerPort = WEAVE_PORT; |
| mInterfaceId = INET_NULL_INTERFACEID; |
| |
| mTransportOption = kTransport_NotSpecified; |
| mDefaultResponseTimeoutMsec = 0; |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mDefaultWRMPConfig = gDefaultWRMPConfig; |
| #endif |
| |
| mSecurityOption = kSecurityOption_NotSpecified; |
| mKeyId = WeaveKeyId::kNone; |
| mEncType = kWeaveEncryptionType_None; |
| mAuthMode = kWeaveAuthMode_Unauthenticated; |
| |
| mFlags = 0; |
| } |
| |
| /** |
| * Request the application to configure and prepare the Binding. |
| * |
| * Protocol layer code can use this method on a Binding that has not been configured, or |
| * has failed, to trigger an event to the application (kEvent_PrepareRequested) requesting |
| * that it configure and prepare the binding for use. |
| * |
| * This method can only be called on Bindings in the NotConfigured or Failed states. |
| * |
| * If the application does not support on-demand configuration/preparation of Bindings, the |
| * method will fail with WEAVE_ERROR_NOT_IMPLEMENTED. |
| * |
| */ |
| WEAVE_ERROR Binding::RequestPrepare() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| InEventParam inParam; |
| OutEventParam outParam; |
| |
| // Ensure the binding doesn't get freed while we make calls to the application. |
| AddRef(); |
| |
| // Make sure the binding is in a state where preparing is possible. |
| VerifyOrExit(CanBePrepared(), err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| inParam.Clear(); |
| inParam.Source = this; |
| outParam.Clear(); |
| outParam.PrepareRequested.PrepareError = WEAVE_NO_ERROR; |
| |
| // Invoke the application to configure and prepare the binding. Note that this event |
| // is only ever delivered to the application, not the protocol layer. |
| mAppEventCallback(AppState, kEvent_PrepareRequested, inParam, outParam); |
| |
| // If the application didn't handle the PrepareRequested event then it doesn't support |
| // on-demand configuration/preparation so fail with an error. |
| VerifyOrExit(!outParam.DefaultHandlerCalled, err = WEAVE_ERROR_NOT_IMPLEMENTED); |
| |
| // Check for a preparation error returned by the app's event handler. Note that the application |
| // is not required to set an error value, since if preparation fails, and the error value is not |
| // set, then the code below will catch this and substitute WEAVE_ERROR_INCORRECT_STATE. |
| err = outParam.PrepareRequested.PrepareError; |
| SuccessOrExit(err); |
| |
| // If the application failed to fully configure the binding, fail with an error. |
| VerifyOrExit(mState != kState_NotConfigured && mState != kState_Configuring, err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| exit: |
| Release(); |
| WeaveLogFunctError(err); |
| return err; |
| } |
| |
| /** |
| * Conduct preparation for this Binding based on configurations supplied before this call. |
| * |
| * @return #WEAVE_NO_ERROR on success and an event callback will happen. Otherwise no event callback will happen. |
| */ |
| WEAVE_ERROR Binding::DoPrepare(WEAVE_ERROR configErr) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| // Immediately return an error, without changing the state of the Binding, if the Binding is not |
| // in the correct state. |
| if (kState_Configuring != mState) |
| { |
| return WEAVE_ERROR_INCORRECT_STATE; |
| } |
| |
| // Fail if an error occurred during configuration. |
| VerifyOrExit(WEAVE_NO_ERROR == configErr, err = configErr); |
| |
| // App must set peer node id |
| VerifyOrExit(kNodeIdNotSpecified != mPeerNodeId, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| // App must pick a transport option |
| VerifyOrExit(kTransport_NotSpecified != mTransportOption, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| // App must pick a security option |
| VerifyOrExit(kSecurityOption_NotSpecified != mSecurityOption, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| mState = kState_Preparing; |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Preparing", GetLogId(), mRefCount); |
| |
| // Start by preparing the peer address |
| PrepareAddress(); |
| |
| exit: |
| if (WEAVE_NO_ERROR != err) |
| { |
| HandleBindingFailed(err, false); |
| } |
| WeaveLogFunctError(err); |
| return err; |
| } |
| |
| /** |
| * Do any work necessary to determine the address of the peer in preparation for communication. |
| */ |
| void Binding::PrepareAddress() |
| { |
| mState = kState_PreparingAddress; |
| |
| // TODO FUTURE: Add support for hostname resolution |
| |
| // Default to using a Weave fabric address in the default subnet if an address was not specified. |
| if (kAddressing_NotSpecified == mAddressingOption) |
| { |
| mPeerAddress = mExchangeManager->FabricState->SelectNodeAddress(mPeerNodeId); |
| } |
| |
| // If requested, form a Weave fabric address for the peer in the configured subnet. |
| else if (kAddressing_WeaveFabric == mAddressingOption) |
| { |
| mPeerAddress = mExchangeManager->FabricState->SelectNodeAddress(mPeerNodeId, mPeerAddress.Subnet()); |
| } |
| |
| PrepareTransport(); |
| } |
| |
| /** |
| * Do any work necessary to determine to establish transport-level communication with the peer. |
| */ |
| void Binding::PrepareTransport() |
| { |
| mState = kState_PreparingTransport; |
| |
| // TODO FUTURE: Add support for TCP and existing connection |
| |
| PrepareSecurity(); |
| } |
| |
| /** |
| * Do any work necessary to establish communication security with the peer. |
| */ |
| void Binding::PrepareSecurity() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WeaveSecurityManager *sm = mExchangeManager->MessageLayer->SecurityMgr; |
| |
| mState = kState_PreparingSecurity; |
| |
| // Default encryption type, if not specified. |
| if (kSecurityOption_None != mSecurityOption && kWeaveEncryptionType_None == mEncType) |
| { |
| mEncType = kWeaveEncryptionType_AES128CTRSHA1; |
| } |
| |
| switch (mSecurityOption) |
| { |
| case kSecurityOption_CASESession: |
| case kSecurityOption_SharedCASESession: |
| { |
| IPAddress peerAddress; |
| uint16_t peerPort; |
| uint64_t terminatingNodeId; |
| const bool isSharedSession = (mSecurityOption == kSecurityOption_SharedCASESession); |
| |
| if (isSharedSession) |
| { |
| // This is also defined in Weave/Profiles/ServiceDirectory.h, but this is in Weave Core |
| // TODO: move this to a common location. |
| static const uint64_t kServiceEndpoint_CoreRouter = 0x18B4300200000012ull; |
| |
| const uint64_t fabricGlobalId = WeaveFabricIdToIPv6GlobalId(mExchangeManager->FabricState->FabricId); |
| peerAddress = IPAddress::MakeULA(fabricGlobalId, nl::Weave::kWeaveSubnetId_Service, |
| nl::Weave::WeaveNodeIdToIPv6InterfaceId(kServiceEndpoint_CoreRouter)); |
| peerPort = WEAVE_PORT; |
| terminatingNodeId = kServiceEndpoint_CoreRouter; |
| } |
| else |
| { |
| peerAddress = mPeerAddress; |
| peerPort = mPeerPort; |
| terminatingNodeId = kNodeIdNotSpecified; |
| } |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Initiating %sCASE session", |
| GetLogId(), mRefCount, isSharedSession ? "shared " : ""); |
| |
| mState = kState_PreparingSecurity_EstablishSession; |
| |
| // Call the security manager to initiate the CASE session. Note that security manager will call the |
| // OnSecureSessionReady function during this call if a shared session is requested and the session is |
| // already available. |
| err = sm->StartCASESession(NULL, mPeerNodeId, peerAddress, peerPort, mAuthMode, this, |
| OnSecureSessionReady, OnSecureSessionFailed, NULL, terminatingNodeId); |
| |
| // If the security manager is currently busy, wait for it to finish. When this happens, |
| // Binding::OnSecurityManagerAvailable() will be called, which will give the binding an opportunity |
| // to try again. |
| if (err == WEAVE_ERROR_SECURITY_MANAGER_BUSY) |
| { |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Security manager busy; waiting.", |
| GetLogId(), mRefCount); |
| |
| mState = kState_PreparingSecurity_WaitSecurityMgr; |
| err = WEAVE_NO_ERROR; |
| } |
| |
| SuccessOrExit(err); |
| } |
| break; |
| |
| case kSecurityOption_SpecificKey: |
| |
| // Add a reservation on the specified key. This reservation will be owned by the binding |
| // until it closes. |
| sm->ReserveKey(mPeerNodeId, mKeyId); |
| SetFlag(kFlag_KeyReserved); |
| |
| HandleBindingReady(); |
| break; |
| |
| case kSecurityOption_None: |
| // No further preparation needed. |
| HandleBindingReady(); |
| break; |
| |
| default: |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| } |
| |
| exit: |
| if (WEAVE_NO_ERROR != err) |
| { |
| HandleBindingFailed(err, true); |
| } |
| } |
| |
| /** |
| * Transition the Binding to the Ready state. |
| */ |
| void Binding::HandleBindingReady() |
| { |
| InEventParam inParam; |
| OutEventParam outParam; |
| |
| // Should never be called in anything other than a preparing state. |
| VerifyOrDie(IsPreparing()); |
| |
| // Transition to the Ready state. |
| mState = kState_Ready; |
| |
| { |
| char ipAddrStr[64]; |
| char intfStr[64]; |
| const char *transportStr; |
| mPeerAddress.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| nl::Inet::GetInterfaceName(mInterfaceId, intfStr, sizeof(intfStr)); |
| switch (mTransportOption) |
| { |
| case kTransport_UDP: |
| transportStr = "UDP"; |
| break; |
| case kTransport_UDP_WRM: |
| transportStr = "WRM"; |
| break; |
| case kTransport_TCP: |
| transportStr = "TCP"; // TODO FUTURE: Add id of connection |
| break; |
| case kTransport_ExistingConnection: |
| transportStr = "ExistingCon"; // TODO FUTURE: Add id of connection |
| break; |
| default: |
| transportStr = "Unknown"; |
| break; |
| } |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Ready, peer %016" PRIX64 " @ [%s]:%" PRId16 " (%s) via %s", |
| GetLogId(), mRefCount, mPeerNodeId, ipAddrStr, mPeerPort, |
| (mInterfaceId != INET_NULL_INTERFACEID) ? intfStr : "default", |
| transportStr); |
| } |
| |
| inParam.Clear(); |
| inParam.Source = this; |
| outParam.Clear(); |
| |
| // Prevent the application from freeing the Binding until we're done using it. |
| AddRef(); |
| |
| // Tell the application that the prepare operation succeeded and the binding is ready for use. |
| mAppEventCallback(AppState, kEvent_BindingReady, inParam, outParam); |
| |
| // If the Binding is still in the Ready state, and a protocol layer callback has been registered, |
| // tell the protocol layer that the Binding is ready for use. |
| if (mState == kState_Ready && mProtocolLayerCallback != NULL) |
| { |
| mProtocolLayerCallback(mProtocolLayerState, kEvent_BindingReady, inParam, outParam); |
| } |
| |
| Release(); |
| } |
| |
| /** |
| * Transition the Binding to the Failed state. |
| */ |
| void Binding::HandleBindingFailed(WEAVE_ERROR err, bool raiseEvents) // TODO: add status report information. |
| { |
| InEventParam inParam; |
| OutEventParam outParam; |
| EventType eventType; |
| |
| inParam.Clear(); |
| inParam.Source = this; |
| outParam.Clear(); |
| |
| if (IsPreparing()) |
| { |
| inParam.PrepareFailed.Reason = err; |
| eventType = kEvent_PrepareFailed; |
| } |
| else |
| { |
| inParam.BindingFailed.Reason = err; |
| eventType = kEvent_BindingFailed; |
| } |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): %s: peer %" PRIX64 ", %s", |
| GetLogId(), mRefCount, |
| (eventType == kEvent_BindingFailed) ? "Binding FAILED" : "Prepare FAILED", |
| mPeerNodeId, ErrorStr(err)); |
| |
| // Reset the binding and enter the Failed state. |
| DoReset(kState_Failed); |
| |
| // Prevent the application from freeing the Binding until we're done using it. |
| AddRef(); |
| |
| // If requested, deliver the failure events to the application and protocol layer. |
| if (raiseEvents) |
| { |
| mAppEventCallback(AppState, eventType, inParam, outParam); |
| if (mProtocolLayerCallback != NULL) |
| { |
| mProtocolLayerCallback(mProtocolLayerState, eventType, inParam, outParam); |
| } |
| } |
| |
| Release(); |
| } |
| |
| /** |
| * Invoked when security session establishment has completed successfully. |
| */ |
| void Binding::OnSecureSessionReady(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, uint16_t keyId, uint64_t peerNodeId, uint8_t encType) |
| { |
| Binding *_this = (Binding *)reqState; |
| |
| // Verify the state of the binding. |
| VerifyOrDie(_this->mState == kState_PreparingSecurity_EstablishSession); |
| |
| // Save the session key id and encryption type. |
| _this->mKeyId = keyId; |
| _this->mEncType = encType; |
| |
| // Remember that the key must be released when the binding closes. |
| _this->SetFlag(kFlag_KeyReserved); |
| |
| // Tell the application that the binding is ready. |
| _this->HandleBindingReady(); |
| } |
| |
| /** |
| * Invoked when security session establishment fails. |
| */ |
| void Binding::OnSecureSessionFailed(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, |
| WEAVE_ERROR localErr, uint64_t peerNodeId, Profiles::StatusReporting::StatusReport *statusReport) |
| { |
| Binding *_this = (Binding *)reqState; |
| |
| // Verify the state of the binding. |
| VerifyOrDie(_this->mState == kState_PreparingSecurity_EstablishSession); |
| |
| // Tell the application that the binding has failed. |
| _this->HandleBindingFailed(localErr, true); |
| } |
| |
| /** |
| * Invoked when a message encryption key has been rejected by a peer (via a KeyError), or a key has |
| * otherwise become invalid (e.g. by ending a session). |
| */ |
| void Binding::OnKeyFailed(uint64_t peerNodeId, uint32_t keyId, WEAVE_ERROR keyErr) |
| { |
| // NOTE: This method is called for any and all key errors that occur system-wide. Thus this code |
| // must filter for errors that apply to the current binding. |
| |
| // Ignore the key error if the binding is not in the Ready state or one of the preparing states. |
| VerifyOrExit(IsPreparing() || mState == kState_Ready, /* no-op */); |
| |
| // Ignore the key error if it is not in relation to the specified peer node. |
| VerifyOrExit(peerNodeId == mPeerNodeId, /* no-op */); |
| |
| // Ignore the key error if the binding is in the Ready state and the failed key id does |
| // not match the key id associated with the binding. |
| VerifyOrExit(mState != kState_Ready || keyId == mKeyId, /* no-op */); |
| |
| // Fail the binding. |
| HandleBindingFailed(keyErr, true); |
| |
| exit: |
| return; |
| } |
| |
| /** |
| * Invoked when the security manager becomes available for initiating new sessions. |
| */ |
| void Binding::OnSecurityManagerAvailable() |
| { |
| // NOTE: This method is called for all binding objects any time the security manager becomes |
| // available. Thus this method must filter the notification based on the state of the binding. |
| |
| // If the binding is waiting for the security manager, retry preparing security. |
| if (mState == kState_PreparingSecurity_WaitSecurityMgr) |
| { |
| PrepareSecurity(); |
| } |
| } |
| |
| /** |
| * Re-configure an existing Exchange Context to adjust the response timeout. |
| * |
| * @param[in] apExchangeContext A pointer to an Exchange Context object to be re-configured |
| * |
| */ |
| WEAVE_ERROR Binding::AdjustResponseTimeout(nl::Weave::ExchangeContext *apExchangeContext) const |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| // Binding must be in the Ready state. |
| VerifyOrExit(kState_Ready == mState, err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| // If a default response timeout has been configured, adjust the response timeout value in |
| // the exchange to match. |
| if (mDefaultResponseTimeoutMsec) |
| { |
| apExchangeContext->ResponseTimeout = mDefaultResponseTimeoutMsec; |
| } |
| |
| exit: |
| WeaveLogFunctError(err); |
| return err; |
| } |
| |
| /** |
| * Determine if a particular incoming message is from the configured peer and is suitably authenticated. |
| * |
| * This method confirms that the message in question originated from the peer node of the binding and |
| * that the encryption key and type used to encrypt the message matches those configured in the binding. |
| * For bindings configured without the use of security, the method confirms that the incoming message is |
| * NOT encrypted. |
| * |
| * This method is intended to be used in protocols such as WDM where peers can spontaneously initiate |
| * exchanges back to the local node after an initial exchange from the node to the peer. In such cases, |
| * the method allows the local node to confirm that the incoming unsolicited message was sent by the |
| * associated peer. (Of course, for Bindings configured without the use of message encryption, this |
| * assertion provides no value from a security perspective. It merely confirms that the sender node |
| * id in the received message matches the peer's node id.) |
| * |
| * Note that if the binding is not in the Ready state, this method will always return false. |
| * |
| * @param[in] msgInfo The Weave message information for the incoming message. |
| * |
| * @return True if the message is authentically from the peer. |
| */ |
| bool Binding::IsAuthenticMessageFromPeer(const nl::Weave::WeaveMessageHeader *msgInfo) |
| { |
| if (mState != kState_Ready) |
| return false; |
| |
| if (msgInfo->SourceNodeId != mPeerNodeId) |
| return false; |
| |
| if (msgInfo->EncryptionType != mEncType) |
| return false; |
| |
| if (mEncType != kWeaveEncryptionType_None && !WeaveKeyId::IsSameKeyOrGroup(msgInfo->KeyId, mKeyId)) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * Get the max Weave payload size that can fit inside the supplied PacketBuffer. |
| * |
| * For UDP, including UDP with WRM, the maximum payload size returned will |
| * ensure the resulting Weave message will not overflow the configured UDP MTU. |
| * |
| * Additionally, this method will ensure the Weave payload will not overflow |
| * the supplied PacketBuffer. |
| * |
| * @param[in] msgBuf A pointer to the PacketBuffer to which the message |
| * payload will be written. |
| * |
| * @return the max Weave payload size. |
| */ |
| uint32_t Binding::GetMaxWeavePayloadSize(const System::PacketBuffer *msgBuf) |
| { |
| // Constrain the max Weave payload size by the UDP MTU if we are using UDP. |
| // TODO: Eventually, we may configure a custom UDP MTU size on the binding |
| // instead of using the default value directly. |
| bool isUDP = (mTransportOption == kTransport_UDP || mTransportOption == kTransport_UDP_WRM); |
| return WeaveMessageLayer::GetMaxWeavePayloadSize(msgBuf, isUDP, WEAVE_CONFIG_DEFAULT_UDP_MTU_SIZE); |
| } |
| |
| /** |
| * Allocate a new Exchange Context for communicating with the peer that is the target of the binding. |
| * |
| * @param[out] ec A reference to a pointer that will receive the newly allocated |
| * Exchange Context object. The pointer will be set to NULL in |
| * the event that the method fails. |
| * |
| * @retval #WEAVE_NO_ERROR If the exchange context was successfully allocated. |
| * |
| * @retval #WEAVE_ERROR_NO_MEMORY If no memory was available to allocate the exchange context. |
| * |
| * @retval #WEAVE_ERROR_INCORRECT_STATE If the binding is not in the Ready state. |
| * |
| * @retval other Other errors related to configuring the exchange context based |
| * on the configuration of the binding. |
| */ |
| WEAVE_ERROR Binding::NewExchangeContext(nl::Weave::ExchangeContext *& ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| ec = NULL; |
| |
| // Fail if the binding is not in the Ready state. |
| VerifyOrExit(kState_Ready == mState, err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| // Attempt to allocate a new exchange context. |
| ec = mExchangeManager->NewContext(mPeerNodeId, mPeerAddress, mPeerPort, mInterfaceId, NULL); |
| VerifyOrExit(NULL != ec, err = WEAVE_ERROR_NO_MEMORY); |
| |
| // TODO FUTURE: Add support for connection-based exchanges |
| |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| |
| // Set the default WRMP configuration in the new exchange. |
| ec->mWRMPConfig = mDefaultWRMPConfig; |
| |
| // If Weave reliable messaging was expressly requested as a transport... |
| if (mTransportOption == kTransport_UDP_WRM) |
| { |
| // Enable the auto-request ACK feature in the exchange so that all outgoing messages |
| // include a request for acknowledgment. |
| ec->SetAutoRequestAck(true); |
| } |
| |
| #endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| |
| // If message encryption is enabled... |
| if (mSecurityOption != kSecurityOption_None) |
| { |
| uint32_t keyId; |
| |
| // If the key id specifies a logical group key (e.g. the "current" rotating group key), resolve it to |
| // the id for a specific key. |
| err = mExchangeManager->FabricState->GroupKeyStore->GetCurrentAppKeyId(mKeyId, keyId); |
| SuccessOrExit(err); |
| |
| // Configure the exchange context with the selected key id and encryption type. |
| ec->KeyId = keyId; |
| ec->EncryptionType = mEncType; |
| |
| // Add a reservation for the key. |
| mExchangeManager->MessageLayer->SecurityMgr->ReserveKey(mPeerNodeId, keyId); |
| |
| // Arrange for the exchange context to automatically release the key when it is freed. |
| ec->SetAutoReleaseKey(true); |
| } |
| |
| err = AdjustResponseTimeout(ec); |
| SuccessOrExit(err); |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && ec != NULL) |
| { |
| ec->Close(); |
| ec = NULL; |
| } |
| WeaveLogFunctError(err); |
| return err; |
| } |
| |
| /** |
| * Construct a new binding configuration object. |
| * |
| * @param[in] aBinding A reference to the Binding to be configured. |
| */ |
| Binding::Configuration::Configuration(Binding& aBinding) |
| : mBinding(aBinding) |
| { |
| if (mBinding.CanBePrepared()) |
| { |
| mBinding.mState = kState_Configuring; |
| mError = WEAVE_NO_ERROR; |
| |
| WeaveLogDetail(ExchangeManager, "Binding[%" PRIu8 "] (%" PRIu16 "): Configuring", mBinding.GetLogId(), mBinding.mRefCount); |
| } |
| else |
| { |
| mError = WEAVE_ERROR_INCORRECT_STATE; |
| } |
| } |
| |
| /** |
| * Configure the binding to communicate with a specific Weave node id. |
| * |
| * @param[in] aPeerNodeId Node id of the peer node. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Target_NodeId(uint64_t aPeerNodeId) |
| { |
| mBinding.mPeerNodeId = aPeerNodeId; |
| return *this; |
| } |
| |
| /** |
| * Configure the binding to communicate with a specific Weave service endpoint. |
| * |
| * If not otherwise configured, the peer address is set to the Weave fabric address of the service endpoint. |
| * |
| * @param[in] serviceEndpointId The node id of the service endpoint with which communication will take place. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Target_ServiceEndpoint(uint64_t serviceEndpointId) |
| { |
| Target_NodeId(serviceEndpointId); |
| if (mBinding.mAddressingOption == Binding::kAddressing_NotSpecified) |
| { |
| TargetAddress_WeaveService(); |
| } |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, use the specific IP address, port and network interface. |
| * |
| * @param[in] aPeerAddress IP address for the peer |
| * @param[in] aPeerPort Remote port |
| * @param[in] aInterfaceId The ID of local network interface to use for communication |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::TargetAddress_IP(const nl::Inet::IPAddress aPeerAddress, const uint16_t aPeerPort, const InterfaceId aInterfaceId) |
| { |
| mBinding.mAddressingOption = Binding::kAddressing_UnicastIP; |
| mBinding.mPeerAddress = aPeerAddress; |
| mBinding.mPeerPort = (aPeerPort != 0) ? aPeerPort : WEAVE_PORT; |
| mBinding.mInterfaceId = aInterfaceId; |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, use a Weave service fabric address derived from the peer's node id. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::TargetAddress_WeaveService() |
| { |
| return TargetAddress_WeaveFabric(nl::Weave::kWeaveSubnetId_Service); |
| } |
| |
| /** |
| * When communicating with the peer, use a Weave fabric address derived from the peer's node id and a specified subnet. |
| * |
| * @param[in] aSubnetId The subnet id to be used in forming the Weave fabric address of the peer. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::TargetAddress_WeaveFabric(uint16_t aSubnetId) |
| { |
| mBinding.mAddressingOption = kAddressing_WeaveFabric; |
| mBinding.mPeerAddress = IPAddress::MakeULA(0, aSubnetId, 0); // Save the subnet in the peer address field. |
| return *this; |
| } |
| |
| /** |
| * Use TCP to communicate with the peer. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Transport_TCP() |
| { |
| mError = WEAVE_ERROR_NOT_IMPLEMENTED; |
| return *this; |
| } |
| |
| /** |
| * Use UDP to communicate with the peer. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Transport_UDP() |
| { |
| mBinding.mTransportOption = kTransport_UDP; |
| return *this; |
| } |
| |
| /** |
| * Use the Weave Reliable Messaging protocol when communicating with the peer. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Transport_UDP_WRM() |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mBinding.mTransportOption = kTransport_UDP_WRM; |
| #else // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mError = WEAVE_ERROR_NOT_IMPLEMENTED; |
| #endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| return *this; |
| } |
| |
| /** |
| * Set the default WRMP configuration for exchange contexts created from this Binding object. |
| * |
| * @param[in] aWRMPConfig A reference to the new default WRMP configuration. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Transport_DefaultWRMPConfig(const nl::Weave::WRMPConfig& aWRMPConfig) |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mBinding.mDefaultWRMPConfig = aWRMPConfig; |
| #else // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| mError = WEAVE_ERROR_NOT_IMPLEMENTED; |
| #endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| return *this; |
| } |
| |
| /** |
| * Use an existing Weave connection to communicate with the peer. |
| */ |
| Binding::Configuration& Binding::Configuration::Transport_ExistingConnection(WeaveConnection *) |
| { |
| mError = WEAVE_ERROR_NOT_IMPLEMENTED; |
| return *this; |
| } |
| |
| /** |
| * Set default response timeout for exchange contexts created from this Binding object |
| * |
| * @param[in] aResponseTimeoutMsec The default response time, in ms. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Exchange_ResponseTimeoutMsec(uint32_t aResponseTimeoutMsec) |
| { |
| mBinding.mDefaultResponseTimeoutMsec = aResponseTimeoutMsec; |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive unencrypted (i.e. unsecured) messages. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_None() |
| { |
| mBinding.mSecurityOption = kSecurityOption_None; |
| mBinding.mKeyId = WeaveKeyId::kNone; |
| mBinding.mAuthMode = kWeaveAuthMode_Unauthenticated; |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted using a CASE session key |
| * established with the peer node. |
| * |
| * If the necessary session is not available, it will be established automatically as part of |
| * preparing the binding. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_CASESession(void) |
| { |
| mBinding.mSecurityOption = kSecurityOption_CASESession; |
| mBinding.mKeyId = WeaveKeyId::kNone; |
| mBinding.mAuthMode = kWeaveAuthMode_CASE_AnyCert; |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted using a shared CASE |
| * session key established with the Nest core router. |
| * |
| * If the necessary session is not available, it will be established automatically as part of |
| * preparing the binding. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_SharedCASESession(void) |
| { |
| mBinding.mSecurityOption = kSecurityOption_SharedCASESession; |
| mBinding.mKeyId = WeaveKeyId::kNone; |
| mBinding.mAuthMode = kWeaveAuthMode_CASE_ServiceEndPoint; |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted using a shared CASE |
| * session key established with a specified router node. |
| * |
| * If the necessary session is not available, it will be established automatically as part of |
| * preparing the binding. |
| * |
| * @param[in] aRouterNodeId The Weave node ID of the router with which shared CASE |
| * session should be established. |
| * |
| * @return A reference to the binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_SharedCASESession(uint64_t aRouterNodeId) |
| { |
| // This is also defined in Weave/Profiles/ServiceDirectory.h, but this is in Weave Core |
| // TODO: move this elsewhere. |
| static const uint64_t kServiceEndpoint_CoreRouter = 0x18B4300200000012ull; |
| |
| // TODO: generalize this |
| // Only support the router to be Core Router in Nest service |
| VerifyOrExit(kServiceEndpoint_CoreRouter == aRouterNodeId, mError = WEAVE_ERROR_NOT_IMPLEMENTED); |
| |
| Security_SharedCASESession(); |
| |
| exit: |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted using a specified key. |
| * |
| * @param[in] aKeyId The id of the encryption key. The specified key must be |
| * suitable for Weave message encryption. |
| * |
| * @return A reference to the Binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_Key(uint32_t aKeyId) |
| { |
| if (WeaveKeyId::IsMessageEncryptionKeyId(aKeyId)) |
| { |
| mBinding.mSecurityOption = kSecurityOption_SpecificKey; |
| if (!WeaveKeyId::IsAppRotatingKey(aKeyId)) |
| mBinding.mKeyId = aKeyId; |
| else |
| mBinding.mKeyId = WeaveKeyId::ConvertToCurrentAppKeyId(aKeyId); |
| mBinding.mAuthMode = kWeaveAuthMode_NotSpecified; |
| } |
| else |
| { |
| mError = WEAVE_ERROR_INVALID_KEY_ID; |
| } |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted for a specified |
| * Weave Application Group. |
| * |
| * @param[in] aAppGroupGlobalId The global id of the application group for which messages should |
| * be encrypted. |
| * @param[in] aRootKeyId The root key used to derive encryption keys for the specified |
| * Weave Application Group. |
| * @param[in] aUseRotatingKey True if the Weave Application Group uses rotating message keys. |
| * |
| * @return A reference to the Binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_AppGroupKey(uint32_t aAppGroupGlobalId, uint32_t aRootKeyId, bool aUseRotatingKey) |
| { |
| if (mError == WEAVE_NO_ERROR) |
| { |
| #if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC |
| mError = mBinding.mExchangeManager->FabricState->GetMsgEncKeyIdForAppGroup(aAppGroupGlobalId, aRootKeyId, aUseRotatingKey, mBinding.mKeyId); |
| if (mError == WEAVE_NO_ERROR) |
| { |
| mBinding.mSecurityOption = kSecurityOption_SpecificKey; |
| mBinding.mAuthMode = GroupKeyAuthMode(mBinding.mKeyId); |
| } |
| #else |
| mError = WEAVE_ERROR_UNSUPPORTED_WEAVE_FEATURE; |
| #endif |
| } |
| return *this; |
| } |
| |
| /** |
| * When communicating with the peer, send and receive messages encrypted using the specified message encryption type. |
| * |
| * @param[in] aEncType The Weave message encryption type. |
| * |
| * @return A reference to the Binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_EncryptionType(uint8_t aEncType) |
| { |
| mBinding.mEncType = aEncType; |
| return *this; |
| } |
| |
| /** |
| * Set the requested authentication mode to be used to authenticate the peer. |
| * |
| * @param[in] aAuthMode The requested authentication mode. |
| * |
| * @return A reference to the Binding object. |
| */ |
| Binding::Configuration& Binding::Configuration::Security_AuthenticationMode(WeaveAuthMode aAuthMode) |
| { |
| mBinding.mAuthMode = aAuthMode; |
| return *this; |
| } |
| |
| /** |
| * Configure the binding to allow communication with the sender of a received message. |
| * |
| * @param[in] apMsgHeader Message information structure associated with the received message. |
| * @param[in] apConnection The connection over which the message was received; or NULL if the message |
| * was not received via a connection. |
| * @param[in] apPktInfo Packet information for the received message. |
| * |
| */ |
| Binding::Configuration& Binding::Configuration::ConfigureFromMessage( |
| const nl::Weave::WeaveMessageHeader *apMsgHeader, |
| const nl::Inet::IPPacketInfo *apPktInfo, |
| WeaveConnection *apConnection) |
| { |
| mBinding.mPeerNodeId = apMsgHeader->SourceNodeId; |
| |
| // Configure the outgoing interface only if the received message is from a |
| // link-local address because we need to specify the interface when we are |
| // sending to a link local address. Otherwise, defer to the routing logic |
| // to choose the outgoing interface. |
| TargetAddress_IP(apPktInfo->SrcAddress, apPktInfo->SrcPort, |
| apPktInfo->SrcAddress.IsIPv6LinkLocal() ? apPktInfo->Interface : INET_NULL_INTERFACEID); |
| |
| if (apConnection != NULL) |
| { |
| Transport_ExistingConnection(apConnection); |
| } |
| else if (apMsgHeader->Flags & kWeaveMessageFlag_PeerRequestedAck) |
| { |
| #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| Transport_UDP_WRM(); |
| #else |
| mError = WEAVE_ERROR_NOT_IMPLEMENTED; |
| #endif // #if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING |
| } |
| else |
| { |
| Transport_UDP(); |
| } |
| |
| if (apMsgHeader->KeyId == WeaveKeyId::kNone) |
| { |
| Security_None(); |
| } |
| else |
| { |
| Security_Key(apMsgHeader->KeyId); |
| Security_EncryptionType(apMsgHeader->EncryptionType); |
| } |
| |
| return *this; |
| } |
| |
| }; // Weave |
| }; // nl |