diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index 2b7a47da3..0fa97dc13 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -129,6 +129,7 @@ add_library(openthread-posix configuration.cpp config_file.cpp daemon.cpp + dhcp6_pd_socket.cpp entropy.cpp firewall.cpp hdlc_interface.cpp diff --git a/src/posix/platform/dhcp6_pd_socket.cpp b/src/posix/platform/dhcp6_pd_socket.cpp new file mode 100644 index 000000000..8a3659b05 --- /dev/null +++ b/src/posix/platform/dhcp6_pd_socket.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2025, 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 "dhcp6_pd_socket.hpp" + +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "infra_if.hpp" +#include "ip6_utils.hpp" +#include "platform-posix.h" +#include "common/code_utils.hpp" + +extern "C" void otPlatInfraIfDhcp6PdClientSetListeningEnabled(otInstance *aInstance, + bool aEnable, + uint32_t aInfraIfIndex) +{ + ot::Posix::InfraNetif::GetDhcp6PdSocket().SetListeningEnabled(aInstance, aEnable, aInfraIfIndex); +} + +extern "C" void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance, + otMessage *aMessage, + otIp6Address *aDestAddress, + uint32_t aInfraIfIndex) +{ + OT_UNUSED_VARIABLE(aInstance); + return ot::Posix::InfraNetif::GetDhcp6PdSocket().Send(aMessage, aDestAddress, aInfraIfIndex); +} + +namespace ot { +namespace Posix { + +using namespace ot::Posix::Ip6Utils; + +const char Dhcp6PdSocket::kLogModuleName[] = "Dhcp6PdSocket"; + +void Dhcp6PdSocket::Init(void) +{ + mEnabled = false; + mInfraIfIndex = 0; + mFd6 = -1; + mPendingTx = false; + + // `All_DHCP_Relay_Agents_and_Servers` "ff02::1:2" + memset(&mMulticastAddress, 0, sizeof(otIp6Address)); + mMulticastAddress.mFields.m8[0] = 0xff; + mMulticastAddress.mFields.m8[1] = 0x02; + mMulticastAddress.mFields.m8[13] = 0x01; + mMulticastAddress.mFields.m8[15] = 0x02; + + memset(&mTxQueue, 0, sizeof(mTxQueue)); +} + +void Dhcp6PdSocket::SetUp(void) { otMessageQueueInit(&mTxQueue); } + +void Dhcp6PdSocket::TearDown(void) +{ + if (mEnabled) + { + ClearTxQueue(); + mEnabled = false; + } +} + +void Dhcp6PdSocket::Deinit(void) { CloseSocket(); } + +void Dhcp6PdSocket::Update(otSysMainloopContext &aContext) +{ + VerifyOrExit(mEnabled); + + FD_SET(mFd6, &aContext.mReadFdSet); + + if (mPendingTx) + { + FD_SET(mFd6, &aContext.mWriteFdSet); + } + + if (aContext.mMaxFd < mFd6) + { + aContext.mMaxFd = mFd6; + } + +exit: + return; +} + +void Dhcp6PdSocket::Process(const otSysMainloopContext &aContext) +{ + VerifyOrExit(mEnabled); + + if (FD_ISSET(mFd6, &aContext.mWriteFdSet)) + { + SendQueuedMessages(); + } + + if (FD_ISSET(mFd6, &aContext.mReadFdSet)) + { + ReceiveMessage(); + } + +exit: + return; +} + +void Dhcp6PdSocket::SetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex) +{ + VerifyOrExit(aEnable != mEnabled); + mInstance = aInstance; + + if (aEnable) + { + Enable(aInfraIfIndex); + } + else + { + Disable(aInfraIfIndex); + } + +exit: + return; +} + +void Dhcp6PdSocket::Enable(uint32_t aInfraIfIndex) +{ + SuccessOrDie(OpenSocket(aInfraIfIndex)); + SuccessOrDie(JoinOrLeaveMulticastGroup(/* aJoin */ true, aInfraIfIndex)); + + mEnabled = true; + mInfraIfIndex = aInfraIfIndex; + + LogInfo("Enabled"); +} + +void Dhcp6PdSocket::Disable(uint32_t aInfraIfIndex) +{ + ClearTxQueue(); + + IgnoreError(JoinOrLeaveMulticastGroup(/* aJoin */ false, aInfraIfIndex)); + CloseSocket(); + + mEnabled = false; + + LogInfo("Disabled"); +} + +void Dhcp6PdSocket::Send(otMessage *aMessage, const otIp6Address *aAddress, uint32_t aInfraIfIndex) +{ + Metadata metadata; + uint16_t length; + + VerifyOrExit(mEnabled); + VerifyOrExit(aInfraIfIndex == mInfraIfIndex); + + length = otMessageGetLength(aMessage); + + if (length > kMaxMessageLength) + { + LogWarn("Msg length %u is longer than max %u", length, kMaxMessageLength); + ExitNow(); + } + + memset(&metadata, 0, sizeof(Metadata)); + + metadata.mAddress = *aAddress; + metadata.mPort = kServerPort; + + SuccessOrExit(otMessageAppend(aMessage, &metadata, sizeof(Metadata))); + + mPendingTx = true; + + otMessageQueueEnqueue(&mTxQueue, aMessage); + aMessage = NULL; + +exit: + if (aMessage != NULL) + { + otMessageFree(aMessage); + } +} + +void Dhcp6PdSocket::ClearTxQueue(void) +{ + otMessage *message; + + while ((message = otMessageQueueGetHead(&mTxQueue)) != NULL) + { + otMessageQueueDequeue(&mTxQueue, message); + otMessageFree(message); + } + + mPendingTx = false; +} + +void Dhcp6PdSocket::SendQueuedMessages(void) +{ + otMessage *message; + + while ((message = otMessageQueueGetHead(&mTxQueue)) != nullptr) + { + uint16_t length; + uint16_t offset; + int bytesSent; + Metadata metadata; + uint8_t buffer[kMaxMessageLength]; + struct sockaddr_in6 addr6; + + length = otMessageGetLength(message); + + offset = length - sizeof(Metadata); + length -= sizeof(Metadata); + + otMessageRead(message, offset, &metadata, sizeof(Metadata)); + otMessageRead(message, 0, buffer, length); + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(metadata.mPort); + CopyIp6AddressTo(metadata.mAddress, &addr6.sin6_addr); + + bytesSent = sendto(mFd6, buffer, length, 0, reinterpret_cast(&addr6), sizeof(addr6)); + VerifyOrExit(bytesSent == length); + + otMessageQueueDequeue(&mTxQueue, message); + otMessageFree(message); + } + + mPendingTx = false; + +exit: + return; +} + +void Dhcp6PdSocket::ReceiveMessage(void) +{ + otMessage *message = nullptr; + uint8_t buffer[kMaxMessageLength]; + uint16_t length = 0; + struct sockaddr_in6 sockaddr6; + socklen_t len; + ssize_t rval; + + len = sizeof(sockaddr6); + memset(&sockaddr6, 0, sizeof(sockaddr6)); + + rval = recvfrom(mFd6, reinterpret_cast(&buffer), sizeof(buffer), 0, + reinterpret_cast(&sockaddr6), &len); + + VerifyOrExit(rval >= 0, LogCrit("recvfrom() for IPv6 socket failed, errno: %s", strerror(errno))); + length = static_cast(rval); + + VerifyOrExit(length > 0); + + message = otIp6NewMessage(mInstance, nullptr); + VerifyOrExit(message != nullptr); + + SuccessOrExit(otMessageAppend(message, buffer, length)); + + otPlatInfraIfDhcp6PdClientHandleReceived(mInstance, message, mInfraIfIndex); + + message = nullptr; + +exit: + if (message != nullptr) + { + otMessageFree(message); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +// Socket helpers + +otError Dhcp6PdSocket::OpenSocket(uint32_t aInfraIfIndex) +{ + otError error = OT_ERROR_FAILED; + struct sockaddr_in6 addr6; + int fd; + int ifindex = static_cast(aInfraIfIndex); + + fd = socket(AF_INET6, SOCK_DGRAM, 0); + VerifyOrExit(fd >= 0, LogCrit("Failed to create socket")); + +#ifdef __linux__ + { + char nameBuffer[IF_NAMESIZE]; + const char *ifname; + + ifname = if_indextoname(aInfraIfIndex, nameBuffer); + VerifyOrExit(ifname != NULL, LogCrit("if_indextoname() failed")); + + error = SetSocketOptionValue(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname), "SO_BINDTODEVICE"); + SuccessOrExit(error); + } +#else + { + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_BOUND_IF, ifindex, "IPV6_BOUND_IF")); + } +#endif + + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255, "IPV6_MULTICAST_HOPS")); + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255, "IPV6_UNICAST_HOPS")); + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1, "IPV6_V6ONLY")); + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex, "IPV6_MULTICAST_IF")); + SuccessOrExit(error = SetSocketOption(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1, "IPV6_MULTICAST_LOOP")); + SuccessOrExit(error = SetReuseAddrPortOptions(fd)); + + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(kClientPort); + + if (bind(fd, reinterpret_cast(&addr6), sizeof(addr6)) < 0) + { + LogCrit("bind() to DHCPv6 Client port for IPv6 socket failed, errno: %s", strerror(errno)); + error = OT_ERROR_FAILED; + ExitNow(); + } + + mFd6 = fd; + + LogInfo("Successfully opened IPv6 socket"); + +exit: + return error; +} + +#ifndef IPV6_ADD_MEMBERSHIP +#ifdef IPV6_JOIN_GROUP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif +#endif + +#ifndef IPV6_DROP_MEMBERSHIP +#ifdef IPV6_LEAVE_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif +#endif + +otError Dhcp6PdSocket::JoinOrLeaveMulticastGroup(bool aJoin, uint32_t aInfraIfIndex) +{ + struct ipv6_mreq mreq6; + + memset(&mreq6, 0, sizeof(mreq6)); + Ip6Utils::CopyIp6AddressTo(mMulticastAddress, &mreq6.ipv6mr_multiaddr); + + mreq6.ipv6mr_interface = static_cast(aInfraIfIndex); + + if (aJoin) + { + // Suggested workaround for netif not dropping + // a previous multicast membership. + setsockopt(mFd6, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)); + } + + return SetSocketOptionValue(mFd6, IPPROTO_IPV6, aJoin ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, + sizeof(mreq6), "IP6_ADD/DROP_MEMBERSHIP"); +} + +void Dhcp6PdSocket::CloseSocket(void) +{ + if (mFd6 >= 0) + { + close(mFd6); + mFd6 = -1; + } +} + +otError Dhcp6PdSocket::SetReuseAddrPortOptions(int aFd) +{ + otError error; + + SuccessOrExit(error = SetSocketOption(aFd, SOL_SOCKET, SO_REUSEADDR, 1, "SO_REUSEADDR")); + SuccessOrExit(error = SetSocketOption(aFd, SOL_SOCKET, SO_REUSEPORT, 1, "SO_REUSEPORT")); + +exit: + return error; +} + +otError Dhcp6PdSocket::SetSocketOptionValue(int aFd, + int aLevel, + int aOption, + const void *aValue, + uint32_t aValueLength, + const char *aOptionName) +{ + otError error = OT_ERROR_NONE; + + if (setsockopt(aFd, aLevel, aOption, aValue, aValueLength) != 0) + { + error = OT_ERROR_FAILED; + LogCrit("Failed to setsockopt(%s) - errno: %s", aOptionName, strerror(errno)); + } + + return error; +} + +} // namespace Posix +} // namespace ot + +#endif // OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE diff --git a/src/posix/platform/dhcp6_pd_socket.hpp b/src/posix/platform/dhcp6_pd_socket.hpp new file mode 100644 index 000000000..4269d7cf4 --- /dev/null +++ b/src/posix/platform/dhcp6_pd_socket.hpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, 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. + */ +#ifndef OT_POSIX_PLATFORM_DHCP6_PD_SOCKET_HPP_ +#define OT_POSIX_PLATFORM_DHCP6_PD_SOCKET_HPP_ + +#include "openthread-posix-config.h" + +#ifdef OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE +#error "OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE MUST NOT be defined directly. It is derived from other configs" +#endif + +#define OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE \ + (OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && \ + OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE) + +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + +#include + +#include "logger.hpp" +#include "mainloop.hpp" + +#include "core/common/non_copyable.hpp" + +namespace ot { +namespace Posix { + +/** + * Implements platform infra-if DHCPv6 Prefix Delegation (PD) socket APIs. + * + * This is sub-component of `ot::Posix::InfraNetif` class. + */ +class Dhcp6PdSocket : public Logger, private NonCopyable +{ +public: + static const char kLogModuleName[]; ///< Module name used for logging. + + /** + * Initializes the `Dhcp6PdSocket`. + * + * Called before OpenThread instance is created. + */ + void Init(void); + + /** + * Sets up the `Dhcp6PdSocket`. + * + * Called after OpenThread instance is created. + */ + void SetUp(void); + + /** + * Tears down the `Dhcp6PdSocket`. + * + * Called before OpenThread instance is destructed. + */ + void TearDown(void); + + /** + * Deinitializes the `Dhcp6PdSocket`. + * + * Called after OpenThread instance is destructed. + */ + void Deinit(void); + + /** + * Updates the fd_set and timeout for mainloop. + * + * @param[in,out] aContext A reference to the mainloop context. + */ + void Update(otSysMainloopContext &aContext); + + /** + * Performs `Dhcp6PdSocket` processing. + * + * @param[in] aContext A reference to the mainloop context. + */ + void Process(const otSysMainloopContext &aContext); + + // otPlatInfraIfDhcp6PdClient APIs + void SetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex); + void Send(otMessage *aMessage, const otIp6Address *aDstAddress, uint32_t aInfraIfIndex); + +private: + static constexpr uint16_t kMaxMessageLength = 2000; + static constexpr uint16_t kClientPort = 546; + static constexpr uint16_t kServerPort = 547; + + struct Metadata + { + otIp6Address mAddress; + uint16_t mPort; + }; + + bool mEnabled; + bool mPendingTx; + uint32_t mInfraIfIndex; + int mFd6; + otMessageQueue mTxQueue; + otIp6Address mMulticastAddress; + otInstance *mInstance; + + void Enable(uint32_t aInfraIfIndex); + void Disable(uint32_t aInfraIfIndex); + void ClearTxQueue(void); + void SendQueuedMessages(void); + void ReceiveMessage(void); + + otError OpenSocket(uint32_t aInfraIfIndex); + otError JoinOrLeaveMulticastGroup(bool aJoin, uint32_t aInfraIfIndex); + void CloseSocket(void); + + static otError SetReuseAddrPortOptions(int aFd); + + template + static otError SetSocketOption(int aFd, int aLevel, int aOption, const ValueType &aValue, const char *aOptionName) + { + return SetSocketOptionValue(aFd, aLevel, aOption, &aValue, sizeof(ValueType), aOptionName); + } + + static otError SetSocketOptionValue(int aFd, + int aLevel, + int aOption, + const void *aValue, + uint32_t aValueLength, + const char *aOptionName); +}; + +} // namespace Posix +} // namespace ot + +#endif // OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + +#endif // OT_POSIX_PLATFORM_DHCP6_PD_SOCKET_HPP_ diff --git a/src/posix/platform/infra_if.cpp b/src/posix/platform/infra_if.cpp index c098ddf12..80b784fd8 100644 --- a/src/posix/platform/infra_if.cpp +++ b/src/posix/platform/infra_if.cpp @@ -414,6 +414,10 @@ void InfraNetif::Init(void) #ifdef __linux__ mNetLinkSocket = CreateNetLinkSocket(); #endif + +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.Init(); +#endif } void InfraNetif::SetInfraNetif(const char *aIfName, int aIcmp6Socket) @@ -473,6 +477,10 @@ void InfraNetif::SetUp(void) mMulticastRoutingManager.SetUp(); #endif +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.SetUp(); +#endif + Mainloop::Manager::Get().Add(*this); ExitNow(); // To silence unused `exit` label warning. @@ -487,6 +495,10 @@ void InfraNetif::TearDown(void) IgnoreError(otBorderRoutingSetEnabled(gInstance, false)); #endif +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.TearDown(); +#endif + #if OPENTHREAD_POSIX_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE mMulticastRoutingManager.TearDown(); #endif @@ -496,6 +508,10 @@ void InfraNetif::TearDown(void) void InfraNetif::Deinit(void) { +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.Deinit(); +#endif + #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE if (mInfraIfIcmp6Socket != -1) { @@ -518,6 +534,10 @@ void InfraNetif::Deinit(void) void InfraNetif::Update(Mainloop::Context &aContext) { +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.Update(aContext); +#endif + #ifdef __linux__ VerifyOrExit(mNetLinkSocket != -1); #endif @@ -682,6 +702,10 @@ void InfraNetif::SetInfraNetifIcmp6SocketForBorderRouting(int aIcmp6Socket) void InfraNetif::Process(const Mainloop::Context &aContext) { +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + mDhcp6PdSocket.Process(aContext); +#endif + #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE VerifyOrExit(mInfraIfIcmp6Socket != -1); #endif diff --git a/src/posix/platform/infra_if.hpp b/src/posix/platform/infra_if.hpp index 5abba0412..e0c58ad5b 100644 --- a/src/posix/platform/infra_if.hpp +++ b/src/posix/platform/infra_if.hpp @@ -42,6 +42,7 @@ #include "core/common/non_copyable.hpp" +#include "dhcp6_pd_socket.hpp" #include "logger.hpp" #include "mainloop.hpp" #include "multicast_routing.hpp" @@ -182,6 +183,15 @@ public: */ static InfraNetif &Get(void); +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + /** + * Gets the singleton `Dhcp6PdSocket` associated with `InfraNetif`. + * + * @returns The singleton `Dhcp6PdSocket`. + */ + static Dhcp6PdSocket &GetDhcp6PdSocket(void) { return Get().mDhcp6PdSocket; } +#endif + /** * Creates a socket for sending/receiving ICMPv6 messages. * @@ -211,6 +221,10 @@ private: MulticastRoutingManager mMulticastRoutingManager; #endif +#if OT_POSIX_CONFIG_DHCP6_PD_SOCKET_ENABLE + Dhcp6PdSocket mDhcp6PdSocket; +#endif + bool HasLinkLocalAddress(void) const; #ifdef __linux__ diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index 4cf0ed724..6309b4892 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -1109,8 +1109,9 @@ exit: } } -#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || \ - (OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE) +#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || \ + (OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && \ + !OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE) static constexpr uint8_t kIpVersion4 = 4; static constexpr uint8_t kIpVersion6 = 6; @@ -1126,7 +1127,8 @@ static uint8_t getIpVersion(const uint8_t *data) } #endif -#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && \ + !OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE /** * Returns nullptr if data does not point to a valid ICMPv6 RA message. @@ -1171,7 +1173,7 @@ static otError tryProcessIcmp6RaMessage(otInstance *aInstance, const uint8_t *da exit: return error; } -#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && ... #ifdef __linux__ /** @@ -1237,7 +1239,8 @@ static void processTransmit(otInstance *aInstance) } #endif -#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE && \ + !OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE if (tryProcessIcmp6RaMessage(aInstance, reinterpret_cast(&packet[offset]), rval) == OT_ERROR_NONE) { ExitNow(); diff --git a/tests/toranj/openthread-core-toranj-config-simulation.h b/tests/toranj/openthread-core-toranj-config-simulation.h index fc6bca09a..51358c3b3 100644 --- a/tests/toranj/openthread-core-toranj-config-simulation.h +++ b/tests/toranj/openthread-core-toranj-config-simulation.h @@ -49,8 +49,6 @@ #define OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE 1 -#define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE 1 - #define OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE 1 #define OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION 1 diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 4db884191..8bc539ed5 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -56,6 +56,8 @@ #define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE 1 + #define OPENTHREAD_CONFIG_BORDER_ROUTING_TESTING_API_ENABLE 1 #define OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE 1