diff --git a/Android.mk b/Android.mk index 816868328..165d14d40 100644 --- a/Android.mk +++ b/Android.mk @@ -176,6 +176,7 @@ LOCAL_SRC_FILES := \ src/core/api/thread_api.cpp \ src/core/api/thread_ftd_api.cpp \ src/core/api/udp_api.cpp \ + src/core/backbone_router/backbone_tmf.cpp \ src/core/backbone_router/bbr_leader.cpp \ src/core/backbone_router/bbr_local.cpp \ src/core/backbone_router/bbr_manager.cpp \ @@ -291,6 +292,7 @@ LOCAL_SRC_FILES := \ src/lib/spinel/spinel_encoder.cpp \ src/lib/url/url.cpp \ src/posix/platform/alarm.cpp \ + src/posix/platform/backbone.cpp \ src/posix/platform/entropy.cpp \ src/posix/platform/hdlc_interface.cpp \ src/posix/platform/logging.cpp \ diff --git a/include/openthread/platform/udp.h b/include/openthread/platform/udp.h index d4906cc63..ed9f8f6a9 100644 --- a/include/openthread/platform/udp.h +++ b/include/openthread/platform/udp.h @@ -39,10 +39,15 @@ extern "C" { #endif +/** + * This enumeration defines the OpenThread network interface identifiers. + * + */ typedef enum otNetifIdentifier { OT_NETIF_UNSPECIFIED = 0, ///< Unspecified network interface. OT_NETIF_THREAD, ///< The Thread interface. + OT_NETIF_BACKBONE, ///< The Backbone interface. } otNetifIdentifier; /** diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 96097ea56..e81166e6a 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -319,6 +319,8 @@ openthread_core_files = [ "api/thread_api.cpp", "api/thread_ftd_api.cpp", "api/udp_api.cpp", + "backbone_router/backbone_tmf.cpp", + "backbone_router/backbone_tmf.hpp", "backbone_router/bbr_leader.cpp", "backbone_router/bbr_leader.hpp", "backbone_router/bbr_local.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 99f0346a1..fe4ba3d5f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -102,6 +102,7 @@ set(COMMON_SOURCES api/thread_api.cpp api/thread_ftd_api.cpp api/udp_api.cpp + backbone_router/backbone_tmf.cpp backbone_router/bbr_leader.cpp backbone_router/bbr_local.cpp backbone_router/bbr_manager.cpp diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 0bfd150f1..1fec81360 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -144,6 +144,7 @@ SOURCES_COMMON = \ api/thread_api.cpp \ api/thread_ftd_api.cpp \ api/udp_api.cpp \ + backbone_router/backbone_tmf.cpp \ backbone_router/bbr_leader.cpp \ backbone_router/bbr_local.cpp \ backbone_router/bbr_manager.cpp \ @@ -325,6 +326,7 @@ endif # OPENTHREAD_ENABLE_VENDOR_EXTENSION HEADERS_COMMON = \ openthread-core-config.h \ + backbone_router/backbone_tmf.hpp \ backbone_router/bbr_leader.hpp \ backbone_router/bbr_local.hpp \ backbone_router/bbr_manager.hpp \ diff --git a/src/core/backbone_router/backbone_tmf.cpp b/src/core/backbone_router/backbone_tmf.cpp new file mode 100644 index 000000000..a43ed5a5f --- /dev/null +++ b/src/core/backbone_router/backbone_tmf.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, 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 Backbone Thread Management Framework (TMF) functionalities. + */ + +#include "backbone_tmf.hpp" + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + +#include "common/locator-getters.hpp" + +namespace ot { +namespace BackboneRouter { + +otError BackboneTmfAgent::Start(void) +{ + return Coap::Start(kBackboneUdpPort, OT_NETIF_BACKBONE); +} + +otError BackboneTmfAgent::Filter(const ot::Coap::Message &aMessage, + const Ip6::MessageInfo & aMessageInfo, + void * aContext) +{ + OT_UNUSED_VARIABLE(aMessage); + + return static_cast(aContext)->IsBackboneTmfMessage(aMessageInfo) ? OT_ERROR_NONE + : OT_ERROR_NOT_TMF; +} + +bool BackboneTmfAgent::IsBackboneTmfMessage(const Ip6::MessageInfo &aMessageInfo) const +{ + const Ip6::Address &dst = aMessageInfo.GetSockAddr(); + const Ip6::Address &src = aMessageInfo.GetPeerAddr(); + + // A Backbone TMF message must comply with following rules: + // The destination must be one of: + // 1. All Network BBRs (Link-Local scope) + // 2. All Domain BBRs (Link-Local scope) + // 3. A Backbone Link-Local address + // The source must be a Backbone Link-local address. + return (Get().IsEnabled() && src.IsLinkLocal() && + (dst.IsLinkLocal() || dst == Get().GetAllNetworkBackboneRoutersAddress() || + dst == Get().GetAllDomainBackboneRoutersAddress())); +} + +} // namespace BackboneRouter +} // namespace ot + +#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE diff --git a/src/core/backbone_router/backbone_tmf.hpp b/src/core/backbone_router/backbone_tmf.hpp new file mode 100644 index 000000000..29a9f36e7 --- /dev/null +++ b/src/core/backbone_router/backbone_tmf.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020, 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 Backbone TMF functionality. + */ + +#ifndef OT_CORE_THREAD_BACKBONE_TMF_HPP_ +#define OT_CORE_THREAD_BACKBONE_TMF_HPP_ + +#include "coap/coap.hpp" + +namespace ot { +namespace BackboneRouter { + +enum +{ + kBackboneUdpPort = 61631, ///< Backbone TMF UDP Port +}; + +/** + * This class implements functionality of the Backbone TMF agent. + * + */ +class BackboneTmfAgent : public Coap::Coap +{ +public: + /** + * This constructor initializes the object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit BackboneTmfAgent(Instance &aInstance) + : Coap::Coap(aInstance) + { + SetInterceptor(&Filter, this); + } + + /** + * This method starts the TMF agent. + * + * @retval OT_ERROR_NONE Successfully started the CoAP service. + * @retval OT_ERROR_ALREADY Already started. + * + */ + otError Start(void); + + /** + * This method returns whether @p aMessageInfo meets Backbone Thread Management Framework Addressing Rules. + * + * @retval true Thread Management Framework Addressing Rules are met. + * @retval false Thread Management Framework Addressing Rules are not met. + * + */ + bool IsBackboneTmfMessage(const Ip6::MessageInfo &aMessageInfo) const; + +private: + static otError Filter(const ot::Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext); +}; + +} // namespace BackboneRouter +} // namespace ot + +#endif // OT_CORE_THREAD_BACKBONE_TMF_HPP_ diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index 459ebd6e7..de59047d1 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -56,6 +56,7 @@ Manager::Manager(Instance &aInstance) , mNdProxyTable(aInstance) , mMulticastListenersTable(aInstance) , mTimer(aInstance, Manager::HandleTimer, this) + , mBackboneTmfAgent(aInstance) #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE , mDuaResponseStatus(ThreadStatusTlv::kDuaSuccess) , mMlrResponseStatus(ThreadStatusTlv::kMlrSuccess) @@ -67,6 +68,8 @@ Manager::Manager(Instance &aInstance) void Manager::HandleNotifierEvents(Events aEvents) { + otError error; + if (aEvents.Contains(kEventThreadBackboneRouterStateChanged)) { if (Get().GetState() == OT_BACKBONE_ROUTER_STATE_DISABLED) @@ -75,6 +78,17 @@ void Manager::HandleNotifierEvents(Events aEvents) Get().RemoveResource(mDuaRegistration); mTimer.Stop(); mMulticastListenersTable.Clear(); + + error = mBackboneTmfAgent.Stop(); + + if (error != OT_ERROR_NONE) + { + otLogWarnBbr("Stop Backbone TMF agent: %s", otThreadErrorToString(error)); + } + else + { + otLogInfoBbr("Stop Backbone TMF agent: %s", otThreadErrorToString(error)); + } } else { @@ -84,6 +98,17 @@ void Manager::HandleNotifierEvents(Events aEvents) { mTimer.Start(kTimerInterval); } + + error = mBackboneTmfAgent.Start(); + + if (error != OT_ERROR_NONE) + { + otLogCritBbr("Start Backbone TMF agent: %s", otThreadErrorToString(error)); + } + else + { + otLogInfoBbr("Start Backbone TMF agent: %s", otThreadErrorToString(error)); + } } } } diff --git a/src/core/backbone_router/bbr_manager.hpp b/src/core/backbone_router/bbr_manager.hpp index ac5419f24..d7a1998df 100644 --- a/src/core/backbone_router/bbr_manager.hpp +++ b/src/core/backbone_router/bbr_manager.hpp @@ -40,6 +40,7 @@ #include #include +#include "backbone_router/backbone_tmf.hpp" #include "backbone_router/bbr_leader.hpp" #include "backbone_router/multicast_listeners_table.hpp" #include "backbone_router/ndproxy_table.hpp" @@ -123,6 +124,14 @@ public: */ bool ShouldForwardDuaToBackbone(const Ip6::Address &aAddress); + /** + * This method returns a reference to the Backbone TMF agent. + * + * @returns A reference to the Backbone TMF agent. + * + */ + BackboneTmfAgent &GetBackboneTmfAgent(void) { return mBackboneTmfAgent; } + private: enum { @@ -166,6 +175,8 @@ private: MulticastListenersTable mMulticastListenersTable; TimerMilli mTimer; + BackboneTmfAgent mBackboneTmfAgent; + #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE Ip6::InterfaceIdentifier mDuaResponseTargetMlIid; ThreadStatusTlv::DuaStatus mDuaResponseStatus; diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index fcefd6694..ff049d46c 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -1018,14 +1018,25 @@ Coap::Coap(Instance &aInstance) { } -otError Coap::Start(uint16_t aPort) +otError Coap::Start(uint16_t aPort, otNetifIdentifier aNetifIdentifier) { otError error; + bool socketOpened = false; + + VerifyOrExit(!mSocket.IsBound(), error = OT_ERROR_ALREADY); SuccessOrExit(error = mSocket.Open(&Coap::HandleUdpReceive, this)); - VerifyOrExit((error = mSocket.Bind(aPort)) == OT_ERROR_NONE, IgnoreError(mSocket.Close())); + socketOpened = true; + + SuccessOrExit(error = mSocket.BindToNetif(aNetifIdentifier)); + SuccessOrExit(error = mSocket.Bind(aPort)); exit: + if (error != OT_ERROR_NONE && socketOpened) + { + IgnoreError(mSocket.Close()); + } + return error; } diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index c2d7b15d7..a8e64e641 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -606,13 +606,14 @@ public: /** * This method starts the CoAP service. * - * @param[in] aPort The local UDP port to bind to. + * @param[in] aPort The local UDP port to bind to. + * @param[in] aNetifIdentifier The network interface identifier to bind. * * @retval OT_ERROR_NONE Successfully started the CoAP service. * @retval OT_ERROR_ALREADY Already started. * */ - otError Start(uint16_t aPort); + otError Start(uint16_t aPort, otNetifIdentifier aNetifIdentifier = OT_NETIF_UNSPECIFIED); /** * This method stops the CoAP service. diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index b4f352621..eeca05f19 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -763,10 +763,16 @@ template <> inline BackboneRouter::MulticastListenersTable &Instance::Get(void) { return mThreadNetif.mBackboneRouterManager.GetMulticastListenersTable(); } + template <> inline BackboneRouter::NdProxyTable &Instance::Get(void) { return mThreadNetif.mBackboneRouterManager.GetNdProxyTable(); } + +template <> inline BackboneRouter::BackboneTmfAgent &Instance::Get(void) +{ + return mThreadNetif.mBackboneRouterManager.GetBackboneTmfAgent(); +} #endif #if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE diff --git a/src/core/common/linked_list.hpp b/src/core/common/linked_list.hpp index 166405f93..1e4ea45c2 100644 --- a/src/core/common/linked_list.hpp +++ b/src/core/common/linked_list.hpp @@ -392,6 +392,73 @@ public: return const_cast(this)->Find(aEntry, const_cast(aPrevEntry)); } + /** + * This template method searches within a given range of the linked list to find an entry matching a given + * indicator. + * + * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries + * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each + * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: + * + * bool Type::Matches(const Indicator &aIndicator) const + * + * @param[in] aBegin A pointer to the begin of the range. + * @param[in] aEnd A pointer to the end of the range, or nullptr to search all entries after @p aBegin. + * @param[in] aIndicator An indicator to match with entries in the list. + * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). + * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise + * it is updated to point to the previous entry before the matching entry in the list. + * + * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. + * + */ + template + const Type *FindMatching(const Type * aBegin, + const Type * aEnd, + const Inidcator &aIndicator, + const Type *& aPrevEntry) const + { + const Type *entry; + + aPrevEntry = nullptr; + + for (entry = aBegin; entry != aEnd; aPrevEntry = entry, entry = entry->GetNext()) + { + if (entry->Matches(aIndicator)) + { + break; + } + } + + return entry; + } + + /** + * This template method searches within a given range of the linked list to find an entry matching a given + * indicator. + * + * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries + * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each + * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: + * + * bool Type::Matches(const Indicator &aIndicator) const + * + * @param[in] aBegin A pointer to the begin of the range. + * @param[in] aEnd A pointer to the end of the range, or nullptr to search all entries after @p aBegin. + * @param[in] aIndicator An indicator to match with entries in the list. + * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). + * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise + * it is updated to point to the previous entry before the matching entry in the list. + * + * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. + * + */ + template + Type *FindMatching(const Type *aBegin, const Type *aEnd, const Inidcator &aIndicator, Type *&aPrevEntry) + { + return const_cast(FindMatching(aBegin, aEnd, aIndicator, const_cast(aPrevEntry))); + } + /** * This template method searches within the linked list to find an entry matching a given indicator. * @@ -401,7 +468,7 @@ public: * * bool Type::Matches(const Indicator &aIndicator) const * - * @param[in] aIndicator An indicator to match with entries in the list.. + * @param[in] aIndicator An indicator to match with entries in the list. * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise * it is updated to point to the previous entry before the matching entry in the list. @@ -411,19 +478,7 @@ public: */ template const Type *FindMatching(const Inidcator &aIndicator, const Type *&aPrevEntry) const { - const Type *entry; - - aPrevEntry = nullptr; - - for (entry = mHead; entry != nullptr; aPrevEntry = entry, entry = entry->GetNext()) - { - if (entry->Matches(aIndicator)) - { - break; - } - } - - return entry; + return FindMatching(mHead, nullptr, aIndicator, aPrevEntry); } /** @@ -436,7 +491,7 @@ public: * * bool Type::Matches(const Indicator &aIndicator) const * - * @param[in] aIndicator An indicator to match with entries in the list.. + * @param[in] aIndicator An indicator to match with entries in the list. * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise * it is updated to point to the previous entry before the matching entry in the list. diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index f5d985b98..4e7a64d84 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -99,13 +99,26 @@ otError Udp::Socket::Bind(uint16_t aPort) return Bind(SockAddr(aPort)); } -#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE otError Udp::Socket::BindToNetif(otNetifIdentifier aNetifIdentifier) { - return otPlatUdpBindToNetif(this, aNetifIdentifier); -} + OT_UNUSED_VARIABLE(aNetifIdentifier); + + otError error = OT_ERROR_NONE; + +#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE + SuccessOrExit(error = otPlatUdpBindToNetif(this, aNetifIdentifier)); #endif +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + Get().BindToNetif(*this, aNetifIdentifier); +#endif + +#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE +exit: +#endif + return error; +} + otError Udp::Socket::Connect(const SockAddr &aSockAddr) { return Get().Connect(*this, aSockAddr); @@ -131,6 +144,9 @@ Udp::Udp(Instance &aInstance) , mEphemeralPort(kDynamicPortMin) , mReceivers() , mSockets() +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + , mPrevBackboneSockets(nullptr) +#endif #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE , mUdpForwarderContext(nullptr) , mUdpForwarder(nullptr) @@ -204,6 +220,35 @@ exit: return error; } +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +void Udp::BindToNetif(SocketHandle &aSocket, otNetifIdentifier aNetifIdentifier) +{ + if (aNetifIdentifier == OT_NETIF_BACKBONE) + { + SetBackboneSocket(aSocket); + } +} + +void Udp::SetBackboneSocket(SocketHandle &aSocket) +{ + RemoveSocket(aSocket); + + if (mPrevBackboneSockets != nullptr) + { + mSockets.PushAfter(aSocket, *mPrevBackboneSockets); + } + else + { + mSockets.Push(aSocket); + } +} + +const Udp::SocketHandle *Udp::GetBackboneSockets(void) +{ + return mPrevBackboneSockets != nullptr ? mPrevBackboneSockets->GetNext() : mSockets.GetHead(); +} +#endif + otError Udp::Connect(SocketHandle &aSocket, const SockAddr &aSockAddr) { otError error = OT_ERROR_NONE; @@ -296,14 +341,34 @@ exit: void Udp::AddSocket(SocketHandle &aSocket) { - IgnoreError(mSockets.Add(aSocket)); + SuccessOrExit(mSockets.Add(aSocket)); + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (mPrevBackboneSockets == nullptr) + { + mPrevBackboneSockets = &aSocket; + } +#endif +exit: + return; } void Udp::RemoveSocket(SocketHandle &aSocket) { - SuccessOrExit(mSockets.Remove(aSocket)); + SocketHandle *prev; + + SuccessOrExit(mSockets.Find(aSocket, prev)); + + mSockets.PopAfter(prev); aSocket.SetNext(nullptr); +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (&aSocket == mPrevBackboneSockets) + { + mPrevBackboneSockets = prev; + } +#endif + exit: return; } @@ -397,7 +462,27 @@ void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo) SocketHandle *socket; SocketHandle *prev; +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + { + const SocketHandle *socketsBegin, *socketsEnd; + + if (!aMessageInfo.IsHostInterface()) + { + socketsBegin = mSockets.GetHead(); + socketsEnd = GetBackboneSockets(); + } + else + { + socketsBegin = GetBackboneSockets(); + socketsEnd = nullptr; + } + + socket = mSockets.FindMatching(socketsBegin, socketsEnd, aMessageInfo, prev); + } +#else socket = mSockets.FindMatching(aMessageInfo, prev); +#endif + VerifyOrExit(socket != nullptr, OT_NOOP); aMessage.RemoveHeader(aMessage.GetOffset()); diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp index 2acff21bf..c1535a02c 100644 --- a/src/core/net/udp6.hpp +++ b/src/core/net/udp6.hpp @@ -177,7 +177,6 @@ public: */ otError Bind(const SockAddr &aSockAddr); -#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE /** * This method binds the UDP socket to a specified network interface. * @@ -188,7 +187,6 @@ public: * */ otError BindToNetif(otNetifIdentifier aNetifIdentifier); -#endif // OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE /** * This method binds the UDP socket. @@ -438,6 +436,15 @@ public: */ otError Bind(SocketHandle &aSocket, const SockAddr &aSockAddr); + /** + * This method binds a UDP socket to the Network interface. + * + * @param[in] aSocket A reference to the socket. + * @param[in] aNetifIdentifier The network interface identifier. + * + */ + void BindToNetif(SocketHandle &aSocket, otNetifIdentifier aNetifIdentifier); + /** * This method connects a UDP socket. * @@ -562,9 +569,17 @@ private: void RemoveSocket(SocketHandle &aSocket); bool IsMlePort(uint16_t aPort) const; +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + void SetBackboneSocket(SocketHandle &aSocket); + const SocketHandle *GetBackboneSockets(void); +#endif + uint16_t mEphemeralPort; LinkedList mReceivers; LinkedList mSockets; +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + SocketHandle *mPrevBackboneSockets; +#endif #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE void * mUdpForwarderContext; otUdpForwarder mUdpForwarder; diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index 4eaf2c0ec..23b2507cb 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -51,6 +51,7 @@ #include "backbone_router/bbr_leader.hpp" #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +#include "backbone_router/backbone_tmf.hpp" #include "backbone_router/bbr_local.hpp" #include "backbone_router/bbr_manager.hpp" #endif diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index 24963d0df..0d6977fd3 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -40,16 +40,7 @@ namespace Tmf { otError TmfAgent::Start(void) { - otError error; - - SuccessOrExit(error = Coap::Start(kUdpPort)); -#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE - error = mSocket.BindToNetif(OT_NETIF_THREAD); - VerifyOrExit(OT_ERROR_NONE == error, IgnoreError(mSocket.Close())); -#endif - -exit: - return error; + return Coap::Start(kUdpPort, OT_NETIF_THREAD); } otError TmfAgent::Filter(const ot::Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext) diff --git a/src/posix/main.c b/src/posix/main.c index 35cded2d5..baefa15f7 100644 --- a/src/posix/main.c +++ b/src/posix/main.c @@ -103,6 +103,9 @@ void __gcov_flush(); */ enum { +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + OT_POSIX_OPT_BACKBONE_INTERFACE_NAME = 'B', +#endif OT_POSIX_OPT_DEBUG_LEVEL = 'd', OT_POSIX_OPT_DRY_RUN = 'n', OT_POSIX_OPT_HELP = 'h', @@ -116,15 +119,19 @@ enum OT_POSIX_OPT_REAL_TIME_SIGNAL, }; -static const struct option kOptions[] = {{"debug-level", required_argument, NULL, OT_POSIX_OPT_DEBUG_LEVEL}, - {"dry-run", no_argument, NULL, OT_POSIX_OPT_DRY_RUN}, - {"help", no_argument, NULL, OT_POSIX_OPT_HELP}, - {"interface-name", required_argument, NULL, OT_POSIX_OPT_INTERFACE_NAME}, - {"radio-version", no_argument, NULL, OT_POSIX_OPT_RADIO_VERSION}, - {"real-time-signal", required_argument, NULL, OT_POSIX_OPT_REAL_TIME_SIGNAL}, - {"time-speed", required_argument, NULL, OT_POSIX_OPT_TIME_SPEED}, - {"verbose", no_argument, NULL, OT_POSIX_OPT_VERBOSE}, - {0, 0, 0, 0}}; +static const struct option kOptions[] = { +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + {"backbone-interface-name", required_argument, NULL, OT_POSIX_OPT_BACKBONE_INTERFACE_NAME}, +#endif + {"debug-level", required_argument, NULL, OT_POSIX_OPT_DEBUG_LEVEL}, + {"dry-run", no_argument, NULL, OT_POSIX_OPT_DRY_RUN}, + {"help", no_argument, NULL, OT_POSIX_OPT_HELP}, + {"interface-name", required_argument, NULL, OT_POSIX_OPT_INTERFACE_NAME}, + {"radio-version", no_argument, NULL, OT_POSIX_OPT_RADIO_VERSION}, + {"real-time-signal", required_argument, NULL, OT_POSIX_OPT_REAL_TIME_SIGNAL}, + {"time-speed", required_argument, NULL, OT_POSIX_OPT_TIME_SPEED}, + {"verbose", no_argument, NULL, OT_POSIX_OPT_VERBOSE}, + {0, 0, 0, 0}}; static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode) { @@ -132,6 +139,9 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode) "Syntax:\n" " %s [Options] RadioURL\n" "Options:\n" +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + " -B --backbone-interface-name Backbone network interface name.\n" +#endif " -d --debug-level Debug level of logging.\n" " -h --help Display this usage information.\n" " -I --interface-name name Thread network interface name.\n" @@ -165,7 +175,12 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig) while (true) { int index = 0; - int option = getopt_long(aArgCount, aArgVector, "d:hI:ns:v", kOptions, &index); + int option = getopt_long(aArgCount, aArgVector, +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + "B:" +#endif + "d:hI:ns:v", + kOptions, &index); if (option == -1) { @@ -183,6 +198,11 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig) case OT_POSIX_OPT_INTERFACE_NAME: aConfig->mPlatformConfig.mInterfaceName = optarg; break; +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + case OT_POSIX_OPT_BACKBONE_INTERFACE_NAME: + aConfig->mPlatformConfig.mBackboneInterfaceName = optarg; + break; +#endif case OT_POSIX_OPT_DRY_RUN: aConfig->mIsDryRun = true; break; diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index 9d9c14e36..8496d6ba7 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -61,6 +61,7 @@ list(APPEND OT_PLATFORM_DEFINES "OPENTHREAD_PROJECT_CORE_CONFIG_FILE=\"${OT_CONF add_library(openthread-posix alarm.cpp + backbone.cpp entropy.cpp hdlc_interface.cpp logging.cpp diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index c93bc216b..8401b46c6 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -45,6 +45,7 @@ libopenthread_posix_a_CPPFLAGS = \ libopenthread_posix_a_SOURCES = \ alarm.cpp \ + backbone.cpp \ entropy.cpp \ hdlc_interface.cpp \ logging.cpp \ diff --git a/src/posix/platform/backbone.cpp b/src/posix/platform/backbone.cpp new file mode 100644 index 000000000..d3d7fb8bc --- /dev/null +++ b/src/posix/platform/backbone.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, 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 platform Backbone interface management on Linux. + */ + +#include "openthread-posix-config.h" + +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + +#include "platform-posix.h" +#include "common/code_utils.hpp" + +char gBackboneNetifName[IFNAMSIZ] = ""; +unsigned int gBackboneNetifIndex = 0; + +void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName) +{ + OT_UNUSED_VARIABLE(aInstance); + + VerifyOrExit(aInterfaceName != nullptr, OT_NOOP); + + VerifyOrDie(strnlen(aInterfaceName, IFNAMSIZ) <= IFNAMSIZ - 1, OT_EXIT_INVALID_ARGUMENTS); + strcpy(gBackboneNetifName, aInterfaceName); + + gBackboneNetifIndex = if_nametoindex(gBackboneNetifName); + VerifyOrDie(gBackboneNetifIndex > 0, OT_EXIT_FAILURE); +exit: + return; +} + +#endif diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index 6c63301c6..27c75f479 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -70,10 +70,11 @@ enum */ typedef struct otPlatformConfig { - const char *mInterfaceName; ///< Thread network interface name. - const char *mRadioUrl; ///< Radio url. - int mRealTimeSignal; ///< The real-time signal for microsecond timer. - uint32_t mSpeedUpFactor; ///< Speed up factor. + const char *mBackboneInterfaceName; ///< Backbone network interface name. + const char *mInterfaceName; ///< Thread network interface name. + const char *mRadioUrl; ///< Radio url. + int mRealTimeSignal; ///< The real-time signal for microsecond timer. + uint32_t mSpeedUpFactor; ///< Speed up factor. } otPlatformConfig; /** diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index d22cf1081..6d360df9b 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -407,6 +407,29 @@ extern char gNetifName[IFNAMSIZ]; */ extern unsigned int gNetifIndex; +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +/** + * This function initializes platform Backbone network. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in] aInterfaceName A pointer to Thread network interface name. + * + */ +void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName); + +/** + * The name of Backbone network interface. + * + */ +extern char gBackboneNetifName[IFNAMSIZ]; + +/** + * The index of Backbone network interface. + * + */ +extern unsigned int gBackboneNetifIndex; +#endif + #ifdef __cplusplus } #endif diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index 04925f3a5..eda4231ae 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -63,6 +63,10 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig) instance = otInstanceInitSingle(); assert(instance != nullptr); +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + platformBackboneInit(instance, aPlatformConfig->mBackboneInterfaceName); +#endif + #if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE platformNetifInit(instance, aPlatformConfig->mInterfaceName); #elif OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE diff --git a/src/posix/platform/udp.cpp b/src/posix/platform/udp.cpp index 16692d907..ea46da18d 100644 --- a/src/posix/platform/udp.cpp +++ b/src/posix/platform/udp.cpp @@ -276,9 +276,6 @@ otError otPlatUdpBind(otUdpSocket *aUdpSocket) VerifyOrExit(0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)), error = OT_ERROR_FAILED); } - VerifyOrExit(0 == setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &gNetifIndex, sizeof(gNetifIndex)), - error = OT_ERROR_FAILED); - exit: if (error == OT_ERROR_FAILED) { @@ -316,6 +313,21 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId #endif // __linux__ break; } + case OT_NETIF_BACKBONE: + { +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +#if __linux__ + VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, gBackboneNetifName, strlen(gBackboneNetifName)) == 0, + error = OT_ERROR_FAILED); +#else // __NetBSD__ || __FreeBSD__ || __APPLE__ + VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &gBackboneNetifIndex, sizeof(gBackboneNetifIndex)), + error = OT_ERROR_FAILED); +#endif // __linux__ +#else + ExitNow(error = OT_ERROR_NOT_IMPLEMENTED); +#endif + break; + } } exit: