[meshcop] move border agent into core (#2771)

This commit moves the border agent service into OpenThread core.

Border agent, commissioner, and joiner shares a single secure CoAP agent,
because they will not be active at the same time.

Other changes include:
- Replaced TMF proxy with UDP proxy, which is more generalized.
- Changed OT_ERROR_NONE string to "OK".
- Defined a special interface id -1 to differentiate packets received by
  host side.
This commit is contained in:
Yakun Xu
2018-07-09 15:25:23 -05:00
committed by Jonathan Hui
parent 8555513247
commit 96a7e2d5a5
41 changed files with 1133 additions and 685 deletions
+49 -16
View File
@@ -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}
+2 -1
View File
@@ -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)
+6 -2
View File
@@ -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)
+1 -1
View File
@@ -3440,7 +3440,7 @@ otThreadErrorToString(
switch (aError)
{
case OT_ERROR_NONE:
retval = "None";
retval = "OK";
break;
case OT_ERROR_FAILED:
-1
View File
@@ -78,7 +78,6 @@ openthread_headers = \
tasklet.h \
thread.h \
thread_ftd.h \
tmf_proxy.h \
types.h \
udp.h \
$(NULL)
+2
View File
@@ -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.
*
-123
View File
@@ -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 <openthread/types.h>
#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_
+2 -1
View File
@@ -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;
/**
+61
View File
@@ -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);
/**
* @}
*
+2 -3
View File
@@ -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 \
+12 -8
View File
@@ -46,11 +46,13 @@ otError otCommissionerStart(otInstance *aInstance)
#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
Instance &instance = *static_cast<Instance *>(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<Instance *>(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;
}
-72
View File
@@ -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 <openthread/tmf_proxy.h>
#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<Instance *>(aInstance);
return instance.GetThreadNetif().GetTmfProxy().Start(aTmfProxyCallback, aContext);
}
otError otTmfProxyStop(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTmfProxy().Stop();
}
otError otTmfProxySend(otInstance *aInstance, otMessage *aMessage, uint16_t aLocator, uint16_t aPort)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTmfProxy().Send(*static_cast<ot::Message *>(aMessage), aLocator, aPort);
}
bool otTmfProxyIsEnabled(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTmfProxy().IsEnabled();
}
#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
+33
View File
@@ -102,3 +102,36 @@ otError otUdpSend(otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo
Ip6::UdpSocket &socket = *static_cast<Ip6::UdpSocket *>(aSocket);
return socket.SendTo(*static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
#if OPENTHREAD_ENABLE_UDP_PROXY
void otUdpProxySetSender(otInstance *aInstance, otUdpProxySender aSender, void *aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
Ip6::Ip6 &ip6 = instance.Get<Ip6::Ip6>();
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<Instance *>(aInstance);
Ip6::Ip6 & ip6 = instance.Get<Ip6::Ip6>();
assert(aMessage != NULL && aPeerAddr != NULL);
messageInfo.SetSockAddr(instance.GetThreadNetif().GetMle().GetMeshLocal16());
messageInfo.SetSockPort(aSockPort);
messageInfo.SetPeerAddr(*static_cast<const ot::Ip6::Address *>(aPeerAddr));
messageInfo.SetPeerPort(aPeerPort);
messageInfo.SetInterfaceId(OT_NETIF_INTERFACE_ID_HOST);
ip6.GetUdp().HandlePayload(*static_cast<ot::Message *>(aMessage), messageInfo);
static_cast<ot::Message *>(aMessage)->Free();
}
#endif // OPENTHREAD_ENABLE_UDP_PROXY
+9 -1
View File
@@ -229,6 +229,14 @@ public:
*/
Resource *GetNext(void) const { return static_cast<Resource *>(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);
};
+3 -3
View File
@@ -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);
-1
View File
@@ -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
+8
View File
@@ -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())
+17
View File
@@ -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);
+10
View File
@@ -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)
{
+8
View File
@@ -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;
+1 -1
View File
@@ -180,7 +180,7 @@ const char *otThreadErrorToString(otError aError)
switch (aError)
{
case OT_ERROR_NONE:
retval = "None";
retval = "OK";
break;
case OT_ERROR_FAILED:
+556
View File
@@ -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 <openthread/types.h>
#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<ForwardContext *>(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<Coap::Header *>(aHeader)->GetCode());
if (static_cast<Message *>(aMessage)->GetLength() - static_cast<Message *>(aMessage)->GetOffset() > 0)
{
header.SetPayloadMarker();
}
borderAgent.ForwardToCommissioner(header, *static_cast<Message *>(aMessage));
exit:
netif.GetInstance().GetHeap().Free(&forwardContext);
}
template <>
void BorderAgent::HandleRequest<&BorderAgent::mCommissionerPetition>(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<BorderAgent *>(aContext)->ForwardToLeader(
*static_cast<Coap::Header *>(aHeader), *static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo), OT_URI_PATH_LEADER_PETITION, true);
}
template <>
void BorderAgent::HandleRequest<&BorderAgent::mCommissionerKeepAlive>(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<BorderAgent *>(aContext)->ForwardToLeader(
*static_cast<Coap::Header *>(aHeader), *static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(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<BorderAgent *>(aContext)->HandleRelayTransmit(*static_cast<Coap::Header *>(aHeader),
*static_cast<Message *>(aMessage));
}
template <>
void BorderAgent::HandleRequest<&BorderAgent::mRelayReceive>(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
static_cast<BorderAgent *>(aContext)->HandleRelayReceive(*static_cast<Coap::Header *>(aHeader),
*static_cast<Message *>(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<ForwardContext *>(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<BorderAgent>().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
+141
View File
@@ -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<BorderAgent *>(aContext)->HandleConnected(aConnected);
}
void HandleConnected(bool aConnected);
otError StartCoaps(void);
template <Coap::Resource BorderAgent::*aResource>
static void HandleRequest(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<BorderAgent *>(aContext)->ForwardToLeader(
*static_cast<Coap::Header *>(aHeader), *static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
(static_cast<BorderAgent *>(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_
+1 -1
View File
@@ -62,7 +62,7 @@ public:
enum
{
kPskMaxLength = 32,
kApplicationDataMaxLength = 128,
kApplicationDataMaxLength = 512,
};
/**
+1 -2
View File
@@ -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<const uint8_t *>(aPSKd),
static_cast<uint8_t>(strlen(aPSKd)));
error = netif.GetCoapSecure().SetPsk(reinterpret_cast<const uint8_t *>(aPSKd), static_cast<uint8_t>(strlen(aPSKd)));
SuccessOrExit(error);
error = netif.GetCoapSecure().GetDtls().mProvisioningUrl.SetProvisioningUrl(aProvisioningUrl);
+39 -14
View File
@@ -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<Udp *>(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<Udp *>(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)
+28
View File
@@ -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
+2 -2
View File
@@ -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
{
+1 -1
View File
@@ -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];
+11
View File
@@ -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;
-3
View File
@@ -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)
-18
View File
@@ -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;
+16
View File
@@ -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
*
-175
View File
@@ -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 <openthread/types.h>
#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<TmfProxy *>(aContext)->DeliverMessage(*static_cast<Coap::Header *>(aHeader),
*static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void TmfProxy::HandleResponse(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aResult)
{
VerifyOrExit(aResult == OT_ERROR_NONE);
static_cast<TmfProxy *>(aContext)->DeliverMessage(*static_cast<Coap::Header *>(aHeader),
*static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(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
-123
View File
@@ -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 <openthread/tmf_proxy.h>
#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_
+5 -2
View File
@@ -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<void *>(this));
otIcmp6SetEchoMode(mInstance, OT_ICMP6_ECHO_HANDLER_DISABLED);
#if OPENTHREAD_FTD
@@ -1640,8 +1643,8 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CAPS>(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
+8 -5
View File
@@ -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`.
-105
View File
@@ -44,10 +44,6 @@
#include <openthread/thread_ftd.h>
#include <openthread/platform/misc.h>
#if OPENTHREAD_ENABLE_TMF_PROXY
#include <openthread/tmf_proxy.h>
#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<SPINEL_PROP_THREAD_TMF_PROXY_ENABLED>(void)
{
return mEncoder.WriteBool(otTmfProxyIsEnabled(mInstance));
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_TMF_PROXY_STREAM>(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<uint16_t>(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<SPINEL_PROP_THREAD_TMF_PROXY_ENABLED>(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<NcpBase *>(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;
+76
View File
@@ -2928,6 +2928,82 @@ exit:
return error;
}
#if OPENTHREAD_ENABLE_UDP_PROXY
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_UDP_PROXY_STREAM>(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<uint16_t>(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<NcpBase *>(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
// ----------------------------------------------------------------------------
+8
View File
@@ -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;
+14
View File
@@ -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,