Skip to content

Commit

Permalink
[netif] add wpan multicast address subscribe/unsubscribe for NCP
Browse files Browse the repository at this point in the history
  • Loading branch information
Irving-cl committed Sep 5, 2024
1 parent e8ea2d3 commit 46cb697
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 25 deletions.
10 changes: 8 additions & 2 deletions src/ncp/ncp_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,14 @@ void NcpHost::Init(void)
{
otSysInit(&mConfig);
mNcpSpinel.Init(mSpinelDriver, *this);
mNetif.Init(mConfig.mInterfaceName,
[this](const uint8_t *aData, uint16_t aLength) { return mNcpSpinel.Ip6Send(aData, aLength); });
mNetif.Init(
mConfig.mInterfaceName,
[this](const uint8_t *aData, uint16_t aLength) { return mNcpSpinel.Ip6Send(aData, aLength); },
[this](const otIp6Address &aAddr, bool aIsAdded) {
OTBR_UNUSED_VARIABLE(aAddr);
OTBR_UNUSED_VARIABLE(aIsAdded);
return OTBR_ERROR_NOT_IMPLEMENTED;
});

mNcpSpinel.Ip6SetAddressCallback(
[this](const std::vector<Ip6AddressInfo> &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); });
Expand Down
193 changes: 191 additions & 2 deletions src/ncp/posix/netif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@

#include "netif.hpp"

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
Expand All @@ -50,21 +52,56 @@

namespace otbr {

#if NETIF_USE_MLD_MONITOR
OT_TOOL_PACKED_BEGIN
struct MLDv2Header
{
uint8_t mType;
uint8_t _rsv0;
uint16_t mChecksum;
uint16_t _rsv1;
uint16_t mNumRecords;
} OT_TOOL_PACKED_END;

OT_TOOL_PACKED_BEGIN
struct MLDv2Record
{
uint8_t mRecordType;
uint8_t mAuxDataLen;
uint16_t mNumSources;
struct in6_addr mMulticastAddress;
} OT_TOOL_PACKED_END;

enum
{
kICMPv6MLDv2Type = 143,
kICMPv6MLDv2RecordChangeToExcludeType = 3,
kICMPv6MLDv2RecordChangeToIncludeType = 4,
};
#endif // NETIF_USE_MLD_MONITOR

Netif::Netif(void)
: mTunFd(-1)
, mIpFd(-1)
, mNetlinkFd(-1)
#if NETIF_USE_MLD_MONITOR
, mMLDFd(-1)
#endif
, mNetlinkSequence(0)
, mNetifIndex(0)
{
}

otbrError Netif::Init(const std::string &aInterfaceName, const Ip6SendFunc &aIp6SendFunc)
otbrError Netif::Init(const std::string &aInterfaceName,
const Ip6SendFunc &aIp6SendFunc,
const Ip6MulAddrUpdateSubscriptionFunc &aIp6MulAddrUpdateSubscriptionFunc)
{
otbrError error = OTBR_ERROR_NONE;

VerifyOrExit(aIp6SendFunc, error = OTBR_ERROR_INVALID_ARGS);
mIp6SendFunc = aIp6SendFunc;
VerifyOrExit(aIp6MulAddrUpdateSubscriptionFunc, error = OTBR_ERROR_INVALID_ARGS);
mIp6MulAddrUpdateSubscriptionFunc = aIp6MulAddrUpdateSubscriptionFunc;

mIpFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_ERRNO);
Expand All @@ -75,6 +112,8 @@ otbrError Netif::Init(const std::string &aInterfaceName, const Ip6SendFunc &aIp6
mNetifIndex = if_nametoindex(mNetifName.c_str());
VerifyOrExit(mNetifIndex > 0, error = OTBR_ERROR_INVALID_STATE);

SuccessOrExit(error = InitMLDListener());

PlatformSpecificInit();

exit:
Expand All @@ -98,19 +137,40 @@ void Netif::Process(const MainloopContext *aContext)
DieNow("Error on Tun Fd!");
}

#if NETIF_USE_MLD_MONITOR
if (FD_ISSET(mMLDFd, &aContext->mErrorFdSet))
{
close(mMLDFd);
DieNow("Error on MLD Fd!");
}
#endif

if (FD_ISSET(mTunFd, &aContext->mReadFdSet))
{
ProcessIp6Send();
}

#if NETIF_USE_MLD_MONITOR
if (FD_ISSET(mMLDFd, &aContext->mReadFdSet))
{
ProcessMLDEvent();
}
#endif
}

void Netif::UpdateFdSet(MainloopContext *aContext)
{
assert(aContext != nullptr);
assert(mTunFd >= 0);
assert(mIpFd >= 0);
#if NETIF_USE_MLD_MONITOR
assert(mMLDFd >= 0);
#endif

aContext->AddFdToSet(mTunFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
#if NETIF_USE_MLD_MONITOR
aContext->AddFdToSet(mMLDFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
#endif
}

void Netif::UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aAddrInfos)
Expand Down Expand Up @@ -287,10 +347,139 @@ void Netif::Clear(void)
mNetlinkFd = -1;
}

#if NETIF_USE_MLD_MONITOR
if (mMLDFd != -1)
{
close(mMLDFd);
mMLDFd = -1;
}
#endif

mNetifIndex = 0;
mIp6UnicastAddresses.clear();
mIp6MulticastAddresses.clear();
mIp6SendFunc = nullptr;
mIp6SendFunc = nullptr;
mIp6MulAddrUpdateSubscriptionFunc = nullptr;
}

#if NETIF_USE_MLD_MONITOR
static const otIp6Address kMLDv2MulticastAddress = {
{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16}}};
static const otIp6Address kAllRouterLocalMulticastAddress = {
{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}};

static bool IsMulAddrFiltered(const otIp6Address &aAddr)
{
return memcmp(&aAddr, &kMLDv2MulticastAddress, sizeof(otIp6Address)) == 0 ||
memcmp(&aAddr, &kAllRouterLocalMulticastAddress, sizeof(otIp6Address)) == 0;
}

otbrError Netif::InitMLDListener(void)
{
otbrError error = OTBR_ERROR_NONE;
struct ipv6_mreq mreq6;

mMLDFd = SocketWithCloseExec(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, kSocketNonBlock);
VerifyOrExit(mMLDFd != -1, error = OTBR_ERROR_ERRNO);

mreq6.ipv6mr_interface = mNetifIndex;
memcpy(&mreq6.ipv6mr_multiaddr, kMLDv2MulticastAddress.mFields.m8, sizeof(kMLDv2MulticastAddress.mFields.m8));

VerifyOrExit(setsockopt(mMLDFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0,
error = OTBR_ERROR_ERRNO);
#ifdef __linux__
VerifyOrExit(setsockopt(mMLDFd, SOL_SOCKET, SO_BINDTODEVICE, mNetifName.c_str(),
static_cast<socklen_t>(mNetifName.length())) == 0,
error = OTBR_ERROR_ERRNO);
#endif

exit:
return error;
}

void Netif::ProcessMLDEvent(void)
{
const size_t kMaxMLDEvent = 8192;
uint8_t buffer[kMaxMLDEvent];
ssize_t bufferLen = -1;
struct sockaddr_in6 srcAddr;
socklen_t addrLen = sizeof(srcAddr);
bool fromSelf = false;
MLDv2Header *hdr = reinterpret_cast<MLDv2Header *>(buffer);
size_t offset;
uint8_t type;
struct ifaddrs *ifAddrs = nullptr;
char addressString[INET6_ADDRSTRLEN + 1];

bufferLen = recvfrom(mMLDFd, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr *>(&srcAddr), &addrLen);
VerifyOrExit(bufferLen > 0);

type = buffer[0];
VerifyOrExit(type == kICMPv6MLDv2Type && bufferLen >= static_cast<ssize_t>(sizeof(MLDv2Header)));

// Check whether it is sent by self
VerifyOrExit(getifaddrs(&ifAddrs) == 0);
for (struct ifaddrs *ifAddr = ifAddrs; ifAddr != nullptr; ifAddr = ifAddr->ifa_next)
{
if (ifAddr->ifa_addr != nullptr && ifAddr->ifa_addr->sa_family == AF_INET6 &&
strncmp(mNetifName.c_str(), ifAddr->ifa_name, IFNAMSIZ) == 0)
{
struct sockaddr_in6 *addr6 = reinterpret_cast<struct sockaddr_in6 *>(ifAddr->ifa_addr);

if (memcmp(&addr6->sin6_addr, &srcAddr.sin6_addr, sizeof(in6_addr)) == 0)
{
fromSelf = true;
break;
}
}
}
VerifyOrExit(fromSelf);

hdr = reinterpret_cast<MLDv2Header *>(buffer);
offset = sizeof(MLDv2Header);

for (size_t i = 0; i < ntohs(hdr->mNumRecords) && offset < static_cast<size_t>(bufferLen); i++)
{
if (static_cast<size_t>(bufferLen) >= (sizeof(MLDv2Record) + offset))
{
MLDv2Record *record = reinterpret_cast<MLDv2Record *>(&buffer[offset]);

otbrError error;
otIp6Address address;

memcpy(&address, &record->mMulticastAddress, sizeof(address));
if (IsMulAddrFiltered(address))
{
continue;
}

inet_ntop(AF_INET6, &record->mMulticastAddress, addressString, sizeof(addressString));

if (record->mRecordType == kICMPv6MLDv2RecordChangeToIncludeType)
{
error = mIp6MulAddrUpdateSubscriptionFunc(address, /* isAdd */ true);
}
else if (record->mRecordType == kICMPv6MLDv2RecordChangeToExcludeType)
{
error = mIp6MulAddrUpdateSubscriptionFunc(address, /* isAdd */ false);
}

offset += sizeof(MLDv2Record) + sizeof(in6_addr) * ntohs(record->mNumSources);

if (error != OTBR_ERROR_NONE)
{
otbrLogWarning("Failed to Update multicast subscription: %s", otbrErrorString(error));
}
}
}

exit:
if (ifAddrs)
{
freeifaddrs(ifAddrs);
}
}

#endif // NETIF_USE_MLD_MONITOR

} // namespace otbr
37 changes: 28 additions & 9 deletions src/ncp/posix/netif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,23 @@

namespace otbr {

#if defined(RTM_NEWMADDR) || defined(__NetBSD__)
#define NETIF_USE_MLD_MONITOR 0
#else
#define NETIF_USE_MLD_MONITOR 1
#endif

class Netif
{
public:
using Ip6SendFunc = std::function<otbrError(const uint8_t *, uint16_t)>;
using Ip6SendFunc = std::function<otbrError(const uint8_t *, uint16_t)>;
using Ip6MulAddrUpdateSubscriptionFunc = std::function<otbrError(const otIp6Address &, bool)>;

Netif(void);

otbrError Init(const std::string &aInterfaceName, const Ip6SendFunc &aIp6SendFunc);
otbrError Init(const std::string &aInterfaceName,
const Ip6SendFunc &aIp6SendFunc,
const Ip6MulAddrUpdateSubscriptionFunc &aIp6MulAddrUpdateSubscriptionFunc);
void Deinit(void);

void Process(const MainloopContext *aContext);
Expand All @@ -72,24 +81,34 @@ class Netif

otbrError CreateTunDevice(const std::string &aInterfaceName);
otbrError InitNetlink(void);
#if NETIF_USE_MLD_MONITOR
otbrError InitMLDListener(void);
#endif

void PlatformSpecificInit(void);
void SetAddrGenModeToNone(void);
void ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded);
otbrError ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded);
void ProcessIp6Send(void);

int mTunFd; ///< Used to exchange IPv6 packets.
int mIpFd; ///< Used to manage IPv6 stack on the network interface.
int mNetlinkFd; ///< Used to receive netlink events.
#if NETIF_USE_MLD_MONITOR
void ProcessMLDEvent(void);
#endif

int mTunFd; ///< Used to exchange IPv6 packets.
int mIpFd; ///< Used to manage IPv6 stack on the network interface.
int mNetlinkFd; ///< Used to receive netlink events.
#if NETIF_USE_MLD_MONITOR
int mMLDFd; ///< Used to receive MLD events.
#endif
uint32_t mNetlinkSequence; ///< Netlink message sequence.

unsigned int mNetifIndex;
std::string mNetifName;

std::vector<Ip6AddressInfo> mIp6UnicastAddresses;
std::vector<Ip6Address> mIp6MulticastAddresses;
Ip6SendFunc mIp6SendFunc;
std::vector<Ip6AddressInfo> mIp6UnicastAddresses;
std::vector<Ip6Address> mIp6MulticastAddresses;
Ip6SendFunc mIp6SendFunc;
Ip6MulAddrUpdateSubscriptionFunc mIp6MulAddrUpdateSubscriptionFunc;
};

} // namespace otbr
Expand Down
Loading

0 comments on commit 46cb697

Please sign in to comment.