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 14, 2024
1 parent b9210e7 commit c69a206
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/ncp/ncp_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,14 @@ otbrError NcpSpinel::HandleResponseForPropSet(spinel_tid_t aTid,
return error;
}

otbrError NcpSpinel::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded)
{
OTBR_UNUSED_VARIABLE(aAddress);
OTBR_UNUSED_VARIABLE(aIsAdded);

return OTBR_ERROR_NOT_IMPLEMENTED;
}

spinel_tid_t NcpSpinel::GetNextTid(void)
{
spinel_tid_t tid = mCmdNextTid;
Expand Down
2 changes: 2 additions & 0 deletions src/ncp/ncp_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ class NcpSpinel : public Netif::Dependencies
const uint8_t *aData,
uint16_t aLength);

otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) override;

spinel_tid_t GetNextTid(void);
void FreeTidTableItem(spinel_tid_t aTid);

Expand Down
184 changes: 184 additions & 0 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 @@ -54,13 +56,51 @@ otbrError Netif::Dependencies::Ip6Send(const uint8_t *aData, uint16_t aLength)
{
OTBR_UNUSED_VARIABLE(aData);
OTBR_UNUSED_VARIABLE(aLength);

return OTBR_ERROR_NONE;
}

otbrError Netif::Dependencies::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdd)
{
OTBR_UNUSED_VARIABLE(aAddress);
OTBR_UNUSED_VARIABLE(aIsAdd);

return OTBR_ERROR_NONE;
}

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,
kIcmpv6Mldv2ModeIsIncludeType = 1,
kIcmpv6Mldv2ModeIsExcludeType = 2,
kIcmpv6Mldv2RecordChangeToIncludeType = 3,
kIcmpv6Mldv2RecordChangeToExcludeType = 4,
};

Netif::Netif(Dependencies &aDependencies)
: mTunFd(-1)
, mIpFd(-1)
, mNetlinkFd(-1)
, mMldFd(-1)
, mNetlinkSequence(0)
, mNetifIndex(0)
, mDeps(aDependencies)
Expand All @@ -80,6 +120,8 @@ otbrError Netif::Init(const std::string &aInterfaceName)
mNetifIndex = if_nametoindex(mNetifName.c_str());
VerifyOrExit(mNetifIndex > 0, error = OTBR_ERROR_INVALID_STATE);

SuccessOrExit(error = InitMldListener());

PlatformSpecificInit();

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

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

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

if (FD_ISSET(mMldFd, &aContext->mReadFdSet))
{
ProcessMldEvent();
}
}

void Netif::UpdateFdSet(MainloopContext *aContext)
{
assert(aContext != nullptr);
assert(mTunFd >= 0);
assert(mIpFd >= 0);
assert(mMldFd >= 0);

aContext->AddFdToSet(mTunFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
aContext->AddFdToSet(mMldFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
}

void Netif::UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aAddrInfos)
Expand Down Expand Up @@ -289,9 +344,138 @@ void Netif::Clear(void)
mNetlinkFd = -1;
}

if (mMldFd != -1)
{
close(mMldFd);
mMldFd = -1;
}

mNetifIndex = 0;
mIp6UnicastAddresses.clear();
mIp6MulticastAddresses.clear();
}

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 Ip6Address(aAddr) == Ip6Address(kMldv2MulticastAddress) ||
Ip6Address(aAddr) == Ip6Address(kAllRouterLocalMulticastAddress);
}

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 = OTBR_ERROR_DROPPED;
otIp6Address address;

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

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

switch (record->mRecordType)
{
case kIcmpv6Mldv2ModeIsIncludeType:
case kIcmpv6Mldv2ModeIsExcludeType:
error = OTBR_ERROR_NONE;
break;
case kIcmpv6Mldv2RecordChangeToIncludeType:
error = (record->mNumSources == 0) ? mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ false)
: OTBR_ERROR_NONE;
break;
case kIcmpv6Mldv2RecordChangeToExcludeType:
error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ true);
break;
}

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);
}
}

} // namespace otbr
4 changes: 4 additions & 0 deletions src/ncp/posix/netif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class Netif
virtual ~Dependencies(void) = default;

virtual otbrError Ip6Send(const uint8_t *aData, uint16_t aLength);
virtual otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded);
};

Netif(Dependencies &aDependencies);
Expand All @@ -78,16 +79,19 @@ class Netif

otbrError CreateTunDevice(const std::string &aInterfaceName);
otbrError InitNetlink(void);
otbrError InitMldListener(void);

void PlatformSpecificInit(void);
void SetAddrGenModeToNone(void);
void ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded);
otbrError ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded);
void ProcessIp6Send(void);
void ProcessMldEvent(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.
int mMldFd; ///< Used to receive MLD events.
uint32_t mNetlinkSequence; ///< Netlink message sequence.

unsigned int mNetifIndex;
Expand Down
Loading

0 comments on commit c69a206

Please sign in to comment.