diff --git a/configure.ac b/configure.ac index 147df1ddf..54d8eaffc 100644 --- a/configure.ac +++ b/configure.ac @@ -659,36 +659,68 @@ AC_MSG_RESULT(${enable_builtin_mbedtls}) AM_CONDITIONAL([OPENTHREAD_ENABLE_BUILTIN_MBEDTLS], [test "${enable_builtin_mbedtls}" = "yes"]) # -# Thread TMF Proxy +# Thread UDP Proxy # -AC_MSG_CHECKING([whether to enable TMF proxy]) -AC_ARG_ENABLE(tmf_proxy, - [AS_HELP_STRING([--enable-tmf-proxy],[Enable TMF proxy support @<:@default=no@:>@.])], +AC_MSG_CHECKING([whether to enable UDP proxy]) +AC_ARG_ENABLE(udp_proxy, + [AS_HELP_STRING([--enable-udp-proxy], [Enable UDP proxy support @<:@default=no@:>@.])], [ case "${enableval}" in no|yes) - enable_tmf_proxy=${enableval} + enable_udp_proxy=${enableval} ;; *) - AC_MSG_ERROR([Invalid value ${enable_tmf_proxy} for --enable-tmf-proxy]) + AC_MSG_ERROR([Invalid value ${enable_udp_proxy} for --enable-udp-proxy]) ;; esac ], - [enable_tmf_proxy=no]) + [enable_udp_proxy=no]) -if test "$enable_tmf_proxy" = "yes"; then - OPENTHREAD_ENABLE_TMF_PROXY=1 +if test "$enable_udp_proxy" = "yes"; then + OPENTHREAD_ENABLE_UDP_PROXY=1 else - OPENTHREAD_ENABLE_TMF_PROXY=0 + OPENTHREAD_ENABLE_UDP_PROXY=0 fi -AC_MSG_RESULT(${enable_tmf_proxy}) -AC_SUBST(OPENTHREAD_ENABLE_TMF_PROXY) -AM_CONDITIONAL([OPENTHREAD_ENABLE_TMF_PROXY], [test "${enable_tmf_proxy}" = "yes"]) -AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_TMF_PROXY],[${OPENTHREAD_ENABLE_TMF_PROXY}],[Define to 1 to enable the TMF proxy feature.]) +AC_MSG_RESULT(${enable_udp_proxy}) +AC_SUBST(OPENTHREAD_ENABLE_UDP_PROXY) +AM_CONDITIONAL([OPENTHREAD_ENABLE_UDP_PROXY], [test "${enable_udp_proxy}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_UDP_PROXY], [${OPENTHREAD_ENABLE_UDP_PROXY}], [Define to 1 to enable the UDP proxy feature.]) + +# +# Thread Border Agent +# + +AC_MSG_CHECKING([whether to enable border agent]) +AC_ARG_ENABLE(border_agent, + [AS_HELP_STRING([--enable-border-agent], [Enable border agent support @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_border_agent=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enable_border_agent} for --enable-border-agent]) + ;; + esac + ], + [enable_border_agent=no]) + +if test "${enable_border_agent}" = "yes"; then + OPENTHREAD_ENABLE_BORDER_AGENT=1 +else + OPENTHREAD_ENABLE_BORDER_AGENT=0 +fi + +AC_MSG_RESULT(${enable_border_agent}) +AC_SUBST(OPENTHREAD_ENABLE_BORDER_AGENT) +AM_CONDITIONAL([OPENTHREAD_ENABLE_BORDER_AGENT], [test "${enable_border_agent}" = "yes"]) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_BORDER_AGENT], [${OPENTHREAD_ENABLE_BORDER_AGENT}], [Define to 1 to enable the border agent feature.]) # # Thread Network Diagnostic for MTD @@ -786,7 +818,7 @@ AC_SUBST(OPENTHREAD_ENABLE_JOINER) AM_CONDITIONAL([OPENTHREAD_ENABLE_JOINER], [test "${enable_joiner}" = "yes"]) AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_JOINER],[${OPENTHREAD_ENABLE_JOINER}],[Define to 1 to enable the joiner role.]) -if test "${enable_commissioner}" = "yes" -o "${enable_joiner}" = "yes"; then +if test "${enable_commissioner}" = "yes" -o "${enable_joiner}" = "yes" -o "${enable_border_agent}" = "yes"; then enable_dtls="yes" OPENTHREAD_ENABLE_DTLS=1 else @@ -1703,7 +1735,7 @@ AC_MSG_NOTICE([ OpenThread Multiple Instances support : ${enable_multiple_instances} OpenThread MTD Network Diagnostic support : ${enable_mtd_network_diagnostic} OpenThread builtin mbedtls support : ${enable_builtin_mbedtls} - OpenThread TMF Proxy support : ${enable_tmf_proxy} + OpenThread UDP Proxy support : ${enable_udp_proxy} OpenThread Commissioner support : ${enable_commissioner} OpenThread Joiner support : ${enable_joiner} OpenThread DTLS support : ${enable_dtls} @@ -1720,6 +1752,7 @@ AC_MSG_NOTICE([ OpenThread DNS Client support : ${enable_dns_client} OpenThread Application CoAP support : ${enable_application_coap} OpenThread Raw Link-Layer support : ${enable_raw_link_api} + OpenThread Border Agent support : ${enable_border_agent} OpenThread Border Router support : ${enable_border_router} OpenThread Service support : ${enable_service} OpenThread examples : ${OPENTHREAD_EXAMPLES} diff --git a/examples/Makefile-posix b/examples/Makefile-posix index 957a7814f..5436ea83b 100644 --- a/examples/Makefile-posix +++ b/examples/Makefile-posix @@ -46,6 +46,7 @@ BuildJobs ?= 10 configure_OPTIONS = \ --enable-application-coap \ + --enable-border-agent \ --enable-border-router \ --enable-cert-log \ --enable-child-supervision \ @@ -63,7 +64,7 @@ configure_OPTIONS = \ --enable-ncp-app=all \ --enable-raw-link-api \ --enable-service \ - --enable-tmf-proxy \ + --enable-udp-proxy \ --with-examples=posix \ --with-ncp-bus=uart \ $(NULL) diff --git a/examples/common-switches.mk b/examples/common-switches.mk index bda56631d..0f2ade320 100644 --- a/examples/common-switches.mk +++ b/examples/common-switches.mk @@ -26,6 +26,10 @@ # POSSIBILITY OF SUCH DAMAGE. # +ifeq ($(BORDER_AGENT),1) +configure_OPTIONS += --enable-border-agent +endif + ifeq ($(BORDER_ROUTER),1) configure_OPTIONS += --enable-border-router endif @@ -95,8 +99,8 @@ ifeq ($(SERVICE),1) configure_OPTIONS += --enable-service endif -ifeq ($(TMF_PROXY),1) -configure_OPTIONS += --enable-tmf-proxy +ifeq ($(UDP_PROXY),1) +configure_OPTIONS += --enable-udp-proxy endif ifeq ($(DEBUG_UART),1) diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index c3f897a48..8d23ae2bf 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3440,7 +3440,7 @@ otThreadErrorToString( switch (aError) { case OT_ERROR_NONE: - retval = "None"; + retval = "OK"; break; case OT_ERROR_FAILED: diff --git a/include/openthread/Makefile.am b/include/openthread/Makefile.am index c07de5a10..737c90882 100644 --- a/include/openthread/Makefile.am +++ b/include/openthread/Makefile.am @@ -78,7 +78,6 @@ openthread_headers = \ tasklet.h \ thread.h \ thread_ftd.h \ - tmf_proxy.h \ types.h \ udp.h \ $(NULL) diff --git a/include/openthread/coap.h b/include/openthread/coap.h index ba77634bc..dd3c335df 100644 --- a/include/openthread/coap.h +++ b/include/openthread/coap.h @@ -59,6 +59,8 @@ extern "C" { #define OT_DEFAULT_COAP_PORT 5683 ///< Default CoAP port, as specified in RFC 7252 +#define OT_COAP_MAX_TOKEN_LENGTH 8 ///< Max token length as specified (RFC 7252). + /** * CoAP Type values. * diff --git a/include/openthread/tmf_proxy.h b/include/openthread/tmf_proxy.h deleted file mode 100644 index 92b1eea20..000000000 --- a/include/openthread/tmf_proxy.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * @brief - * This file includes the OpenThread API for TMF Proxy feature. - */ - -#ifndef OPENTHREAD_TMF_PROXY_H_ -#define OPENTHREAD_TMF_PROXY_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @addtogroup api-tmf-proxy - * - * @brief - * This module includes functions for TMF proxy feature. - * - * The functions in this module are available when tmf-proxy feature (`OPENTHREAD_ENABLE_TMF_PROXY`) is enabled. - * - * @{ - * - */ - -/** - * This function pointer is called when a TMF packet for host is received. - * - * @param[in] aMessage A pointer to the CoAP Message. - * @param[in] aContext A pointer to application-specific context. - * - */ -typedef void (*otTmfProxyStreamHandler)(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext); - -/** - * Start the TMF proxy. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aHandler A pointer to a function called to deliver TMF packet to host. - * @param[in] aContext A pointer to application-specific context. - * - * @retval OT_ERROR_NONE Successfully started the TMF proxy. - * @retval OT_ERROR_ALREADY Border agent proxy has been started before. - * - */ -otError otTmfProxyStart(otInstance *aInstance, otTmfProxyStreamHandler aHandler, void *aContext); - -/** - * Stop the TMF proxy. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @retval OT_ERROR_NONE Successfully stopped the TMF proxy. - * @retval OT_ERROR_ALREADY Border agent proxy is already stopped. - * - */ -otError otTmfProxyStop(otInstance *aInstance); - -/** - * Send packet through TMF proxy. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aMessage A pointer to the CoAP Message. - * @param[in] aLocator Rloc of destination. - * @param[in] aPort Port of destination. - * - * @retval OT_ERROR_NONE Successfully send the message. - * @retval OT_ERROR_INVALID_STATE Border agent proxy is not started. - * - * @warning No matter the call success or fail, the message is freed. - * - */ -otError otTmfProxySend(otInstance *aInstance, otMessage *aMessage, uint16_t aLocator, uint16_t aPort); - -/** - * Get the TMF proxy status (enabled/disabled) - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @returns The TMF proxy status (true if enabled, false otherwise). - */ -bool otTmfProxyIsEnabled(otInstance *aInstance); - -/** - * @} - * - */ - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // OPENTHREAD_TMF_PROXY_H_ diff --git a/include/openthread/types.h b/include/openthread/types.h index f1cc4dfe4..60dcfc642 100644 --- a/include/openthread/types.h +++ b/include/openthread/types.h @@ -1117,7 +1117,8 @@ typedef struct otNetifMulticastAddress * */ typedef enum otNetifInterfaceId { - OT_NETIF_INTERFACE_ID_THREAD = 1, ///< The Thread Network interface ID. + OT_NETIF_INTERFACE_ID_HOST = -1, ///< The interface ID telling packets received by host side interfaces. + OT_NETIF_INTERFACE_ID_THREAD = 1, ///< The Thread Network interface ID. } otNetifInterfaceId; /** diff --git a/include/openthread/udp.h b/include/openthread/udp.h index 09af731d9..e98f1ccd6 100644 --- a/include/openthread/udp.h +++ b/include/openthread/udp.h @@ -173,6 +173,67 @@ otError otUdpConnect(otUdpSocket *aSocket, otSockAddr *aSockName); */ otError otUdpSend(otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo); +/** + * @} + * + */ + +/** + * @addtogroup api-udp-proxy + * + * @brief + * This module includes functions for UDP proxy feature. + * + * The functions in this module are available when udp-proxy feature (`OPENTHREAD_ENABLE_UDP_PROXY`) is enabled. + * + * @{ + * + */ + +/** + * This function pointer delivers the UDP packet to host and host should send the packet through its own network stack. + * + * @param[in] aMessage A pointer to the UDP Message. + * @param[in] aPeerPort The destination UDP port. + * @param[in] aPeerAddr A pointer to the destination IPv6 address. + * @param[in] aSockPort The source UDP port. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (*otUdpProxySender)(otMessage * aMessage, + uint16_t aPeerPort, + otIp6Address *aPeerAddr, + uint16_t aSockPort, + void * aContext); + +/** + * Set UDP proxy callback to deliever UDP packets to host. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aSender A pointer to a function called to deliver UDP packet to host. + * @param[in] aContext A pointer to application-specific context. + * + */ +void otUdpProxySetSender(otInstance *aInstance, otUdpProxySender aSender, void *aContext); + +/** + * Handle a UDP packet received from host. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMessage A pointer to the UDP Message. + * @param[in] aPeerPort The source UDP port. + * @param[in] aPeerAddr A pointer to the source address. + * @param[in] aSockPort The destination UDP port. + * + * @warning No matter the call success or fail, the message is freed. + * + */ +void otUdpProxyReceive(otInstance * aInstance, + otMessage * aMessage, + uint16_t aPeerPort, + const otIp6Address *aPeerAddr, + uint16_t aSockPort); + /** * @} * diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 38cfebd82..28c6cb805 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -119,7 +119,6 @@ SOURCES_COMMON = \ api/tasklet_api.cpp \ api/thread_api.cpp \ api/thread_ftd_api.cpp \ - api/tmf_proxy_api.cpp \ api/udp_api.cpp \ coap/coap.cpp \ coap/coap_header.cpp \ @@ -146,6 +145,7 @@ SOURCES_COMMON = \ mac/mac_filter.cpp \ mac/mac_frame.cpp \ meshcop/announce_begin_client.cpp \ + meshcop/border_agent.cpp \ meshcop/commissioner.cpp \ meshcop/dataset.cpp \ meshcop/dataset_local.cpp \ @@ -195,7 +195,6 @@ SOURCES_COMMON = \ thread/router_table.cpp \ thread/src_match_controller.cpp \ thread/thread_netif.cpp \ - thread/tmf_proxy.cpp \ thread/time_sync_service.cpp \ thread/topology.cpp \ utils/channel_manager.cpp \ @@ -268,6 +267,7 @@ HEADERS_COMMON = \ mac/mac_filter.hpp \ mac/mac_frame.hpp \ meshcop/announce_begin_client.hpp \ + meshcop/border_agent.hpp \ meshcop/commissioner.hpp \ meshcop/dataset.hpp \ meshcop/dataset_local.hpp \ @@ -327,7 +327,6 @@ HEADERS_COMMON = \ thread/thread_netif.hpp \ thread/thread_tlvs.hpp \ thread/thread_uri_paths.hpp \ - thread/tmf_proxy.hpp \ thread/time_sync_service.hpp \ thread/topology.hpp \ utils/channel_manager.hpp \ diff --git a/src/core/api/commissioner_api.cpp b/src/core/api/commissioner_api.cpp index 4e8c250b9..1aa11d0d4 100644 --- a/src/core/api/commissioner_api.cpp +++ b/src/core/api/commissioner_api.cpp @@ -46,11 +46,13 @@ otError otCommissionerStart(otInstance *aInstance) #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER Instance &instance = *static_cast(aInstance); - error = instance.GetThreadNetif().GetCommissioner().Start(); -#else - OT_UNUSED_VARIABLE(aInstance); +#if OPENTHREAD_ENABLE_BORDER_AGENT + SuccessOrExit(error = instance.GetBorderAgent().Stop()); #endif - + SuccessOrExit(error = instance.GetThreadNetif().GetCommissioner().Start()); +exit: +#endif + OT_UNUSED_VARIABLE(aInstance); return error; } @@ -61,11 +63,13 @@ otError otCommissionerStop(otInstance *aInstance) #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER Instance &instance = *static_cast(aInstance); - error = instance.GetThreadNetif().GetCommissioner().Stop(); -#else - OT_UNUSED_VARIABLE(aInstance); + SuccessOrExit(error = instance.GetThreadNetif().GetCommissioner().Stop()); +#if OPENTHREAD_ENABLE_BORDER_AGENT + SuccessOrExit(error = instance.GetBorderAgent().Start()); #endif - +exit: +#endif + OT_UNUSED_VARIABLE(aInstance); return error; } diff --git a/src/core/api/tmf_proxy_api.cpp b/src/core/api/tmf_proxy_api.cpp deleted file mode 100644 index fa90631d2..000000000 --- a/src/core/api/tmf_proxy_api.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This file implements the OpenThread TMF proxy API. - */ - -#include "openthread-core-config.h" - -#include - -#include "common/instance.hpp" - -#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY - -using namespace ot; - -otError otTmfProxyStart(otInstance *aInstance, otTmfProxyStreamHandler aTmfProxyCallback, void *aContext) -{ - Instance &instance = *static_cast(aInstance); - - return instance.GetThreadNetif().GetTmfProxy().Start(aTmfProxyCallback, aContext); -} - -otError otTmfProxyStop(otInstance *aInstance) -{ - Instance &instance = *static_cast(aInstance); - - return instance.GetThreadNetif().GetTmfProxy().Stop(); -} - -otError otTmfProxySend(otInstance *aInstance, otMessage *aMessage, uint16_t aLocator, uint16_t aPort) -{ - Instance &instance = *static_cast(aInstance); - - return instance.GetThreadNetif().GetTmfProxy().Send(*static_cast(aMessage), aLocator, aPort); -} - -bool otTmfProxyIsEnabled(otInstance *aInstance) -{ - Instance &instance = *static_cast(aInstance); - - return instance.GetThreadNetif().GetTmfProxy().IsEnabled(); -} - -#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp index 481324112..0949f23f8 100644 --- a/src/core/api/udp_api.cpp +++ b/src/core/api/udp_api.cpp @@ -102,3 +102,36 @@ otError otUdpSend(otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo Ip6::UdpSocket &socket = *static_cast(aSocket); return socket.SendTo(*static_cast(aMessage), *static_cast(aMessageInfo)); } + +#if OPENTHREAD_ENABLE_UDP_PROXY +void otUdpProxySetSender(otInstance *aInstance, otUdpProxySender aSender, void *aContext) +{ + Instance &instance = *static_cast(aInstance); + Ip6::Ip6 &ip6 = instance.Get(); + + ip6.GetUdp().SetProxySender(aSender, aContext); +} + +void otUdpProxyReceive(otInstance * aInstance, + otMessage * aMessage, + uint16_t aPeerPort, + const otIp6Address *aPeerAddr, + uint16_t aSockPort) +{ + Ip6::MessageInfo messageInfo; + Instance & instance = *static_cast(aInstance); + Ip6::Ip6 & ip6 = instance.Get(); + + assert(aMessage != NULL && aPeerAddr != NULL); + + messageInfo.SetSockAddr(instance.GetThreadNetif().GetMle().GetMeshLocal16()); + messageInfo.SetSockPort(aSockPort); + messageInfo.SetPeerAddr(*static_cast(aPeerAddr)); + messageInfo.SetPeerPort(aPeerPort); + messageInfo.SetInterfaceId(OT_NETIF_INTERFACE_ID_HOST); + + ip6.GetUdp().HandlePayload(*static_cast(aMessage), messageInfo); + + static_cast(aMessage)->Free(); +} +#endif // OPENTHREAD_ENABLE_UDP_PROXY diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index 2fe683525..a47fcfe90 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -229,6 +229,14 @@ public: */ Resource *GetNext(void) const { return static_cast(mNext); }; + /** + * This method returns a pointer to the Uri-Path. + * + * @returns A Pointer to the Uri-Path. + * + */ + const char *GetUriPath(void) const { return mUriPath; }; + private: void HandleRequest(Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const { @@ -584,7 +592,7 @@ public: * @retval OT_ERROR_INVALID_ARGS The @p aRequestHeader header is not of confirmable type. * */ - otError SendAck(Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) + otError SendAck(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) { return SendEmptyMessage(OT_COAP_TYPE_ACKNOWLEDGMENT, aRequestHeader, aMessageInfo); }; diff --git a/src/core/coap/coap_header.cpp b/src/core/coap/coap_header.cpp index 62110845c..0149edb5f 100644 --- a/src/core/coap/coap_header.cpp +++ b/src/core/coap/coap_header.cpp @@ -83,7 +83,7 @@ otError Header::FromMessage(const Message &aMessage, uint16_t aMetadataSize) VerifyOrExit(GetVersion() == 1); tokenLength = GetTokenLength(); - VerifyOrExit(tokenLength <= kMaxTokenLength && (mHeaderLength + tokenLength) <= length); + VerifyOrExit(tokenLength <= OT_COAP_MAX_TOKEN_LENGTH && (mHeaderLength + tokenLength) <= length); aMessage.Read(offset, tokenLength, mHeader.mBytes + mHeaderLength); mHeaderLength += tokenLength; offset += tokenLength; @@ -416,9 +416,9 @@ exit: void Header::SetToken(uint8_t aTokenLength) { - uint8_t token[kMaxTokenLength] = {0}; + uint8_t token[OT_COAP_MAX_TOKEN_LENGTH] = {0}; - assert(aTokenLength <= kMaxTokenLength); + assert(aTokenLength <= sizeof(token)); Random::FillBuffer(token, aTokenLength); diff --git a/src/core/coap/coap_header.hpp b/src/core/coap/coap_header.hpp index 2fd2a2ca3..4f00e4403 100644 --- a/src/core/coap/coap_header.hpp +++ b/src/core/coap/coap_header.hpp @@ -480,7 +480,6 @@ private: kTokenLengthMask = 0x0f, ///< Token Length mask as specified (RFC 7252). kTokenLengthOffset = 0, ///< Token Length offset as specified (RFC 7252). kTokenOffset = 4, ///< Token offset as specified (RFC 7252). - kMaxTokenLength = 8, ///< Max token length as specified (RFC 7252). kMaxOptionHeaderSize = 5, ///< Maximum size of an Option header diff --git a/src/core/coap/coap_secure.cpp b/src/core/coap/coap_secure.cpp index 2f1610c7f..d6db38d98 100644 --- a/src/core/coap/coap_secure.cpp +++ b/src/core/coap/coap_secure.cpp @@ -62,6 +62,8 @@ otError CoapSecure::Start(uint16_t aPort, TransportCallback aCallback, void *aCo otError error = OT_ERROR_NONE; mTransportCallback = aCallback; mTransportContext = aContext; + mConnectedCallback = NULL; + mConnectedContext = NULL; // Passing mTransportCallback means that we do not want to use socket // to transmit/receive messages, so do not open it in that case. @@ -73,6 +75,12 @@ otError CoapSecure::Start(uint16_t aPort, TransportCallback aCallback, void *aCo return error; } +void CoapSecure::SetConnectedCallback(ConnectedCallback aCallback, void *aContext) +{ + mConnectedCallback = aCallback; + mConnectedContext = aContext; +} + otError CoapSecure::Stop(void) { if (IsConnectionActive()) diff --git a/src/core/coap/coap_secure.hpp b/src/core/coap/coap_secure.hpp index 2c69b5f45..a5e2693c8 100644 --- a/src/core/coap/coap_secure.hpp +++ b/src/core/coap/coap_secure.hpp @@ -86,6 +86,15 @@ public: */ otError Start(uint16_t aPort, TransportCallback aCallback = NULL, void *aContext = NULL); + /** + * This method sets connected callback of this secure CoAP agent. + * + * @param[in] aCallback A pointer to a function to get called when connection state changes. + * @param[in] aContext A pointer to arbitrary context information. + * + */ + void SetConnectedCallback(ConnectedCallback aCallback, void *aContext); + /** * This method stops the secure CoAP agent. * @@ -201,6 +210,14 @@ public: */ virtual void Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + /** + * This method returns the DTLS session's peer address. + * + * @return DTLS session's message info. + * + */ + const Ip6::MessageInfo &GetPeerMessageInfo(void) const { return mPeerAddress; } + private: virtual otError Send(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp index 07ef73694..7adc21f99 100644 --- a/src/core/common/instance.cpp +++ b/src/core/common/instance.cpp @@ -64,6 +64,9 @@ Instance::Instance(void) , mSettings(*this) , mIp6(*this) , mThreadNetif(*this) +#if OPENTHREAD_ENABLE_BORDER_AGENT + , mBorderAgent(*this) +#endif #if OPENTHREAD_ENABLE_APPLICATION_COAP , mApplicationCoap(*this) #endif @@ -422,6 +425,13 @@ template <> Utils::ChannelManager &Instance::Get(void) } #endif +#if OPENTHREAD_ENABLE_BORDER_AGENT +template <> MeshCoP::BorderAgent &Instance::Get(void) +{ + return mBorderAgent; +} +#endif + #if OPENTHREAD_CONFIG_ENABLE_ANNOUNCE_SENDER template <> AnnounceSender &Instance::Get(void) { diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index fff697752..76c92fc10 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -55,6 +55,7 @@ #endif #include "common/notifier.hpp" #include "common/settings.hpp" +#include "meshcop/border_agent.hpp" #include "net/ip6.hpp" #include "thread/announce_sender.hpp" #include "thread/link_quality.hpp" @@ -364,6 +365,10 @@ public: * */ MessagePool &GetMessagePool(void) { return mMessagePool; } + +#if OPENTHREAD_ENABLE_BORDER_AGENT + MeshCoP::BorderAgent &GetBorderAgent(void) { return mBorderAgent; } +#endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD /** @@ -419,6 +424,9 @@ private: Ip6::Ip6 mIp6; ThreadNetif mThreadNetif; +#if OPENTHREAD_ENABLE_BORDER_AGENT + MeshCoP::BorderAgent mBorderAgent; +#endif #if OPENTHREAD_ENABLE_APPLICATION_COAP Coap::ApplicationCoap mApplicationCoap; diff --git a/src/core/common/logging.cpp b/src/core/common/logging.cpp index 3521beacf..7e555d891 100644 --- a/src/core/common/logging.cpp +++ b/src/core/common/logging.cpp @@ -180,7 +180,7 @@ const char *otThreadErrorToString(otError aError) switch (aError) { case OT_ERROR_NONE: - retval = "None"; + retval = "OK"; break; case OT_ERROR_FAILED: diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp new file mode 100644 index 000000000..873f2b573 --- /dev/null +++ b/src/core/meshcop/border_agent.cpp @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2018, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the BorderAgent service. + */ + +#define WPP_NAME "border_agent.tmh" + +#include "border_agent.hpp" + +#include + +#include "coap/coap_header.hpp" +#include "common/instance.hpp" +#include "common/logging.hpp" +#include "common/new.hpp" +#include "common/owner-locator.hpp" +#include "meshcop/meshcop.hpp" +#include "meshcop/meshcop_tlvs.hpp" +#include "thread/thread_netif.hpp" +#include "thread/thread_tlvs.hpp" +#include "thread/thread_uri_paths.hpp" + +#if OPENTHREAD_ENABLE_BORDER_AGENT + +namespace ot { +namespace MeshCoP { + +class ForwardContext +{ +public: + /** + * This constructor initializes a forward context. + * + * @param[in] aBorderAgent A reference to the border agent. + * @param[in] aHeader A reference to the request header. + * @param[in] aSeparate Whether this request should be responded separately. + * + */ + ForwardContext(BorderAgent &aBorderAgent, const Coap::Header &aHeader, bool aSeparate) + : mBorderAgent(aBorderAgent) + , mMessageId(aHeader.GetMessageId()) + , mSeparate(aSeparate) + , mType(aHeader.GetType() >> kTypeOffset) + , mTokenLength(aHeader.GetTokenLength()) + { + memcpy(mToken, aHeader.GetToken(), mTokenLength); + } + + BorderAgent &GetBorderAgent(void) { return mBorderAgent; } + + /** + * This method generate the response header according to the saved metadata. + * + * @param[out] aHeader A refernce to the response header. + * @param[in] aCode The response code to fill in the response header. + * + */ + void ToHeader(Coap::Header &aHeader, Coap::Header::Code aCode) + { + if (mType == (OT_COAP_TYPE_NON_CONFIRMABLE >> kTypeOffset) || mSeparate) + { + aHeader.Init(OT_COAP_TYPE_NON_CONFIRMABLE, aCode); + } + else + { + aHeader.Init(OT_COAP_TYPE_ACKNOWLEDGMENT, aCode); + } + + aHeader.SetMessageId(mSeparate ? 0 : mMessageId); + aHeader.SetToken(mToken, mTokenLength); + } + +private: + enum + { + kTypeOffset = 4, ///< The type offset in the first byte of coap header + }; + + BorderAgent &mBorderAgent; + uint16_t mMessageId; ///< The CoAP Message ID + bool mSeparate : 1; + uint8_t mType : 2; ///< Type + uint8_t mTokenLength : 4; ///< The CoAP Version, Type, and Token Length + uint8_t mToken[OT_COAP_MAX_TOKEN_LENGTH]; +}; + +static Coap::Header::Code CoapCodeFromError(otError aError) +{ + switch (aError) + { + case OT_ERROR_NONE: + return OT_COAP_CODE_CHANGED; + + case OT_ERROR_PARSE: + return OT_COAP_CODE_BAD_REQUEST; + + default: + return OT_COAP_CODE_INTERNAL_ERROR; + } +} + +void BorderAgent::SendErrorMessage(const Coap::Header &aHeader) +{ + otError error = OT_ERROR_NONE; + Message * message = NULL; + ThreadNetif &netif = GetNetif(); + + VerifyOrExit((message = NewMeshCoPMessage(netif.GetCoapSecure(), aHeader)) != NULL, error = OT_ERROR_NO_BUFS); + + SuccessOrExit(error = netif.GetCoapSecure().SendMessage(*message, netif.GetCoapSecure().GetPeerMessageInfo())); + +exit: + + if (error != OT_ERROR_NONE) + { + if (message != NULL) + { + message->Free(); + } + + otLogWarnMeshCoP(GetInstance(), "Failed to send CoAP message: %s", otThreadErrorToString(error)); + } +} + +void BorderAgent::HandleCoapResponse(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + otError aResult) +{ + ForwardContext &forwardContext = *static_cast(aContext); + BorderAgent & borderAgent = forwardContext.GetBorderAgent(); + ThreadNetif & netif = borderAgent.GetNetif(); + Coap::Header header; + + OT_UNUSED_VARIABLE(aMessageInfo); + otLogInfoMeshCoP(GetInstance(), "Got CoAP response[%s]", otThreadErrorToString(aResult)); + + if (aResult != OT_ERROR_NONE) + { + forwardContext.ToHeader(header, CoapCodeFromError(aResult)); + ExitNow(borderAgent.SendErrorMessage(header)); + } + + assert(aMessage != NULL); + + forwardContext.ToHeader(header, static_cast(aHeader)->GetCode()); + + if (static_cast(aMessage)->GetLength() - static_cast(aMessage)->GetOffset() > 0) + { + header.SetPayloadMarker(); + } + + borderAgent.ForwardToCommissioner(header, *static_cast(aMessage)); + +exit: + netif.GetInstance().GetHeap().Free(&forwardContext); +} + +template <> +void BorderAgent::HandleRequest<&BorderAgent::mCommissionerPetition>(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->ForwardToLeader( + *static_cast(aHeader), *static_cast(aMessage), + *static_cast(aMessageInfo), OT_URI_PATH_LEADER_PETITION, true); +} + +template <> +void BorderAgent::HandleRequest<&BorderAgent::mCommissionerKeepAlive>(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->ForwardToLeader( + *static_cast(aHeader), *static_cast(aMessage), + *static_cast(aMessageInfo), OT_URI_PATH_LEADER_KEEP_ALIVE, true); +} + +template <> +void BorderAgent::HandleRequest<&BorderAgent::mRelayTransmit>(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo) +{ + OT_UNUSED_VARIABLE(aMessageInfo); + static_cast(aContext)->HandleRelayTransmit(*static_cast(aHeader), + *static_cast(aMessage)); +} + +template <> +void BorderAgent::HandleRequest<&BorderAgent::mRelayReceive>(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo) +{ + OT_UNUSED_VARIABLE(aMessageInfo); + static_cast(aContext)->HandleRelayReceive(*static_cast(aHeader), + *static_cast(aMessage)); +} + +BorderAgent::BorderAgent(Instance &aInstance) + : InstanceLocator(aInstance) + , mCommissionerPetition(OT_URI_PATH_COMMISSIONER_PETITION, + BorderAgent::HandleRequest<&BorderAgent::mCommissionerPetition>, + this) + , mCommissionerKeepAlive(OT_URI_PATH_COMMISSIONER_KEEP_ALIVE, + BorderAgent::HandleRequest<&BorderAgent::mCommissionerKeepAlive>, + this) + , mRelayTransmit(OT_URI_PATH_RELAY_TX, BorderAgent::HandleRequest<&BorderAgent::mRelayTransmit>, this) + , mRelayReceive(OT_URI_PATH_RELAY_RX, BorderAgent::HandleRequest<&BorderAgent::mRelayReceive>, this) + , mCommissionerGet(OT_URI_PATH_COMMISSIONER_GET, BorderAgent::HandleRequest<&BorderAgent::mCommissionerGet>, this) + , mCommissionerSet(OT_URI_PATH_COMMISSIONER_SET, BorderAgent::HandleRequest<&BorderAgent::mCommissionerSet>, this) + , mActiveGet(OT_URI_PATH_ACTIVE_GET, BorderAgent::HandleRequest<&BorderAgent::mActiveGet>, this) + , mActiveSet(OT_URI_PATH_ACTIVE_SET, BorderAgent::HandleRequest<&BorderAgent::mActiveSet>, this) + , mPendingGet(OT_URI_PATH_PENDING_GET, BorderAgent::HandleRequest<&BorderAgent::mPendingGet>, this) + , mPendingSet(OT_URI_PATH_PENDING_SET, BorderAgent::HandleRequest<&BorderAgent::mPendingSet>, this) + , mTimer(aInstance, HandleTimeout, this) + , mIsStarted(false) +{ +} + +void BorderAgent::HandleRelayReceive(const Coap::Header &aHeader, const Message &aMessage) +{ + Coap::Header header; + + VerifyOrExit(aHeader.GetType() == OT_COAP_TYPE_NON_CONFIRMABLE && aHeader.GetCode() == OT_COAP_CODE_POST); + + header.Init(OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_POST); + header.AppendUriPathOptions(OT_URI_PATH_RELAY_RX); + + if (aMessage.GetLength() - aMessage.GetOffset() > 0) + { + header.SetPayloadMarker(); + } + + SuccessOrExit(ForwardToCommissioner(header, aMessage)); + otLogInfoMeshCoP(GetInstance(), "Sent to leader on %s", OT_URI_PATH_RELAY_RX); + +exit: + return; +} + +otError BorderAgent::ForwardToCommissioner(const Coap::Header &aHeader, const Message &aMessage) +{ + ThreadNetif &netif = GetNetif(); + otError error = OT_ERROR_NONE; + Message * message = NULL; + uint16_t offset = 0; + + VerifyOrExit((message = NewMeshCoPMessage(netif.GetCoapSecure(), aHeader)) != NULL, error = OT_ERROR_NO_BUFS); + + offset = message->GetLength(); + SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength() - aMessage.GetOffset())); + aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), *message); + + SuccessOrExit(error = netif.GetCoapSecure().SendMessage(*message, netif.GetCoapSecure().GetPeerMessageInfo())); + + otLogInfoMeshCoP(GetInstance(), "Sent to commissioner"); + +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnMeshCoP(GetInstance(), "Failed to send to commissioner: %s", otThreadErrorToString(error)); + if (message != NULL) + { + message->Free(); + } + } + + return error; +} + +void BorderAgent::HandleRelayTransmit(const Coap::Header &aHeader, const Message &aMessage) +{ + ThreadNetif & netif = GetNetif(); + otError error = OT_ERROR_NONE; + JoinerRouterLocatorTlv joinerRouterRloc; + Message * message = NULL; + Ip6::MessageInfo messageInfo; + Coap::Header header; + uint16_t offset = 0; + + VerifyOrExit(aHeader.GetType() == OT_COAP_TYPE_NON_CONFIRMABLE && aHeader.GetCode() == OT_COAP_CODE_POST); + + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kJoinerRouterLocator, sizeof(joinerRouterRloc), joinerRouterRloc)); + VerifyOrExit(joinerRouterRloc.IsValid(), error = OT_ERROR_PARSE); + + header.Init(OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_POST); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(OT_URI_PATH_RELAY_TX); + header.SetPayloadMarker(); + + VerifyOrExit((message = NewMeshCoPMessage(netif.GetCoap(), header)) != NULL, error = OT_ERROR_NO_BUFS); + + offset = message->GetLength(); + SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength() - aMessage.GetOffset())); + aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), *message); + + messageInfo.SetSockPort(kCoapUdpPort); + messageInfo.SetSockAddr(netif.GetMle().GetMeshLocal16()); + messageInfo.SetPeerPort(kCoapUdpPort); + messageInfo.SetPeerAddr(netif.GetMle().GetMeshLocal16()); + messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(joinerRouterRloc.GetJoinerRouterLocator()); + + SuccessOrExit(error = netif.GetCoap().SendMessage(*message, messageInfo)); + + otLogInfoMeshCoP(borderAgent->GetInstance(), "Sent to joiner router request on %s", OT_URI_PATH_RELAY_TX); + +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnMeshCoP(borderAgent->GetInstance(), + "Failed to sent to joiner router request " OT_URI_PATH_RELAY_TX " %s", + otThreadErrorToString(error)); + if (message != NULL) + { + message->Free(); + } + } +} + +void BorderAgent::ForwardToLeader(const Coap::Header & aHeader, + const Message & aMessage, + const Ip6::MessageInfo &aMessageInfo, + const char * aPath, + bool aSeparate) +{ + ThreadNetif & netif = GetNetif(); + otError error = OT_ERROR_NONE; + ForwardContext * forwardContext = NULL; + Ip6::MessageInfo messageInfo; + Coap::Header header; + Message * message = NULL; + uint16_t offset = 0; + + if (aSeparate) + { + SuccessOrExit(error = netif.GetCoapSecure().SendAck(aHeader, aMessageInfo)); + } + + forwardContext = static_cast(GetInstance().GetHeap().CAlloc(1, sizeof(ForwardContext))); + VerifyOrExit(forwardContext != NULL, error = OT_ERROR_NO_BUFS); + + forwardContext = new (forwardContext) ForwardContext(*this, aHeader, aSeparate); + + header.Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(aPath); + + // Payload of c/cg may be empty + if (aMessage.GetLength() - aMessage.GetOffset() > 0) + { + header.SetPayloadMarker(); + } + + VerifyOrExit((message = NewMeshCoPMessage(netif.GetCoap(), header)) != NULL, error = OT_ERROR_NO_BUFS); + + offset = message->GetLength(); + SuccessOrExit(error = message->SetLength(offset + aMessage.GetLength() - aMessage.GetOffset())); + aMessage.CopyTo(aMessage.GetOffset(), offset, aMessage.GetLength() - aMessage.GetOffset(), *message); + + SuccessOrExit(netif.GetMle().GetLeaderAloc(messageInfo.GetPeerAddr())); + messageInfo.SetPeerPort(kCoapUdpPort); + messageInfo.SetSockAddr(netif.GetMle().GetMeshLocal16()); + messageInfo.SetSockPort(kCoapUdpPort); + + SuccessOrExit(error = netif.GetCoap().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext)); + + // HandleCoapResponse is responsible to free this forward context. + forwardContext = NULL; + + otLogInfoMeshCoP(GetInstance(), "Forwarded request to leader on %s", aPath); + +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnMeshCoP(GetInstance(), "Failed to forward to leader: %s", otThreadErrorToString(error)); + if (forwardContext != NULL) + { + GetInstance().GetHeap().Free(forwardContext); + } + + if (message != NULL) + { + message->Free(); + } + + if (aHeader.GetType() == OT_COAP_TYPE_NON_CONFIRMABLE || aSeparate) + { + header.Init(OT_COAP_TYPE_NON_CONFIRMABLE, CoapCodeFromError(error)); + } + else + { + header.Init(OT_COAP_TYPE_ACKNOWLEDGMENT, CoapCodeFromError(error)); + } + + header.SetMessageId(aSeparate ? 0 : aHeader.GetMessageId()); + header.SetToken(aHeader.GetToken(), aHeader.GetTokenLength()); + + SendErrorMessage(header); + } +} + +void BorderAgent::HandleConnected(bool aConnected) +{ + if (aConnected) + { + otLogInfoMeshCoP(GetInstance(), "Commissioner connected"); + mTimer.Start(kKeepAliveTimeout); + } + else + { + otLogInfoMeshCoP(GetInstance(), "Commissioner disconnected"); + mTimer.Start(kRestartDelay); + } +} + +otError BorderAgent::StartCoaps(void) +{ + ThreadNetif & netif = GetNetif(); + Coap::CoapSecure &coaps = netif.GetCoapSecure(); + otError error; + + SuccessOrExit(error = coaps.Start(kBorderAgentUdpPort)); + SuccessOrExit(error = coaps.SetPsk(netif.GetKeyManager().GetPSKc(), OT_PSKC_MAX_SIZE)); + coaps.SetConnectedCallback(HandleConnected, this); + +exit: + return error; +} + +otError BorderAgent::Start(void) +{ + otError error; + ThreadNetif & netif = GetNetif(); + Coap::CoapSecure &coaps = netif.GetCoapSecure(); + Coap::Coap & coap = netif.GetCoap(); + + VerifyOrExit(!mIsStarted, error = OT_ERROR_ALREADY); + + SuccessOrExit(error = StartCoaps()); + + coaps.AddResource(mActiveGet); + coaps.AddResource(mActiveSet); + coaps.AddResource(mPendingGet); + coaps.AddResource(mPendingSet); + coaps.AddResource(mCommissionerPetition); + coaps.AddResource(mCommissionerKeepAlive); + coaps.AddResource(mCommissionerSet); + coaps.AddResource(mCommissionerGet); + coaps.AddResource(mRelayTransmit); + + coap.AddResource(mRelayReceive); + + mIsStarted = true; + +exit: + return error; +} + +void BorderAgent::HandleTimeout(Timer &aTimer) +{ + aTimer.GetOwner().HandleTimeout(); +} + +void BorderAgent::HandleTimeout(void) +{ + ThreadNetif & netif = GetNetif(); + Coap::CoapSecure &coaps = netif.GetCoapSecure(); + otError error; + + if (coaps.IsConnected()) + { + error = coaps.Stop(); + otLogWarnMeshCoP(GetInstance(), "Reset commissioner session: %s", otThreadErrorToString(error)); + } + else if (!coaps.IsConnectionActive()) + { + error = StartCoaps(); + otLogWarnMeshCoP(GetInstance(), "Restart border agent secure CoAP service: %s", otThreadErrorToString(error)); + } + else + { + assert(false); + } + + OT_UNUSED_VARIABLE(error); +} + +otError BorderAgent::Stop(void) +{ + otError error; + ThreadNetif & netif = GetNetif(); + Coap::CoapSecure &coaps = netif.GetCoapSecure(); + Coap::Coap & coap = netif.GetCoap(); + + VerifyOrExit(mIsStarted, error = OT_ERROR_ALREADY); + + mTimer.Stop(); + + coaps.RemoveResource(mCommissionerPetition); + coaps.RemoveResource(mCommissionerKeepAlive); + coaps.RemoveResource(mCommissionerSet); + coaps.RemoveResource(mCommissionerGet); + coaps.RemoveResource(mActiveGet); + coaps.RemoveResource(mActiveSet); + coaps.RemoveResource(mPendingGet); + coaps.RemoveResource(mPendingSet); + coaps.RemoveResource(mRelayTransmit); + + coap.RemoveResource(mRelayReceive); + + error = coaps.Stop(); + assert(error == OT_ERROR_NONE); + + mIsStarted = false; + +exit: + return error; +} + +} // namespace MeshCoP +} // namespace ot + +#endif // OPENTHREAD_ENABLE_BORDER_AGENT diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp new file mode 100644 index 000000000..9ab0e52e9 --- /dev/null +++ b/src/core/meshcop/border_agent.hpp @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for the BorderAgent role. + */ + +#ifndef BORDER_AGENT_HPP_ +#define BORDER_AGENT_HPP_ + +#include "openthread-core-config.h" + +#include "coap/coap.hpp" +#include "common/locator.hpp" + +namespace ot { + +class ThreadNetif; + +namespace MeshCoP { + +class BorderAgent : public InstanceLocator +{ +public: + /** + * This constructor initializes the BorderAgent object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit BorderAgent(Instance &aInstance); + + /** + * This method starts the BorderAgent service. + * + * @retval OT_ERROR_NONE Successfully started the BorderAgent service. + * + */ + otError Start(void); + + /** + * This method stops the BorderAgent service. + * + * @retval OT_ERROR_NONE Successfully stopped the BorderAgent service. + * + */ + otError Stop(void); + +private: + static void HandleConnected(bool aConnected, void *aContext) + { + static_cast(aContext)->HandleConnected(aConnected); + } + void HandleConnected(bool aConnected); + otError StartCoaps(void); + + template + static void HandleRequest(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo) + { + static_cast(aContext)->ForwardToLeader( + *static_cast(aHeader), *static_cast(aMessage), + *static_cast(aMessageInfo), + (static_cast(aContext)->*aResource).GetUriPath(), false); + } + + static void HandleTimeout(Timer &aTimer); + void HandleTimeout(void); + + static void HandleCoapResponse(void * aContext, + otCoapHeader * aHeader, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + otError aResult); + + void SendErrorMessage(const Coap::Header &aHeader); + void ForwardToLeader(const Coap::Header & aHeader, + const Message & aMessage, + const Ip6::MessageInfo &aMessageInfo, + const char * aPath, + bool aSeparate); + otError ForwardToCommissioner(const Coap::Header &aHeader, const Message &aMessage); + void HandleRelayTransmit(const Coap::Header &aHeader, const Message &aMessage); + void HandleRelayReceive(const Coap::Header &aHeader, const Message &aMessage); + + enum + { + kBorderAgentUdpPort = 49191, ///< UDP port of border agent service. + kKeepAliveTimeout = 50 * 1000, ///< Timeout to reject a commissioner. + kRestartDelay = 1 * 1000, ///< Delay to restart border agent service. + }; + + Ip6::MessageInfo mMessageInfo; + + Coap::Resource mCommissionerPetition; + Coap::Resource mCommissionerKeepAlive; + Coap::Resource mRelayTransmit; + Coap::Resource mRelayReceive; + Coap::Resource mCommissionerGet; + Coap::Resource mCommissionerSet; + Coap::Resource mActiveGet; + Coap::Resource mActiveSet; + Coap::Resource mPendingGet; + Coap::Resource mPendingSet; + + TimerMilli mTimer; + bool mIsStarted; +}; + +} // namespace MeshCoP +} // namespace ot + +#endif // BORDER_AGENT_HPP_ diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp index e5157e353..bf94011e6 100644 --- a/src/core/meshcop/dtls.hpp +++ b/src/core/meshcop/dtls.hpp @@ -62,7 +62,7 @@ public: enum { kPskMaxLength = 32, - kApplicationDataMaxLength = 128, + kApplicationDataMaxLength = 512, }; /** diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index e6cc91fe4..58950e95c 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -119,8 +119,7 @@ otError Joiner::Start(const char * aPSKd, error = netif.GetCoapSecure().Start(OPENTHREAD_CONFIG_JOINER_UDP_PORT); SuccessOrExit(error); - error = netif.GetCoapSecure().GetDtls().SetPsk(reinterpret_cast(aPSKd), - static_cast(strlen(aPSKd))); + error = netif.GetCoapSecure().SetPsk(reinterpret_cast(aPSKd), static_cast(strlen(aPSKd))); SuccessOrExit(error); error = netif.GetCoapSecure().GetDtls().mProvisioningUrl.SetProvisioningUrl(aProvisioningUrl); diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index 770feaa56..1d233772b 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -99,7 +99,6 @@ otError UdpSocket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo) { otError error = OT_ERROR_NONE; MessageInfo messageInfoLocal; - UdpHeader udpHeader; messageInfoLocal = aMessageInfo; @@ -112,6 +111,7 @@ otError UdpSocket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo) { GetSockName().mPort = static_cast(mTransport)->GetEphemeralPort(); } + messageInfoLocal.SetSockPort(GetSockName().mPort); if (messageInfoLocal.GetPeerAddr().IsUnspecified()) { @@ -126,13 +126,6 @@ otError UdpSocket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo) messageInfoLocal.mPeerPort = GetPeerName().mPort; } - udpHeader.SetSourcePort(GetSockName().mPort); - udpHeader.SetDestinationPort(messageInfoLocal.mPeerPort); - udpHeader.SetLength(sizeof(udpHeader) + aMessage.GetLength()); - udpHeader.SetChecksum(0); - - SuccessOrExit(error = aMessage.Prepend(&udpHeader, sizeof(udpHeader))); - aMessage.SetOffset(0); SuccessOrExit(error = static_cast(mTransport)->SendDatagram(aMessage, messageInfoLocal, kProtoUdp)); exit: @@ -209,7 +202,34 @@ Message *Udp::NewMessage(uint16_t aReserved) otError Udp::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, IpProto aIpProto) { - return GetIp6().SendDatagram(aMessage, aMessageInfo, aIpProto); + otError error = OT_ERROR_NONE; + +#if OPENTHREAD_ENABLE_UDP_PROXY + if (aMessageInfo.GetInterfaceId() == OT_NETIF_INTERFACE_ID_HOST) + { + VerifyOrExit(mProxySender != NULL, error = OT_ERROR_NO_ROUTE); + mProxySender(&aMessage, aMessageInfo.mPeerPort, &aMessageInfo.GetPeerAddr(), aMessageInfo.mSockPort, + mProxySenderContext); + // message is consumed by the callback + } + else +#endif + { + UdpHeader udpHeader; + + udpHeader.SetSourcePort(aMessageInfo.mSockPort); + udpHeader.SetDestinationPort(aMessageInfo.mPeerPort); + udpHeader.SetLength(sizeof(udpHeader) + aMessage.GetLength()); + udpHeader.SetChecksum(0); + + SuccessOrExit(error = aMessage.Prepend(&udpHeader, sizeof(udpHeader))); + aMessage.SetOffset(0); + + error = GetIp6().SendDatagram(aMessage, aMessageInfo, aIpProto); + } + +exit: + return error; } otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) @@ -239,10 +259,18 @@ otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) aMessageInfo.mPeerPort = udpHeader.GetSourcePort(); aMessageInfo.mSockPort = udpHeader.GetDestinationPort(); + HandlePayload(aMessage, aMessageInfo); + +exit: + return error; +} + +void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo) +{ // find socket for (UdpSocket *socket = mSockets; socket; socket = socket->GetNext()) { - if (socket->GetSockName().mPort != udpHeader.GetDestinationPort()) + if (socket->GetSockName().mPort != aMessageInfo.GetSockPort()) { continue; } @@ -261,7 +289,7 @@ otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) // verify source if connected socket if (socket->GetPeerName().mPort != 0) { - if (socket->GetPeerName().mPort != udpHeader.GetSourcePort()) + if (socket->GetPeerName().mPort != aMessageInfo.GetPeerPort()) { continue; } @@ -275,9 +303,6 @@ otError Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) socket->HandleUdpReceive(aMessage, aMessageInfo); } - -exit: - return error; } otError Udp::UpdateChecksum(Message &aMessage, uint16_t aChecksum) diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp index d8db11a05..3e789791b 100644 --- a/src/core/net/udp6.hpp +++ b/src/core/net/udp6.hpp @@ -241,6 +241,15 @@ public: */ otError HandleMessage(Message &aMessage, MessageInfo &aMessageInfo); + /** + * This method handles a received UDP message with offset set to the payload. + * + * @param[in] aMessage A reference to the UDP message to process. + * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. + * + */ + void HandlePayload(Message &aMessage, MessageInfo &aMessageInfo); + /** * This method updates the UDP checksum. * @@ -253,6 +262,21 @@ public: */ otError UpdateChecksum(Message &aMessage, uint16_t aPseudoHeaderChecksum); +#if OPENTHREAD_ENABLE_UDP_PROXY + /** + * This method sets the proxy sender. + * + * @param[in] aSender A function pointer to send the proxy UDP packet. + * @param[in] aContext A pointer to arbitrary context information. + * + */ + void SetProxySender(otUdpProxySender aSender, void *aContext) + { + mProxySender = aSender; + mProxySenderContext = aContext; + } +#endif // OPENTHREAD_ENABLE_UDP_PROXY + private: enum { @@ -261,6 +285,10 @@ private: }; uint16_t mEphemeralPort; UdpSocket *mSockets; +#if OPENTHREAD_ENABLE_UDP_PROXY + void * mProxySenderContext; + otUdpProxySender mProxySender; +#endif }; OT_TOOL_PACKED_BEGIN diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index ff8902401..2530fc946 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -96,7 +96,7 @@ void KeyManager::Stop(void) mKeyRotationTimer.Stop(); } -#if OPENTHREAD_FTD +#if OPENTHREAD_MTD || OPENTHREAD_FTD const uint8_t *KeyManager::GetPSKc(void) const { return mPSKc; @@ -111,7 +111,7 @@ void KeyManager::SetPSKc(const uint8_t *aPSKc) exit: return; } -#endif +#endif // OPENTHREAD_MTD || OPENTHREAD_FTD const otMasterKey &KeyManager::GetMasterKey(void) const { diff --git a/src/core/thread/key_manager.hpp b/src/core/thread/key_manager.hpp index b52ef6af3..fe3a7a1f4 100644 --- a/src/core/thread/key_manager.hpp +++ b/src/core/thread/key_manager.hpp @@ -359,7 +359,7 @@ private: bool mKeySwitchGuardEnabled; TimerMilli mKeyRotationTimer; -#if OPENTHREAD_FTD +#if OPENTHREAD_MTD || OPENTHREAD_FTD uint8_t mPSKc[kMaxKeyLength]; #endif uint8_t mKek[kMaxKeyLength]; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index e35b060aa..8ce220a28 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -302,6 +302,17 @@ void Mle::SetRole(otDeviceRole aRole) mRole = aRole; GetNotifier().Signal(OT_CHANGED_THREAD_ROLE); +#if OPENTHREAD_ENABLE_BORDER_AGENT + // Start border agent + if (aRole == OT_DEVICE_ROLE_ROUTER || aRole == OT_DEVICE_ROLE_LEADER || aRole == OT_DEVICE_ROLE_CHILD) + { + SuccessOrExit(GetInstance().GetBorderAgent().Start()); + } + else + { + SuccessOrExit(GetInstance().GetBorderAgent().Stop()); + } +#endif exit: return; diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index 166c7730b..80be150b8 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -90,9 +90,6 @@ ThreadNetif::ThreadNetif(Instance &aInstance) , mJamDetector(aInstance) #endif // OPENTHREAD_ENABLE_JAM_DETECTTION #if OPENTHREAD_FTD -#if OPENTHREAD_ENABLE_TMF_PROXY - , mTmfProxy(mMleRouter.GetMeshLocal16(), mCoap) -#endif // OPENTHREAD_ENABLE_TMF_PROXY , mJoinerRouter(aInstance) , mLeader(aInstance) , mAddressResolver(aInstance) diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index e1f868fc4..d950e0004 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -42,10 +42,6 @@ #include "coap/coap_secure.hpp" #include "mac/mac.hpp" -#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD -#include "thread/tmf_proxy.hpp" -#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD - #if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD #include "meshcop/commissioner.hpp" #endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD @@ -371,16 +367,6 @@ public: Utils::JamDetector &GetJamDetector(void) { return mJamDetector; } #endif // OPENTHREAD_ENABLE_JAM_DETECTION -#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD - /** - * This method returns the TMF proxy object. - * - * @returns Reference to the TMF proxy object. - * - */ - TmfProxy &GetTmfProxy(void) { return mTmfProxy; } -#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD - /** * This method returns a reference to the child supervisor object. * @@ -479,10 +465,6 @@ private: Utils::JamDetector mJamDetector; #endif // OPENTHREAD_ENABLE_JAM_DETECTION -#if OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD - TmfProxy mTmfProxy; -#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD - #if OPENTHREAD_FTD MeshCoP::JoinerRouter mJoinerRouter; MeshCoP::Leader mLeader; diff --git a/src/core/thread/thread_uri_paths.hpp b/src/core/thread/thread_uri_paths.hpp index 886b47a8c..c4f83e3b4 100644 --- a/src/core/thread/thread_uri_paths.hpp +++ b/src/core/thread/thread_uri_paths.hpp @@ -220,6 +220,22 @@ namespace ot { */ #define OT_URI_PATH_COMMISSIONER_GET "c/cg" +/** + * @def OT_URI_PATH_COMMISSIONER_KEEP_ALIVE + * + * The URI Path for Commissioner Keep Alive. + * + */ +#define OT_URI_PATH_COMMISSIONER_KEEP_ALIVE "c/ca" + +/** + * @def OT_URI_PATH_COMMISSIONER_PETITION + * + * The URI Path for Commissioner Petition. + * + */ +#define OT_URI_PATH_COMMISSIONER_PETITION "c/cp" + /** * @def OT_URI_PATH_COMMISSIONER_SET * diff --git a/src/core/thread/tmf_proxy.cpp b/src/core/thread/tmf_proxy.cpp deleted file mode 100644 index 3640ea0ab..000000000 --- a/src/core/thread/tmf_proxy.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2017, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This file implements the TMF proxy. - */ - -#define WPP_NAME "tmf_proxy.tmh" - -#include "tmf_proxy.hpp" - -#include - -#include "coap/coap_header.hpp" -#include "common/instance.hpp" -#include "net/ip6_address.hpp" -#include "thread/thread_tlvs.hpp" -#include "thread/thread_uri_paths.hpp" - -#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY - -namespace ot { - -TmfProxy::TmfProxy(const Ip6::Address &aMeshLocal16, Coap::Coap &aCoap) - : mRelayReceive(OT_URI_PATH_RELAY_RX, &TmfProxy::HandleRelayReceive, this) - , mStreamHandler(NULL) - , mContext(NULL) - , mMeshLocal16(aMeshLocal16) - , mCoap(aCoap) -{ -} - -otError TmfProxy::Start(otTmfProxyStreamHandler aStreamHandler, void *aContext) -{ - otError error = OT_ERROR_NONE; - - VerifyOrExit(!mStreamHandler, error = OT_ERROR_ALREADY); - - mCoap.AddResource(mRelayReceive); - mStreamHandler = aStreamHandler; - mContext = aContext; - -exit: - return error; -} - -otError TmfProxy::Stop(void) -{ - otError error = OT_ERROR_NONE; - - VerifyOrExit(mStreamHandler != NULL, error = OT_ERROR_ALREADY); - - mCoap.RemoveResource(mRelayReceive); - - mStreamHandler = NULL; - -exit: - return error; -} - -bool TmfProxy::IsEnabled(void) const -{ - return mStreamHandler != NULL; -} - -void TmfProxy::HandleRelayReceive(void * aContext, - otCoapHeader * aHeader, - otMessage * aMessage, - const otMessageInfo *aMessageInfo) -{ - static_cast(aContext)->DeliverMessage(*static_cast(aHeader), - *static_cast(aMessage), - *static_cast(aMessageInfo)); -} - -void TmfProxy::HandleResponse(void * aContext, - otCoapHeader * aHeader, - otMessage * aMessage, - const otMessageInfo *aMessageInfo, - otError aResult) -{ - VerifyOrExit(aResult == OT_ERROR_NONE); - - static_cast(aContext)->DeliverMessage(*static_cast(aHeader), - *static_cast(aMessage), - *static_cast(aMessageInfo)); -exit: - return; -} - -void TmfProxy::DeliverMessage(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) -{ - otError error = OT_ERROR_NONE; - uint16_t rloc; - uint16_t port; - Message *message = NULL; - - VerifyOrExit(mStreamHandler != NULL, error = OT_ERROR_INVALID_STATE); - - VerifyOrExit((message = aMessage.Clone()) != NULL, error = OT_ERROR_NO_BUFS); - message->RemoveHeader(message->GetOffset() - aHeader.GetLength()); - - rloc = HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[7]); - port = aMessageInfo.GetPeerPort(); - mStreamHandler(message, rloc, port, mContext); - -exit: - - if (error != OT_ERROR_NONE && message != NULL) - { - message->Free(); - } -} - -otError TmfProxy::Send(Message &aMessage, uint16_t aLocator, uint16_t aPort) -{ - otError error = OT_ERROR_NONE; - Ip6::MessageInfo messageInfo; - - VerifyOrExit(mStreamHandler != NULL, error = OT_ERROR_INVALID_STATE); - - messageInfo.SetSockAddr(mMeshLocal16); - messageInfo.SetPeerAddr(mMeshLocal16); - messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(aLocator); - messageInfo.SetPeerPort(aPort); - - if (aPort == kCoapUdpPort) - { - // this is request to server, send with client - error = mCoap.SendMessage(aMessage, messageInfo, TmfProxy::HandleResponse, this); - } - else - { - error = mCoap.SendMessage(aMessage, messageInfo); - } - -exit: - - if (error != OT_ERROR_NONE) - { - aMessage.Free(); - } - - return error; -} - -} // namespace ot - -#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY diff --git a/src/core/thread/tmf_proxy.hpp b/src/core/thread/tmf_proxy.hpp deleted file mode 100644 index 83319eaeb..000000000 --- a/src/core/thread/tmf_proxy.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This file includes definitions for TMF proxy. - */ - -#ifndef TMF_PROXY_HPP_ -#define TMF_PROXY_HPP_ - -#include "openthread-core-config.h" - -#include - -#include "coap/coap.hpp" - -namespace ot { - -class TmfProxy -{ -public: - /** - * This constructor initializes the TMF proxy. - * - * @param[in] aMeshLocal16 A reference to the Mesh Local Routing Locator. - * @param[in] aCoap A reference to the Management CoAP Service. - * - */ - TmfProxy(const Ip6::Address &aMeshLocal16, Coap::Coap &aCoap); - - /** - * This method enables the TMF proxy service. - * - * @retval OT_ERROR_NONE Successfully started the service. - * @retval OT_ERROR_ALREADY The service already started. - * - */ - otError Start(otTmfProxyStreamHandler aStreamHandler, void *aContext); - - /** - * This method disables the TMF proxy service. - * - * @retval OT_ERROR_NONE Successfully stopped the TMF proxy service. - * @retval OT_ERROR_ALREADY The service already stopped. - * - */ - otError Stop(void); - - /** - * This method sends the message into the thread network. - * - * @param[in] aMessage A reference to the message to send. - * @param[in] aLocator The destination's RLOC16 or ALOC16. - * @param[in] aPort The destination port. - * - * @retval OT_ERROR_NONE Successfully send the message. - * @retval OT_ERROR_INVALID_STATE Border agent proxy is not started. - * - * @warning No matter the call success or fail, the message is freed. - * - */ - otError Send(Message &aMessage, uint16_t aLocator, uint16_t aPort); - - /** - * This method indicates whether or not the TMF proxy service is enabled. - * - * @retval TRUE If the service is enabled. - * @retval FALSE If the service is disabled. - * - */ - bool IsEnabled(void) const; - -private: - static void HandleRelayReceive(void * aContext, - otCoapHeader * aHeader, - otMessage * aMessage, - const otMessageInfo *aMessageInfo); - - static void HandleResponse(void * aContext, - otCoapHeader * aHeader, - otMessage * aMessage, - const otMessageInfo *aMessageInfo, - otError aResult); - - void DeliverMessage(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - - Coap::Resource mRelayReceive; - otTmfProxyStreamHandler mStreamHandler; - void * mContext; - - const Ip6::Address &mMeshLocal16; - Coap::Coap & mCoap; -}; - -} // namespace ot - -#endif // TMF_PROXY_HPP_ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index ce101bf4b..a74b96aed 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -251,6 +251,9 @@ NcpBase::NcpBase(Instance *aInstance) otSetStateChangedCallback(mInstance, &NcpBase::HandleStateChanged, this); otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this); otIp6SetReceiveFilterEnabled(mInstance, true); +#if OPENTHREAD_ENABLE_UDP_PROXY + otUdpProxySetSender(mInstance, &NcpBase::HandleUdpProxyStream, this); +#endif otLinkSetPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this)); otIcmp6SetEchoMode(mInstance, OT_ICMP6_ECHO_HANDLER_DISABLED); #if OPENTHREAD_FTD @@ -1640,8 +1643,8 @@ template <> otError NcpBase::HandlePropertyGet(void) SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_NEST_LEGACY_INTERFACE)); #endif -#if OPENTHREAD_ENABLE_TMF_PROXY - SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_TMF_PROXY)); +#if OPENTHREAD_ENABLE_UDP_PROXY + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_UDP_PROXY)); #endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 29541b2c4..8679524cb 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -293,13 +293,16 @@ protected: otError DecodeOperationalDataset(otOperationalDataset &aDataset, const uint8_t **aTlvs, uint8_t *aTlvsLength); #endif +#if OPENTHREAD_ENABLE_UDP_PROXY + static void HandleUdpProxyStream(otMessage * aMessage, + uint16_t aPeerPort, + otIp6Address *aPeerAddr, + uint16_t aSockPort, + void * aContext); + void HandleUdpProxyStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort); +#endif // OPENTHREAD_ENABLE_UDP_PROXY #endif // OPENTHREAD_MTD || OPENTHREAD_FTD -#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY - static void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext); - void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort); -#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY - otError CommandHandler_NOOP(uint8_t aHeader); otError CommandHandler_RESET(uint8_t aHeader); // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`. diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 03815da92..93b89d680 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -44,10 +44,6 @@ #include #include -#if OPENTHREAD_ENABLE_TMF_PROXY -#include -#endif - #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/instance.hpp" @@ -548,107 +544,6 @@ exit: return error; } -#if OPENTHREAD_ENABLE_TMF_PROXY -template <> otError NcpBase::HandlePropertyGet(void) -{ - return mEncoder.WriteBool(otTmfProxyIsEnabled(mInstance)); -} - -template <> otError NcpBase::HandlePropertySet(void) -{ - const uint8_t *framePtr = NULL; - uint16_t frameLen = 0; - uint16_t locator; - uint16_t port; - otMessage * message; - otError error = OT_ERROR_NONE; - - // THREAD_TMF_PROXY_STREAM requires layer 2 security. - message = otIp6NewMessage(mInstance, true); - VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - - SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen)); - SuccessOrExit(error = mDecoder.ReadUint16(locator)); - SuccessOrExit(error = mDecoder.ReadUint16(port)); - - SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen))); - - error = otTmfProxySend(mInstance, message, locator, port); - - // `otTmfProxySend()` takes ownership of `message` (in both success - // or failure cases). `message` is set to NULL so it is not freed at - // exit. - message = NULL; - -exit: - if (message != NULL) - { - otMessageFree(message); - } - - return error; -} - -template <> otError NcpBase::HandlePropertySet(void) -{ - bool enabled; - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = mDecoder.ReadBool(enabled)); - - if (enabled) - { - error = otTmfProxyStart(mInstance, &NcpBase::HandleTmfProxyStream, this); - } - else - { - error = otTmfProxyStop(mInstance); - } - -exit: - return error; -} - -void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext) -{ - static_cast(aContext)->HandleTmfProxyStream(aMessage, aLocator, aPort); -} - -void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort) -{ - otError error = OT_ERROR_NONE; - uint16_t length = otMessageGetLength(aMessage); - uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; - - SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_THREAD_TMF_PROXY_STREAM)); - SuccessOrExit(error = mEncoder.WriteUint16(length)); - SuccessOrExit(error = mEncoder.WriteMessage(aMessage)); - - SuccessOrExit(error = mEncoder.WriteUint16(aLocator)); - SuccessOrExit(error = mEncoder.WriteUint16(aPort)); - SuccessOrExit(error = mEncoder.EndFrame()); - - // The `aMessage` is owned by the outbound frame and NCP buffer - // after frame was finished/ended successfully. It will be freed - // when the frame is successfully sent and removed. - - aMessage = NULL; - -exit: - - if (aMessage != NULL) - { - otMessageFree(aMessage); - } - - if (error != OT_ERROR_NONE) - { - mChangedPropsSet.AddLastStatus(SPINEL_STATUS_DROPPED); - mUpdateChangedPropsTask.Post(); - } -} -#endif // OPENTHREAD_ENABLE_TMF_PROXY - otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset, const uint8_t **aTlvs, uint8_t *aTlvsLength) { otError error = OT_ERROR_NONE; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index c740128d4..89570e070 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -2928,6 +2928,82 @@ exit: return error; } +#if OPENTHREAD_ENABLE_UDP_PROXY +template <> otError NcpBase::HandlePropertySet(void) +{ + const uint8_t * framePtr = NULL; + uint16_t frameLen = 0; + const otIp6Address *peerAddr; + uint16_t peerPort; + uint16_t sockPort; + otMessage * message; + otError error = OT_ERROR_NONE; + + message = otIp6NewMessage(mInstance, false); + VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); + + SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen)); + SuccessOrExit(error = mDecoder.ReadUint16(peerPort)); + SuccessOrExit(error = mDecoder.ReadIp6Address(peerAddr)); + SuccessOrExit(error = mDecoder.ReadUint16(sockPort)); + + SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen))); + + otUdpProxyReceive(mInstance, message, peerPort, peerAddr, sockPort); + + // `otUdpProxyReceive()` takes ownership of `message` (in both success + // or failure cases). `message` is set to NULL so it is not freed at + // exit. + message = NULL; + +exit: + if (message != NULL) + { + otMessageFree(message); + } + + return error; +} + +void NcpBase::HandleUdpProxyStream(otMessage * aMessage, + uint16_t aPeerPort, + otIp6Address *aPeerAddr, + uint16_t aSockPort, + void * aContext) +{ + static_cast(aContext)->HandleUdpProxyStream(aMessage, aPeerPort, *aPeerAddr, aSockPort); +} + +void NcpBase::HandleUdpProxyStream(otMessage *aMessage, uint16_t aPeerPort, otIp6Address &aPeerAddr, uint16_t aPort) +{ + otError error = OT_ERROR_NONE; + uint16_t length = otMessageGetLength(aMessage); + uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; + + SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_THREAD_UDP_PROXY_STREAM)); + SuccessOrExit(error = mEncoder.WriteUint16(length)); + SuccessOrExit(error = mEncoder.WriteMessage(aMessage)); + + SuccessOrExit(error = mEncoder.WriteUint16(aPeerPort)); + SuccessOrExit(error = mEncoder.WriteIp6Address(aPeerAddr)); + SuccessOrExit(error = mEncoder.WriteUint16(aPort)); + SuccessOrExit(error = mEncoder.EndFrame()); + + // The `aMessage` is owned by the outbound frame and NCP buffer + // after frame was finished/ended successfully. It will be freed + // when the frame is successfully sent and removed. + + aMessage = NULL; + +exit: + + if (aMessage != NULL) + { + otMessageFree(aMessage); + } +} +#endif // OPENTHREAD_ENABLE_UDP_PROXY + // ---------------------------------------------------------------------------- // MARK: Property/Status Changed // ---------------------------------------------------------------------------- diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index ba1de7906..82bfc105a 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1493,6 +1493,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PROP_THREAD_TMF_PROXY_STREAM"; break; + case SPINEL_PROP_THREAD_UDP_PROXY_STREAM: + ret = "PROP_THREAD_UDP_PROXY_STREAM"; + break; + case SPINEL_PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG: ret = "PROP_THREAD_DISCOVERY_SCAN_JOINER_FLAG"; break; @@ -2254,6 +2258,10 @@ const char *spinel_capability_to_cstr(unsigned int capability) ret = "CAP_THREAD_TMF_PROXY"; break; + case SPINEL_CAP_THREAD_UDP_PROXY: + ret = "CAP_THREAD_UDP_PROXY"; + break; + case SPINEL_CAP_NEST_LEGACY_INTERFACE: ret = "CAP_NEST_LEGACY_INTERFACE"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index f4b5abe7a..ec2b22cc7 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -458,6 +458,7 @@ enum SPINEL_CAP_THREAD__BEGIN = 1024, SPINEL_CAP_THREAD_COMMISSIONER = (SPINEL_CAP_THREAD__BEGIN + 0), SPINEL_CAP_THREAD_TMF_PROXY = (SPINEL_CAP_THREAD__BEGIN + 1), + SPINEL_CAP_THREAD_UDP_PROXY = (SPINEL_CAP_THREAD__BEGIN + 2), SPINEL_CAP_THREAD__END = 1152, SPINEL_CAP_NEST__BEGIN = 15296, @@ -1394,6 +1395,19 @@ typedef enum { */ SPINEL_PROP_THREAD_ADDRESS_CACHE_TABLE = SPINEL_PROP_THREAD_EXT__BEGIN + 35, + /// Thread UDP proxy stream + /** Format `dS6S` + * + * This property helps exchange UDP packets with host. + * + * `d`: UDP payload + * `S`: Remote UDP port + * `6`: Remote IPv6 address + * `S`: Local UDP port + * + */ + SPINEL_PROP_THREAD_UDP_PROXY_STREAM = SPINEL_PROP_THREAD_EXT__BEGIN + 36, + SPINEL_PROP_THREAD_EXT__END = 0x1600, SPINEL_PROP_IPV6__BEGIN = 0x60,