[border-router] border routing optional at runtime (#6629)

This commit allows launching an OpenThread daemon which was built with
backbone-router and border-routing support but disabling them at runtime
by not specifying the `-B` option.
This commit is contained in:
Yakun Xu
2021-05-17 18:26:20 -07:00
committed by GitHub
parent d3b1a0dac7
commit 3e19ce1f1f
12 changed files with 579 additions and 288 deletions
+2
View File
@@ -145,6 +145,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \
LOCAL_CPPFLAGS := \
-std=c++11 \
-Wno-error=non-virtual-dtor \
-pedantic-errors \
$(NULL)
@@ -355,6 +356,7 @@ LOCAL_SRC_FILES := \
src/posix/platform/hdlc_interface.cpp \
src/posix/platform/infra_if.cpp \
src/posix/platform/logging.cpp \
src/posix/platform/mainloop.cpp \
src/posix/platform/memory.cpp \
src/posix/platform/misc.cpp \
src/posix/platform/multicast_routing.cpp \
+1
View File
@@ -76,6 +76,7 @@ add_library(openthread-posix
hdlc_interface.cpp
infra_if.cpp
logging.cpp
mainloop.cpp
memory.cpp
misc.cpp
multicast_routing.cpp
+2
View File
@@ -51,6 +51,7 @@ libopenthread_posix_a_SOURCES = \
hdlc_interface.cpp \
infra_if.cpp \
logging.cpp \
mainloop.cpp \
memory.cpp \
misc.cpp \
multicast_routing.cpp \
@@ -72,6 +73,7 @@ libopenthread_posix_a_LIBADD
noinst_HEADERS = \
hdlc_interface.hpp \
mainloop.hpp \
multicast_routing.hpp \
openthread-posix-config.h \
platform-posix.h \
+5 -20
View File
@@ -38,6 +38,7 @@
#include "multicast_routing.hpp"
#include "platform-posix.h"
#include "common/code_utils.hpp"
#include "posix/platform/mainloop.hpp"
char gBackboneNetifName[IFNAMSIZ] = "";
unsigned int gBackboneNetifIndex = 0;
@@ -49,10 +50,10 @@ void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName)
{
OT_UNUSED_VARIABLE(aInstance);
VerifyOrDie(aInterfaceName != nullptr, OT_EXIT_INVALID_ARGUMENTS);
VerifyOrExit(aInterfaceName != nullptr);
VerifyOrDie(strnlen(aInterfaceName, IFNAMSIZ) <= IFNAMSIZ - 1, OT_EXIT_INVALID_ARGUMENTS);
strcpy(gBackboneNetifName, aInterfaceName);
strncpy(gBackboneNetifName, aInterfaceName, sizeof(gBackboneNetifName));
gBackboneNetifIndex = if_nametoindex(gBackboneNetifName);
VerifyOrDie(gBackboneNetifIndex > 0, OT_EXIT_FAILURE);
@@ -62,25 +63,9 @@ void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName)
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
sMulticastRoutingManager.Init(aInstance);
#endif
}
void platformBackboneUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd)
{
OT_UNUSED_VARIABLE(aReadFdSet);
OT_UNUSED_VARIABLE(aMaxFd);
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
sMulticastRoutingManager.UpdateFdSet(aReadFdSet, aMaxFd);
#endif
}
void platformBackboneProcess(const fd_set &aReadSet)
{
OT_UNUSED_VARIABLE(aReadSet);
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
sMulticastRoutingManager.Process(aReadSet);
#endif
exit:
return;
}
void platformBackboneStateChange(otInstance *aInstance, otChangedFlags aFlags)
+200 -176
View File
@@ -58,16 +58,7 @@
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "lib/platform/exit_code.h"
static char sInfraIfName[IFNAMSIZ];
static uint32_t sInfraIfIndex = 0;
static int sInfraIfIcmp6Socket = -1;
static int sNetLinkSocket = -1;
static int CreateIcmp6Socket(void);
static int CreateNetLinkSocket(void);
static void ReceiveNetLinkMessage(otInstance *aInstance);
static void ReceiveIcmp6Message(otInstance *aInstance);
#include "posix/platform/infra_if.hpp"
bool otPlatInfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
{
@@ -102,95 +93,19 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
const uint8_t * aBuffer,
uint16_t aBufferLength)
{
otError error = OT_ERROR_NONE;
struct iovec iov;
struct in6_pktinfo *packetInfo;
int hopLimit = 255;
uint8_t cmsgBuffer[CMSG_SPACE(sizeof(*packetInfo)) + CMSG_SPACE(sizeof(hopLimit))];
struct msghdr msgHeader;
struct cmsghdr * cmsgPointer;
ssize_t rval;
struct sockaddr_in6 dest;
VerifyOrExit(sInfraIfIcmp6Socket >= 0, error = OT_ERROR_FAILED);
VerifyOrExit(aInfraIfIndex == sInfraIfIndex, error = OT_ERROR_DROP);
memset(cmsgBuffer, 0, sizeof(cmsgBuffer));
// Send the message
memset(&dest, 0, sizeof(dest));
dest.sin6_family = AF_INET6;
memcpy(&dest.sin6_addr, aDestAddress, sizeof(*aDestAddress));
if (IN6_IS_ADDR_LINKLOCAL(&dest.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dest.sin6_addr))
{
dest.sin6_scope_id = sInfraIfIndex;
}
iov.iov_base = const_cast<uint8_t *>(aBuffer);
iov.iov_len = aBufferLength;
msgHeader.msg_namelen = sizeof(dest);
msgHeader.msg_name = &dest;
msgHeader.msg_iov = &iov;
msgHeader.msg_iovlen = 1;
msgHeader.msg_control = cmsgBuffer;
msgHeader.msg_controllen = sizeof(cmsgBuffer);
// Specify the interface.
cmsgPointer = CMSG_FIRSTHDR(&msgHeader);
cmsgPointer->cmsg_level = IPPROTO_IPV6;
cmsgPointer->cmsg_type = IPV6_PKTINFO;
cmsgPointer->cmsg_len = CMSG_LEN(sizeof(*packetInfo));
packetInfo = (struct in6_pktinfo *)CMSG_DATA(cmsgPointer);
memset(packetInfo, 0, sizeof(*packetInfo));
packetInfo->ipi6_ifindex = sInfraIfIndex;
// Per section 6.1.2 of RFC 4861, we need to send the ICMPv6 message with IP Hop Limit 255.
cmsgPointer = CMSG_NXTHDR(&msgHeader, cmsgPointer);
cmsgPointer->cmsg_level = IPPROTO_IPV6;
cmsgPointer->cmsg_type = IPV6_HOPLIMIT;
cmsgPointer->cmsg_len = CMSG_LEN(sizeof(hopLimit));
memcpy(CMSG_DATA(cmsgPointer), &hopLimit, sizeof(hopLimit));
rval = sendmsg(sInfraIfIcmp6Socket, &msgHeader, 0);
if (rval < 0)
{
otLogWarnPlat("failed to send ICMPv6 message: %s", strerror(errno));
ExitNow(error = OT_ERROR_FAILED);
}
if (static_cast<size_t>(rval) != iov.iov_len)
{
otLogWarnPlat("failed to send ICMPv6 message: partially sent");
ExitNow(error = OT_ERROR_FAILED);
}
exit:
return error;
return ot::Posix::InfraNetif::Get().SendIcmp6Nd(aInfraIfIndex, *aDestAddress, aBuffer, aBufferLength);
}
bool platformInfraIfIsRunning(void)
{
int sock;
struct ifreq ifReq;
OT_ASSERT(sInfraIfIndex != 0);
sock = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketBlock);
VerifyOrDie(sock != -1, OT_EXIT_ERROR_ERRNO);
memset(&ifReq, 0, sizeof(ifReq));
strncpy(ifReq.ifr_name, sInfraIfName, sizeof(ifReq.ifr_name));
VerifyOrDie(ioctl(sock, SIOCGIFFLAGS, &ifReq) != -1, OT_EXIT_ERROR_ERRNO);
close(sock);
return (ifReq.ifr_flags & IFF_RUNNING);
return ot::Posix::InfraNetif::Get().IsRunning();
}
static int CreateIcmp6Socket(void)
namespace ot {
namespace Posix {
namespace {
int CreateIcmp6Socket(void)
{
int sock;
int rval;
@@ -235,76 +150,8 @@ static int CreateIcmp6Socket(void)
return sock;
}
uint32_t platformInfraIfInit(otInstance *aInstance, const char *aIfName)
{
OT_UNUSED_VARIABLE(aInstance);
ssize_t rval;
uint32_t ifIndex = 0;
if (strlen(aIfName) >= sizeof(sInfraIfName))
{
otLogCritPlat("infra interface name '%s' is too long", aIfName);
DieNow(OT_EXIT_INVALID_ARGUMENTS);
}
strcpy(sInfraIfName, aIfName);
// Initializes the infra interface.
ifIndex = if_nametoindex(aIfName);
if (ifIndex == 0)
{
otLogCritPlat("failed to get the index for infra interface %s", aIfName);
DieNow(OT_EXIT_INVALID_ARGUMENTS);
}
sInfraIfIndex = ifIndex;
sInfraIfIcmp6Socket = CreateIcmp6Socket();
#ifdef __linux__
rval = setsockopt(sInfraIfIcmp6Socket, SOL_SOCKET, SO_BINDTODEVICE, sInfraIfName, strlen(sInfraIfName));
#else // __NetBSD__ || __FreeBSD__ || __APPLE__
rval = setsockopt(sInfraIfIcmp6Socket, IPPROTO_IP, IP_BOUND_IF, &sInfraIfIndex, sizeof(sInfraIfIndex));
#endif // __linux__
VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO);
sNetLinkSocket = CreateNetLinkSocket();
return sInfraIfIndex;
}
void platformInfraIfDeinit(void)
{
if (sInfraIfIcmp6Socket != -1)
{
close(sInfraIfIcmp6Socket);
sInfraIfIcmp6Socket = -1;
}
if (sNetLinkSocket != -1)
{
close(sNetLinkSocket);
sNetLinkSocket = -1;
}
sInfraIfIndex = 0;
}
void platformInfraIfUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd)
{
VerifyOrExit(sInfraIfIcmp6Socket != -1);
VerifyOrExit(sNetLinkSocket != -1);
FD_SET(sInfraIfIcmp6Socket, &aReadFdSet);
aMaxFd = OT_MAX(aMaxFd, sInfraIfIcmp6Socket);
FD_SET(sNetLinkSocket, &aReadFdSet);
aMaxFd = OT_MAX(aMaxFd, sNetLinkSocket);
exit:
return;
}
// Create a net-link socket that subscribes to link & addresses events.
static int CreateNetLinkSocket(void)
int CreateNetLinkSocket(void)
{
int sock;
int rval;
@@ -324,7 +171,175 @@ static int CreateNetLinkSocket(void)
return sock;
}
static void ReceiveNetLinkMessage(otInstance *aInstance)
} // namespace
otError InfraNetif::SendIcmp6Nd(uint32_t aInfraIfIndex,
const otIp6Address &aDestAddress,
const uint8_t * aBuffer,
uint16_t aBufferLength)
{
otError error = OT_ERROR_NONE;
struct iovec iov;
struct in6_pktinfo *packetInfo;
int hopLimit = 255;
uint8_t cmsgBuffer[CMSG_SPACE(sizeof(*packetInfo)) + CMSG_SPACE(sizeof(hopLimit))];
struct msghdr msgHeader;
struct cmsghdr * cmsgPointer;
ssize_t rval;
struct sockaddr_in6 dest;
VerifyOrExit(mInfraIfIcmp6Socket >= 0, error = OT_ERROR_FAILED);
VerifyOrExit(aInfraIfIndex == mInfraIfIndex, error = OT_ERROR_DROP);
memset(cmsgBuffer, 0, sizeof(cmsgBuffer));
// Send the message
memset(&dest, 0, sizeof(dest));
dest.sin6_family = AF_INET6;
memcpy(&dest.sin6_addr, &aDestAddress, sizeof(aDestAddress));
if (IN6_IS_ADDR_LINKLOCAL(&dest.sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dest.sin6_addr))
{
dest.sin6_scope_id = mInfraIfIndex;
}
iov.iov_base = const_cast<uint8_t *>(aBuffer);
iov.iov_len = aBufferLength;
msgHeader.msg_namelen = sizeof(dest);
msgHeader.msg_name = &dest;
msgHeader.msg_iov = &iov;
msgHeader.msg_iovlen = 1;
msgHeader.msg_control = cmsgBuffer;
msgHeader.msg_controllen = sizeof(cmsgBuffer);
// Specify the interface.
cmsgPointer = CMSG_FIRSTHDR(&msgHeader);
cmsgPointer->cmsg_level = IPPROTO_IPV6;
cmsgPointer->cmsg_type = IPV6_PKTINFO;
cmsgPointer->cmsg_len = CMSG_LEN(sizeof(*packetInfo));
packetInfo = (struct in6_pktinfo *)CMSG_DATA(cmsgPointer);
memset(packetInfo, 0, sizeof(*packetInfo));
packetInfo->ipi6_ifindex = mInfraIfIndex;
// Per section 6.1.2 of RFC 4861, we need to send the ICMPv6 message with IP Hop Limit 255.
cmsgPointer = CMSG_NXTHDR(&msgHeader, cmsgPointer);
cmsgPointer->cmsg_level = IPPROTO_IPV6;
cmsgPointer->cmsg_type = IPV6_HOPLIMIT;
cmsgPointer->cmsg_len = CMSG_LEN(sizeof(hopLimit));
memcpy(CMSG_DATA(cmsgPointer), &hopLimit, sizeof(hopLimit));
rval = sendmsg(mInfraIfIcmp6Socket, &msgHeader, 0);
if (rval < 0)
{
otLogWarnPlat("failed to send ICMPv6 message: %s", strerror(errno));
ExitNow(error = OT_ERROR_FAILED);
}
if (static_cast<size_t>(rval) != iov.iov_len)
{
otLogWarnPlat("failed to send ICMPv6 message: partially sent");
ExitNow(error = OT_ERROR_FAILED);
}
exit:
return error;
}
bool InfraNetif::IsRunning(void) const
{
int sock;
struct ifreq ifReq;
OT_ASSERT(mInfraIfIndex != 0);
sock = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketBlock);
VerifyOrDie(sock != -1, OT_EXIT_ERROR_ERRNO);
memset(&ifReq, 0, sizeof(ifReq));
strncpy(ifReq.ifr_name, mInfraIfName, sizeof(ifReq.ifr_name));
VerifyOrDie(ioctl(sock, SIOCGIFFLAGS, &ifReq) != -1, OT_EXIT_ERROR_ERRNO);
close(sock);
return (ifReq.ifr_flags & IFF_RUNNING);
}
void InfraNetif::Init(otInstance *aInstance, const char *aIfName)
{
ssize_t rval;
uint32_t ifIndex = 0;
VerifyOrExit(aIfName != nullptr);
VerifyOrDie(strnlen(aIfName, sizeof(mInfraIfName)) <= sizeof(mInfraIfName) - 1, OT_EXIT_INVALID_ARGUMENTS);
strncpy(mInfraIfName, aIfName, sizeof(mInfraIfName));
// Initializes the infra interface.
ifIndex = if_nametoindex(aIfName);
if (ifIndex == 0)
{
otLogCritPlat("failed to get the index for infra interface %s", aIfName);
DieNow(OT_EXIT_INVALID_ARGUMENTS);
}
mInfraIfIndex = ifIndex;
mInfraIfIcmp6Socket = CreateIcmp6Socket();
#ifdef __linux__
rval = setsockopt(mInfraIfIcmp6Socket, SOL_SOCKET, SO_BINDTODEVICE, mInfraIfName, strlen(mInfraIfName));
#else // __NetBSD__ || __FreeBSD__ || __APPLE__
rval = setsockopt(mInfraIfIcmp6Socket, IPPROTO_IP, IP_BOUND_IF, &mInfraIfIndex, sizeof(mInfraIfIndex));
#endif // __linux__
VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO);
mNetLinkSocket = CreateNetLinkSocket();
SuccessOrDie(otBorderRoutingInit(aInstance, ifIndex, platformInfraIfIsRunning()));
SuccessOrDie(otBorderRoutingSetEnabled(aInstance, /* aEnabled */ true));
mInstance = aInstance;
Mainloop::Manager::Get().Add(*this);
exit:
return;
}
void InfraNetif::Deinit(void)
{
Mainloop::Manager::Get().Remove(*this);
if (mInfraIfIcmp6Socket != -1)
{
close(mInfraIfIcmp6Socket);
mInfraIfIcmp6Socket = -1;
}
if (mNetLinkSocket != -1)
{
close(mNetLinkSocket);
mNetLinkSocket = -1;
}
mInfraIfIndex = 0;
}
void InfraNetif::Update(otSysMainloopContext &aContext)
{
VerifyOrExit(mInfraIfIcmp6Socket != -1);
VerifyOrExit(mNetLinkSocket != -1);
FD_SET(mInfraIfIcmp6Socket, &aContext.mReadFdSet);
aContext.mMaxFd = OT_MAX(aContext.mMaxFd, mInfraIfIcmp6Socket);
FD_SET(mNetLinkSocket, &aContext.mReadFdSet);
aContext.mMaxFd = OT_MAX(aContext.mMaxFd, mNetLinkSocket);
exit:
return;
}
void InfraNetif::ReceiveNetLinkMessage(void)
{
const size_t kMaxNetLinkBufSize = 8192;
ssize_t len;
@@ -334,7 +349,7 @@ static void ReceiveNetLinkMessage(otInstance *aInstance)
uint8_t mBuffer[kMaxNetLinkBufSize];
} msgBuffer;
len = recv(sNetLinkSocket, msgBuffer.mBuffer, sizeof(msgBuffer.mBuffer), 0);
len = recv(mNetLinkSocket, msgBuffer.mBuffer, sizeof(msgBuffer.mBuffer), 0);
if (len < 0)
{
otLogCritPlat("failed to receive netlink message: %s", strerror(errno));
@@ -353,7 +368,7 @@ static void ReceiveNetLinkMessage(otInstance *aInstance)
case RTM_DELADDR:
case RTM_NEWLINK:
case RTM_DELLINK:
SuccessOrDie(otPlatInfraIfStateChanged(aInstance, sInfraIfIndex, platformInfraIfIsRunning()));
SuccessOrDie(otPlatInfraIfStateChanged(mInstance, mInfraIfIndex, platformInfraIfIsRunning()));
break;
case NLMSG_ERROR:
{
@@ -371,7 +386,7 @@ exit:
return;
}
static void ReceiveIcmp6Message(otInstance *aInstance)
void InfraNetif::ReceiveIcmp6Message(void)
{
otError error = OT_ERROR_NONE;
uint8_t buffer[1500];
@@ -400,7 +415,7 @@ static void ReceiveIcmp6Message(otInstance *aInstance)
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
rval = recvmsg(sInfraIfIcmp6Socket, &msg, 0);
rval = recvmsg(mInfraIfIcmp6Socket, &msg, 0);
if (rval < 0)
{
otLogWarnPlat("failed to receive ICMPv6 message: %s", strerror(errno));
@@ -427,13 +442,13 @@ static void ReceiveIcmp6Message(otInstance *aInstance)
}
}
VerifyOrExit(ifIndex == sInfraIfIndex, error = OT_ERROR_DROP);
VerifyOrExit(ifIndex == mInfraIfIndex, error = OT_ERROR_DROP);
// We currently accept only RA & RS messages for the Border Router and it requires that
// the hoplimit must be 255 and the source address must be a link-local address.
VerifyOrExit(hopLimit == 255 && IN6_IS_ADDR_LINKLOCAL(&srcAddr.sin6_addr), error = OT_ERROR_DROP);
otPlatInfraIfRecvIcmp6Nd(aInstance, ifIndex, reinterpret_cast<otIp6Address *>(&srcAddr.sin6_addr), buffer,
otPlatInfraIfRecvIcmp6Nd(mInstance, ifIndex, reinterpret_cast<otIp6Address *>(&srcAddr.sin6_addr), buffer,
bufferLength);
exit:
@@ -443,23 +458,32 @@ exit:
}
}
void platformInfraIfProcess(otInstance *aInstance, const fd_set &aReadFdSet)
void InfraNetif::Process(const otSysMainloopContext &aContext)
{
VerifyOrExit(sInfraIfIcmp6Socket != -1);
VerifyOrExit(sNetLinkSocket != -1);
VerifyOrExit(mInfraIfIcmp6Socket != -1);
VerifyOrExit(mNetLinkSocket != -1);
if (FD_ISSET(sInfraIfIcmp6Socket, &aReadFdSet))
if (FD_ISSET(mInfraIfIcmp6Socket, &aContext.mReadFdSet))
{
ReceiveIcmp6Message(aInstance);
ReceiveIcmp6Message();
}
if (FD_ISSET(sNetLinkSocket, &aReadFdSet))
if (FD_ISSET(mNetLinkSocket, &aContext.mReadFdSet))
{
ReceiveNetLinkMessage(aInstance);
ReceiveNetLinkMessage();
}
exit:
return;
}
InfraNetif &InfraNetif::Get(void)
{
static InfraNetif sInstance;
return sInstance;
}
} // namespace Posix
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2021, 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 infrastructure interface for posix.
*/
#include "openthread-posix-config.h"
#include <net/if.h>
#include "core/common/non_copyable.hpp"
#include "posix/platform/mainloop.hpp"
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
namespace ot {
namespace Posix {
/**
* This class manages infrastructure network interface.
*
*/
class InfraNetif : public Mainloop::Source, private NonCopyable
{
public:
/**
* This method updates the fd_set and timeout for mainloop.
*
* @param[inout] aContext A reference to the mainloop context.
*
*/
void Update(otSysMainloopContext &aContext) override;
/**
* This method performs infrastructure network interface processing.
*
* @param[in] aContext A reference to the mainloop context.
*
*/
void Process(const otSysMainloopContext &aContext) override;
/**
* This method initializes the infrastructure network interface.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aIfName A pointer to infrastructure network interface name.
*
*/
void Init(otInstance *aInstance, const char *aIfName);
/**
* This method deinitializes the infrastructure network interface.
*
*/
void Deinit(void);
/**
* This method checks whether the infrastructure network interface is running.
*
*/
bool IsRunning(void) const;
/**
* This method sends an ICMPv6 Neighbor Discovery message on given infrastructure interface.
*
* See RFC 4861: https://tools.ietf.org/html/rfc4861.
*
* @param[in] aInfraIfIndex The index of the infrastructure interface this message is sent to.
* @param[in] aDestAddress The destination address this message is sent to.
* @param[in] aBuffer The ICMPv6 message buffer. The ICMPv6 checksum is left zero and the
* platform should do the checksum calculate.
* @param[in] aBufferLength The length of the message buffer.
*
* @note Per RFC 4861, the implementation should send the message with IPv6 link-local source address
* of interface @p aInfraIfIndex and IP Hop Limit 255.
*
* @retval OT_ERROR_NONE Successfully sent the ICMPv6 message.
* @retval OT_ERROR_FAILED Failed to send the ICMPv6 message.
*
*/
otError SendIcmp6Nd(uint32_t aInfraIfIndex,
const otIp6Address &aDestAddress,
const uint8_t * aBuffer,
uint16_t aBufferLength);
/**
* This function gets the infrastructure network interface singleton.
*
* @returns The singleton object.
*/
static InfraNetif &Get(void);
private:
otInstance *mInstance;
char mInfraIfName[IFNAMSIZ];
uint32_t mInfraIfIndex = 0;
int mInfraIfIcmp6Socket = -1;
int mNetLinkSocket = -1;
void ReceiveNetLinkMessage(void);
void ReceiveIcmp6Message(void);
};
} // namespace Posix
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2021, 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.
*/
#include "posix/platform/mainloop.hpp"
#include <assert.h>
#include "core/common/code_utils.hpp"
namespace ot {
namespace Posix {
namespace Mainloop {
void Manager::Add(Source &aSource)
{
assert(aSource.mNext == nullptr);
aSource.mNext = mSources;
mSources = &aSource;
}
void Manager::Remove(Source &aSource)
{
for (Source **pnext = &mSources; *pnext != nullptr; pnext = &(*pnext)->mNext)
{
if (*pnext == &aSource)
{
*pnext = aSource.mNext;
break;
}
}
aSource.mNext = nullptr;
}
void Manager::Update(otSysMainloopContext &aContext)
{
for (Source *source = mSources; source != nullptr; source = source->mNext)
{
source->Update(aContext);
}
}
void Manager::Process(const otSysMainloopContext &aContext)
{
for (Source *source = mSources; source != nullptr; source = source->mNext)
{
source->Process(aContext);
}
}
Manager &Manager::Get(void)
{
static Manager sInstance;
return sInstance;
}
} // namespace Mainloop
} // namespace Posix
} // namespace ot
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2021, 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 SPI interface to radio (RCP).
*/
#ifndef OT_POSIX_PLATFORM_MAINLOOP_HPP_
#define OT_POSIX_PLATFORM_MAINLOOP_HPP_
#include <openthread/openthread-system.h>
namespace ot {
namespace Posix {
namespace Mainloop {
/**
* This class is the base for all mainloop event sources.
*
*/
class Source
{
friend class Manager;
public:
/**
* This method registers events in the mainloop.
*
* @param[inout] aContext A reference to the mainloop context.
*
*/
virtual void Update(otSysMainloopContext &aContext) = 0;
/**
* This method processes the mainloop events.
*
* @param[in] aContext A reference to the mainloop context.
*
*/
virtual void Process(const otSysMainloopContext &aContext) = 0;
private:
Source *mNext = nullptr;
};
/**
* This class manages mainloop.
*
*/
class Manager
{
public:
/**
* This method updates event polls in the mainloop context.
*
* @param[inout] aContext A reference to the mainloop context.
*
*/
void Update(otSysMainloopContext &aContext);
/**
* This method processes events in the mainloop context.
*
* @param[in] aContext A reference to the mainloop context.
*
*/
void Process(const otSysMainloopContext &aContext);
/**
* This method adds a new event source into the mainloop.
*
* @param[in] aSource A reference to the event source.
*
*/
void Add(Source &aSource);
/**
* This method removes an event source from the mainloop.
*
* @param[in] aSource A reference to the event source.
*
*/
void Remove(Source &aSource);
/**
* This function returns the Mainloop singleton.
*
* @returns A refernce to the Mainloop singleton.
*
*/
static Manager &Get(void);
private:
Source *mSources = nullptr;
};
} // namespace Mainloop
} // namespace Posix
} // namespace ot
#endif // OT_POSIX_PLATFORM_MAINLOOP_HPP_
+6 -5
View File
@@ -57,6 +57,7 @@ void MulticastRoutingManager::Init(otInstance *aInstance)
otBackboneRouterSetMulticastListenerCallback(aInstance,
&MulticastRoutingManager::HandleBackboneMulticastListenerEvent, this);
Mainloop::Manager::Get().Add(*this);
}
void MulticastRoutingManager::HandleBackboneMulticastListenerEvent(void * aContext,
@@ -138,24 +139,24 @@ exit:
return found;
}
void MulticastRoutingManager::UpdateFdSet(fd_set &aReadFdSet, int &aMaxFd) const
void MulticastRoutingManager::Update(otSysMainloopContext &aContext)
{
VerifyOrExit(IsEnabled());
FD_SET(mMulticastRouterSock, &aReadFdSet);
aMaxFd = OT_MAX(aMaxFd, mMulticastRouterSock);
FD_SET(mMulticastRouterSock, &aContext.mReadFdSet);
aContext.mMaxFd = OT_MAX(aContext.mMaxFd, mMulticastRouterSock);
exit:
return;
}
void MulticastRoutingManager::Process(const fd_set &aReadFdSet)
void MulticastRoutingManager::Process(const otSysMainloopContext &aContext)
{
VerifyOrExit(IsEnabled());
ExpireMulticastForwardingCache();
if (FD_ISSET(mMulticastRouterSock, &aReadFdSet))
if (FD_ISSET(mMulticastRouterSock, &aContext.mReadFdSet))
{
ProcessMulticastRouterMessages();
}
+7 -7
View File
@@ -43,6 +43,7 @@
#include "core/common/non_copyable.hpp"
#include "core/net/ip6_address.hpp"
#include "lib/url/url.hpp"
#include "posix/platform/mainloop.hpp"
namespace ot {
namespace Posix {
@@ -51,7 +52,7 @@ namespace Posix {
* This class implements Multicast Routing management.
*
*/
class MulticastRoutingManager : private NonCopyable
class MulticastRoutingManager : public Mainloop::Source, private NonCopyable
{
public:
/**
@@ -59,9 +60,9 @@ public:
*
*/
explicit MulticastRoutingManager()
: mLastExpireTime(0)
, mMulticastRouterSock(-1)
, mInstance(nullptr)
{
}
@@ -76,19 +77,18 @@ public:
/**
* This method updates the fd_set and timeout for mainloop.
*
* @param[inout] aReadFdSet A reference to fd_set for polling read.
* @param[inout] aMaxFd A reference to the current max fd in fd_sets.
* @param[inout] aContext A reference to the mainloop context.
*
*/
void UpdateFdSet(fd_set &aReadFdSet, int &aMaxFd) const;
void Update(otSysMainloopContext &aContext) override;
/**
* This method performs Multicast Routing processing.
*
* @param[in] aReadFdSet A reference to read file descriptors.
* @param[in] aContext A reference to the mainloop context.
*
*/
void Process(const fd_set &aReadFdSet);
void Process(const otSysMainloopContext &aContext) override;
/**
* This method handles Thread state changes.
-52
View File
@@ -462,23 +462,6 @@ extern unsigned int gNetifIndex;
*/
void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName);
/**
* This function updates the file descriptor sets with file descriptors used by the platform Backbone network.
*
* @param[inout] aReadFdSet A reference to the read file descriptors.
* @param[inout] aMaxFd A reference to the max file descriptor.
*
*/
void platformBackboneUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd);
/**
* This function performs platform Backbone network processing.
*
* @param[in] aReadFdSet A reference to the read file descriptors.
*
*/
void platformBackboneProcess(const fd_set &aReadSet);
/**
* This function performs notifies state changes to platform Backbone network.
*
@@ -500,23 +483,6 @@ extern char gBackboneNetifName[IFNAMSIZ];
*/
extern unsigned int gBackboneNetifIndex;
/**
* This function initializes the infrastructure interface.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aIfName The name of the infrastructure interface.
*
* @returns The index of the infrastructure interface.
*
*/
uint32_t platformInfraIfInit(otInstance *aInstance, const char *aIfName);
/**
* This function deinitializes the infrastructure interface.
*
*/
void platformInfraIfDeinit(void);
/**
* This function tells if the infrastructure interface is running.
*
@@ -525,24 +491,6 @@ void platformInfraIfDeinit(void);
*/
bool platformInfraIfIsRunning(void);
/**
* This function updates the read fd set.
*
* @param[out] aReadFdSet The fd set to be updated.
* @param[out] aMaxFd The maximum fd to be updated.
*
*/
void platformInfraIfUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd);
/**
* This function processes possible events on the infrastructure interface.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aReadFdSet The fd set which may contain read vents.
*
*/
void platformInfraIfProcess(otInstance *aInstance, const fd_set &aReadFdSet);
/**
* This function enables daemon.
*
+12 -28
View File
@@ -47,6 +47,8 @@
#include <openthread/platform/radio.h>
#include "common/code_utils.hpp"
#include "posix/platform/infra_if.hpp"
#include "posix/platform/mainloop.hpp"
#include "posix/platform/radio_url.hpp"
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
@@ -62,7 +64,10 @@ static void processStateChange(otChangedFlags aFlags, void *aContext)
#endif
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
platformBackboneStateChange(instance, aFlags);
if (gBackboneNetifIndex != 0)
{
platformBackboneStateChange(instance, aFlags);
}
#endif
}
#endif
@@ -127,20 +132,7 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
{
uint32_t infraIfIndex;
// Reuse the backbone interface name.
if (aPlatformConfig->mBackboneInterfaceName == nullptr || strlen(aPlatformConfig->mBackboneInterfaceName) == 0)
{
DieNowWithMessage("no infra interface is specified", OT_EXIT_INVALID_ARGUMENTS);
}
infraIfIndex = platformInfraIfInit(instance, aPlatformConfig->mBackboneInterfaceName);
SuccessOrDie(otBorderRoutingInit(instance, infraIfIndex, platformInfraIfIsRunning()));
SuccessOrDie(otBorderRoutingSetEnabled(instance, /* aEnabled */ true));
}
ot::Posix::InfraNetif::Get().Init(instance, aPlatformConfig->mBackboneInterfaceName);
#endif
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
@@ -178,7 +170,7 @@ void otSysDeinit(void)
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
platformInfraIfDeinit();
ot::Posix::InfraNetif::Get().Deinit();
#endif
}
@@ -217,6 +209,8 @@ static int trySelect(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSe
void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
{
ot::Posix::Mainloop::Manager::Get().Update(*aMainloop);
platformAlarmUpdateTimeout(&aMainloop->mTimeout);
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
platformUdpUpdateFdSet(aInstance, &aMainloop->mReadFdSet, &aMainloop->mMaxFd);
@@ -225,12 +219,6 @@ void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
platformNetifUpdateFdSet(&aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet,
&aMainloop->mMaxFd);
#endif
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
platformBackboneUpdateFdSet(aMainloop->mReadFdSet, aMainloop->mMaxFd);
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
platformInfraIfUpdateFdSet(aMainloop->mReadFdSet, aMainloop->mMaxFd);
#endif
#if OPENTHREAD_POSIX_VIRTUAL_TIME
virtualTimeUpdateFdSet(&aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet, &aMainloop->mMaxFd,
&aMainloop->mTimeout);
@@ -297,6 +285,8 @@ int otSysMainloopPoll(otSysMainloopContext *aMainloop)
void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMainloop)
{
ot::Posix::Mainloop::Manager::Get().Process(*aMainloop);
#if OPENTHREAD_POSIX_VIRTUAL_TIME
virtualTimeProcess(aInstance, &aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet);
#else
@@ -312,12 +302,6 @@ void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMa
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
platformUdpProcess(aInstance, &aMainloop->mReadFdSet);
#endif
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
platformBackboneProcess(aMainloop->mReadFdSet);
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
platformInfraIfProcess(aInstance, aMainloop->mReadFdSet);
#endif
#if OPENTHREAD_POSIX_CONFIG_DAEMON_ENABLE
platformDaemonProcess(aMainloop);
#endif