diff --git a/include/openthread/instance.h b/include/openthread/instance.h index e0fd29426..73546c8cc 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (36) +#define OPENTHREAD_API_VERSION (37) /** * @addtogroup api-instance diff --git a/include/openthread/platform/udp.h b/include/openthread/platform/udp.h index ed9f8f6a9..042e38a0d 100644 --- a/include/openthread/platform/udp.h +++ b/include/openthread/platform/udp.h @@ -121,6 +121,40 @@ otError otPlatUdpConnect(otUdpSocket *aUdpSocket); */ otError otPlatUdpSend(otUdpSocket *aUdpSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo); +/** + * This function configures the UDP socket to join a UDP multicast group. + * + * Note: only available when `OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE` is used. + * + * @param[in] aUdpSocket A pointer to the UDP socket. + * @param[in] aNetifIdentifier The network interface identifier. + * @param[in] aAddress The UDP multicast group address. + * + * @retval OT_ERROR_NONE Successfully joined the multicast group. + * @retval OT_ERROR_FAILED Failed to join the multicast group. + * + */ +otError otPlatUdpJoinMulticastGroup(otUdpSocket * aUdpSocket, + otNetifIdentifier aNetifIdentifier, + const otIp6Address *aAddress); + +/** + * This function configures the UDP socket to leave a UDP multicast group. + * + * Note: only available when `OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE` is used. + * + * @param[in] aUdpSocket A pointer to the UDP socket. + * @param[in] aNetifIdentifier The network interface identifier. + * @param[in] aAddress The UDP multicast group address. + * + * @retval OT_ERROR_NONE Successfully left the multicast group. + * @retval OT_ERROR_FAILED Failed to leave the multicast group. + * + */ +otError otPlatUdpLeaveMulticastGroup(otUdpSocket * aUdpSocket, + otNetifIdentifier aNetifIdentifier, + const otIp6Address *aAddress); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/core/backbone_router/backbone_tmf.cpp b/src/core/backbone_router/backbone_tmf.cpp index a43ed5a5f..75ff364a5 100644 --- a/src/core/backbone_router/backbone_tmf.cpp +++ b/src/core/backbone_router/backbone_tmf.cpp @@ -42,7 +42,13 @@ namespace BackboneRouter { otError BackboneTmfAgent::Start(void) { - return Coap::Start(kBackboneUdpPort, OT_NETIF_BACKBONE); + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = Coap::Start(kBackboneUdpPort, OT_NETIF_BACKBONE)); + SubscribeMulticast(Get().GetAllNetworkBackboneRoutersAddress()); + +exit: + return error; } otError BackboneTmfAgent::Filter(const ot::Coap::Message &aMessage, @@ -71,6 +77,38 @@ bool BackboneTmfAgent::IsBackboneTmfMessage(const Ip6::MessageInfo &aMessageInfo dst == Get().GetAllDomainBackboneRoutersAddress())); } +void BackboneTmfAgent::SubscribeMulticast(const Ip6::Address &aAddress) +{ + otError error; + + error = mSocket.JoinNetifMulticastGroup(OT_NETIF_BACKBONE, aAddress); + + if (error != OT_ERROR_NONE) + { + otLogDebgBbr("Backbone TMF subscribes %s: %s", aAddress.ToString().AsCString(), otThreadErrorToString(error)); + } + else + { + otLogCritBbr("Backbone TMF subscribes %s: %s", aAddress.ToString().AsCString(), otThreadErrorToString(error)); + } +} + +void BackboneTmfAgent::UnsubscribeMulticast(const Ip6::Address &aAddress) +{ + otError error; + + error = mSocket.LeaveNetifMulticastGroup(OT_NETIF_BACKBONE, aAddress); + + if (error == OT_ERROR_NONE) + { + otLogDebgBbr("Backbone TMF unsubscribes %s: %s", aAddress.ToString().AsCString(), otThreadErrorToString(error)); + } + else + { + otLogCritBbr("Backbone TMF unsubscribes %s: %s", aAddress.ToString().AsCString(), otThreadErrorToString(error)); + } +} + } // namespace BackboneRouter } // namespace ot diff --git a/src/core/backbone_router/backbone_tmf.hpp b/src/core/backbone_router/backbone_tmf.hpp index af8ad0248..5137045fb 100644 --- a/src/core/backbone_router/backbone_tmf.hpp +++ b/src/core/backbone_router/backbone_tmf.hpp @@ -81,6 +81,22 @@ public: */ bool IsBackboneTmfMessage(const Ip6::MessageInfo &aMessageInfo) const; + /** + * This method subscribes the Backbone TMF socket to a given Ip6 multicast group on the Backbone network. + * + * @param[in] aAddress The Ip6 multicast group address. + * + */ + void SubscribeMulticast(const Ip6::Address &aAddress); + + /** + * This method unsubscribes the Backbone TMF socket from a given Ip6 multicast group on the Backbone network. + * + * @param[in] aAddress The Ip6 multicast group address. + * + */ + void UnsubscribeMulticast(const Ip6::Address &aAddress); + private: static otError Filter(const ot::Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext); }; diff --git a/src/core/backbone_router/bbr_local.cpp b/src/core/backbone_router/bbr_local.cpp index 6fe808a17..f808e9552 100644 --- a/src/core/backbone_router/bbr_local.cpp +++ b/src/core/backbone_router/bbr_local.cpp @@ -65,18 +65,16 @@ Local::Local(Instance &aInstance) // All Network Backbone Routers Multicast Address. mAllNetworkBackboneRouters.Clear(); - mAllNetworkBackboneRouters.GetAddress().mFields.m8[0] = 0xff; // Multicast - mAllNetworkBackboneRouters.GetAddress().mFields.m8[1] = 0x32; // Flags = 3, Scope = 2 - mAllNetworkBackboneRouters.GetAddress().mFields.m8[2] = 0; // Reserved - mAllNetworkBackboneRouters.GetAddress().mFields.m8[15] = 3; // Group ID = 3 + mAllNetworkBackboneRouters.mFields.m8[0] = 0xff; // Multicast + mAllNetworkBackboneRouters.mFields.m8[1] = 0x32; // Flags = 3, Scope = 2 + mAllNetworkBackboneRouters.mFields.m8[15] = 3; // Group ID = 3 // All Domain Backbone Routers Multicast Address. mAllDomainBackboneRouters.Clear(); - mAllDomainBackboneRouters.GetAddress().mFields.m8[0] = 0xff; // Multicast - mAllDomainBackboneRouters.GetAddress().mFields.m8[1] = 0x32; // Flags = 3, Scope = 2 - mAllDomainBackboneRouters.GetAddress().mFields.m8[2] = 0; // Reserved - mAllDomainBackboneRouters.GetAddress().mFields.m8[15] = 3; // Group ID = 3 + mAllDomainBackboneRouters.mFields.m8[0] = 0xff; // Multicast + mAllDomainBackboneRouters.mFields.m8[1] = 0x32; // Flags = 3, Scope = 2 + mAllDomainBackboneRouters.mFields.m8[15] = 3; // Group ID = 3 } void Local::SetEnabled(bool aEnable) @@ -227,13 +225,8 @@ void Local::SetState(BackboneRouterState aState) if (mState == OT_BACKBONE_ROUTER_STATE_DISABLED) { - // Subscribe All Network Backbone Routers Multicast Address for both Secondary and Primary state. - mAllNetworkBackboneRouters.GetAddress().SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); - Get().SubscribeMulticast(mAllNetworkBackboneRouters); - } - else if (aState == OT_BACKBONE_ROUTER_STATE_DISABLED) - { - Get().UnsubscribeMulticast(mAllNetworkBackboneRouters); + // Update All Network Backbone Routers Multicast Address for both Secondary and Primary state. + mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); } if (mState == OT_BACKBONE_ROUTER_STATE_PRIMARY) @@ -351,9 +344,9 @@ void Local::ApplyMeshLocalPrefix(void) { VerifyOrExit(IsEnabled()); - Get().UnsubscribeMulticast(mAllNetworkBackboneRouters); - mAllNetworkBackboneRouters.GetAddress().SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); - Get().SubscribeMulticast(mAllNetworkBackboneRouters); + Get().UnsubscribeMulticast(mAllNetworkBackboneRouters); + mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get().GetMeshLocalPrefix()); + Get().SubscribeMulticast(mAllNetworkBackboneRouters); if (IsPrimary()) { @@ -370,19 +363,18 @@ void Local::UpdateAllDomainBackboneRouters(Leader::DomainPrefixState aState) { if (!IsEnabled()) { - Get().UnsubscribeMulticast(mAllDomainBackboneRouters); ExitNow(); } if (aState == Leader::kDomainPrefixRemoved || aState == Leader::kDomainPrefixRefreshed) { - Get().UnsubscribeMulticast(mAllDomainBackboneRouters); + Get().UnsubscribeMulticast(mAllDomainBackboneRouters); } if (aState == Leader::kDomainPrefixAdded || aState == Leader::kDomainPrefixRefreshed) { - mAllDomainBackboneRouters.GetAddress().SetMulticastNetworkPrefix(*Get().GetDomainPrefix()); - Get().SubscribeMulticast(mAllDomainBackboneRouters); + mAllDomainBackboneRouters.SetMulticastNetworkPrefix(*Get().GetDomainPrefix()); + Get().SubscribeMulticast(mAllDomainBackboneRouters); } exit: diff --git a/src/core/backbone_router/bbr_local.hpp b/src/core/backbone_router/bbr_local.hpp index c141fa6c7..7d7c2090e 100644 --- a/src/core/backbone_router/bbr_local.hpp +++ b/src/core/backbone_router/bbr_local.hpp @@ -205,10 +205,7 @@ public: * @returns A reference to the All Network Backbone Routers Multicast Address. * */ - const Ip6::Address &GetAllNetworkBackboneRoutersAddress(void) const - { - return mAllNetworkBackboneRouters.GetAddress(); - } + const Ip6::Address &GetAllNetworkBackboneRoutersAddress(void) const { return mAllNetworkBackboneRouters; } /** * This method returns a reference to the All Domain Backbone Routers Multicast Address. @@ -216,10 +213,7 @@ public: * @returns A reference to the All Domain Backbone Routers Multicast Address. * */ - const Ip6::Address &GetAllDomainBackboneRoutersAddress(void) const - { - return mAllDomainBackboneRouters.GetAddress(); - } + const Ip6::Address &GetAllDomainBackboneRoutersAddress(void) const { return mAllDomainBackboneRouters; } /** * This method applies the Mesh Local Prefix. @@ -261,9 +255,9 @@ private: NetworkData::OnMeshPrefixConfig mDomainPrefixConfig; - Ip6::NetifUnicastAddress mBackboneRouterPrimaryAloc; - Ip6::NetifMulticastAddress mAllNetworkBackboneRouters; - Ip6::NetifMulticastAddress mAllDomainBackboneRouters; + Ip6::NetifUnicastAddress mBackboneRouterPrimaryAloc; + Ip6::Address mAllNetworkBackboneRouters; + Ip6::Address mAllDomainBackboneRouters; }; } // namespace BackboneRouter diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index e5f07c433..1d8da4b5d 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -324,7 +324,6 @@ void Manager::SendBackboneMulticastListenerRegistration(const Ip6::Address *aAdd messageInfo.SetPeerAddr(Get().GetAllNetworkBackboneRoutersAddress()); messageInfo.SetPeerPort(BackboneRouter::kBackboneUdpPort); // TODO: Provide API for configuring Backbone COAP port. - messageInfo.SetSockAddr(Get().GetMeshLocal16()); messageInfo.SetHopLimit(Mle::kDefaultBackboneHoplimit); messageInfo.SetIsHostInterface(true); diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index 1ea33864f..5b8c7f324 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -225,6 +225,10 @@ otError CoapBase::SendMessage(Message & aMessage, metadata.mRetransmissionTimeout = aTxParameters.CalculateInitialRetransmissionTimeout(); metadata.mAcknowledged = false; metadata.mConfirmable = aMessage.IsConfirmable(); +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + metadata.mHopLimit = aMessageInfo.GetHopLimit(); + metadata.mIsHostInterface = aMessageInfo.IsHostInterface(); +#endif #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE metadata.mObserve = observe; #endif @@ -377,6 +381,10 @@ void CoapBase::HandleRetransmissionTimer(void) messageInfo.SetPeerAddr(metadata.mDestinationAddress); messageInfo.SetPeerPort(metadata.mDestinationPort); messageInfo.SetSockAddr(metadata.mSourceAddress); +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + messageInfo.SetHopLimit(metadata.mHopLimit); + messageInfo.SetIsHostInterface(metadata.mIsHostInterface); +#endif SendCopy(*message, messageInfo); } diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index 1177995e9..35d188d44 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -540,8 +540,14 @@ private: TimeMilli mNextTimerShot; // Time when the timer should shoot for this message. uint32_t mRetransmissionTimeout; // Delay that is applied to next retransmission. uint8_t mRetransmissionsRemaining; // Number of retransmissions remaining. - bool mAcknowledged : 1; // Information that request was acknowledged. - bool mConfirmable : 1; // Information that message is confirmable. +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + uint8_t mHopLimit; // The hop limit. +#endif + bool mAcknowledged : 1; // Information that request was acknowledged. + bool mConfirmable : 1; // Information that message is confirmable. +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + bool mIsHostInterface : 1; // TRUE if packets sent/received via host interface, FALSE otherwise. +#endif #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE bool mObserve : 1; // Information that this request involves Observations. #endif diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index a44f3eaa7..063a059aa 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -137,6 +137,42 @@ otError Udp::Socket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo) return Get().SendTo(*this, aMessage, aMessageInfo); } +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +otError Udp::Socket::JoinNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress) +{ + OT_UNUSED_VARIABLE(aNetifIdentifier); + OT_UNUSED_VARIABLE(aAddress); + + otError error = OT_ERROR_NOT_IMPLEMENTED; + + VerifyOrExit(aAddress.IsMulticast(), error = OT_ERROR_INVALID_ARGS); + +#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE + error = otPlatUdpJoinMulticastGroup(this, aNetifIdentifier, &aAddress); +#endif + +exit: + return error; +} + +otError Udp::Socket::LeaveNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress) +{ + OT_UNUSED_VARIABLE(aNetifIdentifier); + OT_UNUSED_VARIABLE(aAddress); + + otError error = OT_ERROR_NOT_IMPLEMENTED; + + VerifyOrExit(aAddress.IsMulticast(), error = OT_ERROR_INVALID_ARGS); + +#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE + error = otPlatUdpLeaveMulticastGroup(this, aNetifIdentifier, &aAddress); +#endif + +exit: + return error; +} +#endif + Udp::Udp(Instance &aInstance) : InstanceLocator(aInstance) , mEphemeralPort(kDynamicPortMin) diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp index e102ee697..9c1aecbf5 100644 --- a/src/core/net/udp6.hpp +++ b/src/core/net/udp6.hpp @@ -261,6 +261,32 @@ public: * */ otError SendTo(Message &aMessage, const MessageInfo &aMessageInfo); + +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + /** + * This method configures the UDP socket to join a mutlicast group on a Host network interface. + * + * @param[in] aNetifIdentifier The network interface identifier. + * @param[in] aAddress The multicast group address. + * + * @retval OT_ERROR_NONE Successfully joined the multicast group. + * @retval OT_ERROR_FAILED Failed to join the multicast group. + * + */ + otError JoinNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress); + + /** + * This method configures the UDP socket to leave a multicast group on a Host network interface. + * + * @param[in] aNetifIdentifier The network interface identifier. + * @param[in] aAddress The multicast group address. + * + * @retval OT_ERROR_NONE Successfully left the multicast group. + * @retval OT_ERROR_FAILED Failed to leave the multicast group. + * + */ + otError LeaveNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress); +#endif }; /** diff --git a/src/posix/platform/udp.cpp b/src/posix/platform/udp.cpp index e7cc7050c..8993ca1b9 100644 --- a/src/posix/platform/udp.cpp +++ b/src/posix/platform/udp.cpp @@ -289,6 +289,8 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId { otError error = OT_ERROR_NONE; int fd = FdFromHandle(aUdpSocket->mHandle); + int one = 1; + int zero = 0; switch (aNetifIdentifier) { @@ -298,7 +300,8 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, nullptr, 0) == 0, error = OT_ERROR_FAILED); #else // __NetBSD__ || __FreeBSD__ || __APPLE__ unsigned int netifIndex = 0; - VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &netifIndex, sizeof(netifIndex)), error = OT_ERROR_FAILED); + VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &netifIndex, sizeof(netifIndex)) == 0, + error = OT_ERROR_FAILED); #endif // __linux__ break; } @@ -308,7 +311,7 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &gNetifName, strlen(gNetifName)) == 0, error = OT_ERROR_FAILED); #else // __NetBSD__ || __FreeBSD__ || __APPLE__ - VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &gNetifIndex, sizeof(gNetifIndex)), + VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &gNetifIndex, sizeof(gNetifIndex)) == 0, error = OT_ERROR_FAILED); #endif // __linux__ break; @@ -320,16 +323,21 @@ otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifId 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)), + VerifyOrExit(setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &gBackboneNetifIndex, sizeof(gBackboneNetifIndex)) == 0, error = OT_ERROR_FAILED); #endif // __linux__ #else ExitNow(error = OT_ERROR_NOT_IMPLEMENTED); #endif + VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&one, sizeof(one)) == 0, + error = OT_ERROR_FAILED); + break; } } + VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) == 0, error = OT_ERROR_FAILED); + exit: return error; } @@ -427,6 +435,86 @@ exit: return error; } +otError otPlatUdpJoinMulticastGroup(otUdpSocket * aUdpSocket, + otNetifIdentifier aNetifIdentifier, + const otIp6Address *aAddress) +{ + otError error = OT_ERROR_NONE; + struct ipv6_mreq mreq; + int fd; + + VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS); + fd = FdFromHandle(aUdpSocket->mHandle); + + memcpy(&mreq.ipv6mr_multiaddr, aAddress->mFields.m8, sizeof(mreq.ipv6mr_multiaddr)); + + switch (aNetifIdentifier) + { + case OT_NETIF_UNSPECIFIED: + break; + case OT_NETIF_THREAD: + mreq.ipv6mr_interface = gNetifIndex; + break; + case OT_NETIF_BACKBONE: +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + mreq.ipv6mr_interface = gBackboneNetifIndex; +#else + ExitNow(error = OT_ERROR_NOT_IMPLEMENTED); +#endif + break; + } + + VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == 0 || errno == EADDRINUSE, + error = OT_ERROR_FAILED); + +exit: + if (error != OT_ERROR_NONE) + { + otLogCritPlat("IPV6_JOIN_GROUP failed: %s", strerror(errno)); + } + return error; +} + +otError otPlatUdpLeaveMulticastGroup(otUdpSocket * aUdpSocket, + otNetifIdentifier aNetifIdentifier, + const otIp6Address *aAddress) +{ + otError error = OT_ERROR_NONE; + struct ipv6_mreq mreq; + int fd; + + VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS); + fd = FdFromHandle(aUdpSocket->mHandle); + + memcpy(&mreq.ipv6mr_multiaddr, aAddress->mFields.m8, sizeof(mreq.ipv6mr_multiaddr)); + + switch (aNetifIdentifier) + { + case OT_NETIF_UNSPECIFIED: + break; + case OT_NETIF_THREAD: + mreq.ipv6mr_interface = gNetifIndex; + break; + case OT_NETIF_BACKBONE: +#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + mreq.ipv6mr_interface = gBackboneNetifIndex; +#else + ExitNow(error = OT_ERROR_NOT_IMPLEMENTED); +#endif + break; + } + + VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) == 0 || errno == EADDRINUSE, + error = OT_ERROR_FAILED); + +exit: + if (error != OT_ERROR_NONE) + { + otLogCritPlat("IPV6_LEAVE_GROUP failed: %s", strerror(errno)); + } + return error; +} + void platformUdpUpdateFdSet(otInstance *aInstance, fd_set *aReadFdSet, int *aMaxFd) { VerifyOrExit(gNetifIndex != 0); diff --git a/tests/scripts/thread-cert/backbone/test_bmlr.py b/tests/scripts/thread-cert/backbone/test_bmlr.py index eb50e2504..5e979844d 100644 --- a/tests/scripts/thread-cert/backbone/test_bmlr.py +++ b/tests/scripts/thread-cert/backbone/test_bmlr.py @@ -147,6 +147,7 @@ class BBR_5_11_01(thread_cert.TestCase): pkts.filter_eth_src(PBBR_ETH).filter_coap_request('/b/bmr').must_next().must_verify(f""" thread_meshcop.tlv.ipv6_addr == ['{MA1}'] and thread_bl.tlv.timeout == {MLR_TIMEOUT} + and ipv6.src.is_link_local """) # Router registers MA2 with default timeout @@ -158,6 +159,7 @@ class BBR_5_11_01(thread_cert.TestCase): pkts.filter_eth_src(PBBR_ETH).filter_coap_request('/b/bmr').must_next().must_verify(f""" thread_meshcop.tlv.ipv6_addr == ['{MA2}'] and thread_bl.tlv.timeout == {MLR_TIMEOUT} + and ipv6.src.is_link_local """) # Commissioner registers MA3 with deafult timeout @@ -169,6 +171,7 @@ class BBR_5_11_01(thread_cert.TestCase): pkts.filter_eth_src(PBBR_ETH).filter_coap_request('/b/bmr').must_next().must_verify(f""" thread_meshcop.tlv.ipv6_addr == ['{MA3}'] and thread_bl.tlv.timeout == {MLR_TIMEOUT} + and ipv6.src.is_link_local """) # Commissioner registers MA4 with custom timeout @@ -180,6 +183,7 @@ class BBR_5_11_01(thread_cert.TestCase): pkts.filter_eth_src(PBBR_ETH).filter_coap_request('/b/bmr').must_next().must_verify(f""" thread_meshcop.tlv.ipv6_addr == ['{MA4}'] and thread_bl.tlv.timeout == {CUSTOM_MLR_TIMEOUT} + and ipv6.src.is_link_local """) # Commissioner unregisters MA5 @@ -190,6 +194,7 @@ class BBR_5_11_01(thread_cert.TestCase): # Verify PBBR not sends `/b/bmr` on the Backbone link for MA5. pkts.filter_eth_src(PBBR_ETH).filter_coap_request('/b/bmr').filter(f""" thread_meshcop.tlv.ipv6_addr == ['{MA5}'] + and ipv6.src.is_link_local """).must_not_next() diff --git a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py index c351a53cc..c538ec52e 100755 --- a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py +++ b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py @@ -108,13 +108,10 @@ class TestBackboneRouterService(thread_cert.TestCase): WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) - assert not self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) WAIT_TIME = WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) # 2) Reset BBR_1 and bring it back soon. # Verify that it restores Primary State with sequence number @@ -175,9 +172,6 @@ class TestBackboneRouterService(thread_cert.TestCase): self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Disabled') - assert not self.nodes[BBR_2].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) - assert not self.nodes[BBR_2].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) - # Enable Backbone function, it will stay at Secondary state as # there is Primary Backbone Router already. # Here removes the Domain Prefix before enabling backbone function @@ -242,9 +236,6 @@ class TestBackboneRouterService(thread_cert.TestCase): self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) - # 6a) Check the uniqueness of DUA by comparing the one in above 4a). bbr2_dua2 = self.nodes[BBR_2].get_addr(config.DOMAIN_PREFIX) assert bbr2_dua == bbr2_dua2, 'Error: Unexpected different DUA ({} v.s. {})'.format(bbr2_dua, bbr2_dua2) diff --git a/tests/scripts/thread-cert/v1_2_test_domain_unicast_address.py b/tests/scripts/thread-cert/v1_2_test_domain_unicast_address.py index 9b045fd2d..54b9a5bfd 100755 --- a/tests/scripts/thread-cert/v1_2_test_domain_unicast_address.py +++ b/tests/scripts/thread-cert/v1_2_test_domain_unicast_address.py @@ -166,13 +166,10 @@ class TestDomainUnicastAddress(thread_cert.TestCase): WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) - assert not self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX, 'prosD') WAIT_TIME = WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) self.simulator.set_lowpan_context(context_id, config.DOMAIN_PREFIX) domain_prefix_cid = context_id diff --git a/tests/scripts/thread-cert/v1_2_test_domain_unicast_address_registration.py b/tests/scripts/thread-cert/v1_2_test_domain_unicast_address_registration.py index 413df0295..17183d46d 100755 --- a/tests/scripts/thread-cert/v1_2_test_domain_unicast_address_registration.py +++ b/tests/scripts/thread-cert/v1_2_test_domain_unicast_address_registration.py @@ -190,13 +190,10 @@ class TestDomainUnicastAddressRegistration(thread_cert.TestCase): WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) - assert not self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX, 'prosD') WAIT_TIME = WAIT_REDUNDANCE self.simulator.go(WAIT_TIME) - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) self.simulator.set_lowpan_context(context_id, config.DOMAIN_PREFIX) domain_prefix_cid = context_id diff --git a/tests/scripts/thread-cert/v1_2_test_dua_handle_address_error.py b/tests/scripts/thread-cert/v1_2_test_dua_handle_address_error.py index 68aefc831..78cb1da96 100755 --- a/tests/scripts/thread-cert/v1_2_test_dua_handle_address_error.py +++ b/tests/scripts/thread-cert/v1_2_test_dua_handle_address_error.py @@ -102,7 +102,6 @@ class TestDomainUnicastAddress(thread_cert.TestCase): self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX, 'prosD') self.simulator.go(WAIT_REDUNDANCE) - assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) # 2) Bring up ROUTER_1 self.nodes[ROUTER].start()