From 180e27b20c5353dd5bd2f193e0ac678cf3e012ca Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 28 Aug 2024 23:05:09 +0800 Subject: [PATCH] [ncp] integrate netif multicast address update (#2460) This commit integrates `Netif` multicast address update with `NcpSpinel` so that wpan will join the multicast group that NCP joins. --- src/ncp/ncp_host.cpp | 2 ++ src/ncp/ncp_spinel.cpp | 33 +++++++++++++++++++ src/ncp/ncp_spinel.hpp | 26 ++++++++++++--- .../expect/ncp_netif_address_update.exp | 15 +++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/ncp/ncp_host.cpp b/src/ncp/ncp_host.cpp index cb95025f492..19af5e8d640 100644 --- a/src/ncp/ncp_host.cpp +++ b/src/ncp/ncp_host.cpp @@ -86,6 +86,8 @@ void NcpHost::Init(void) mNcpSpinel.Ip6SetAddressCallback( [this](const std::vector &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); }); + mNcpSpinel.Ip6SetAddressMulticastCallback( + [this](const std::vector &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); }); mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); }); } diff --git a/src/ncp/ncp_spinel.cpp b/src/ncp/ncp_spinel.cpp index 84c1dd65306..7c09e857f50 100644 --- a/src/ncp/ncp_spinel.cpp +++ b/src/ncp/ncp_spinel.cpp @@ -366,6 +366,16 @@ void NcpSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, ui break; } + case SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE: + { + std::vector addressTable; + + VerifyOrExit(ParseIp6MulticastAddresses(aBuffer, aLength, addressTable) == OT_ERROR_NONE, + error = OTBR_ERROR_PARSE); + SafeInvoke(mIp6MulticastAddressTableCallback, addressTable); + break; + } + case SPINEL_PROP_NET_IF_UP: { bool isUp; @@ -545,6 +555,29 @@ otError NcpSpinel::ParseIp6AddressTable(const uint8_t *aBuf, return error; } +otError NcpSpinel::ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector &aAddressList) +{ + otError error = OT_ERROR_NONE; + ot::Spinel::Decoder decoder; + + VerifyOrExit(aBuf != nullptr, error = OT_ERROR_INVALID_ARGS); + + decoder.Init(aBuf, aLen); + + while (!decoder.IsAllReadInStruct()) + { + const otIp6Address *addr; + + SuccessOrExit(error = decoder.OpenStruct()); + SuccessOrExit(error = decoder.ReadIp6Address(addr)); + aAddressList.emplace_back(Ip6Address(*addr)); + SuccessOrExit((error = decoder.CloseStruct())); + } + +exit: + return error; +} + otDeviceRole NcpSpinel::SpinelRoleToDeviceRole(spinel_net_role_t aRole) { otDeviceRole role = OT_DEVICE_ROLE_DISABLED; diff --git a/src/ncp/ncp_spinel.hpp b/src/ncp/ncp_spinel.hpp index 3db6dcedfbb..d8d4de10420 100644 --- a/src/ncp/ncp_spinel.hpp +++ b/src/ncp/ncp_spinel.hpp @@ -83,8 +83,9 @@ class PropsObserver class NcpSpinel { public: - using Ip6AddressTableCallback = std::function &)>; - using NetifStateChangedCallback = std::function; + using Ip6AddressTableCallback = std::function &)>; + using Ip6MulticastAddressTableCallback = std::function &)>; + using NetifStateChangedCallback = std::function; /** * Constructor. @@ -162,6 +163,21 @@ class NcpSpinel */ void Ip6SetAddressCallback(const Ip6AddressTableCallback &aCallback) { mIp6AddressTableCallback = aCallback; } + /** + * This method sets the callback to receive the IPv6 multicast address table from the NCP. + * + * @param[in] aCallback The callback to handle the IPv6 address table. + * + * The callback will be invoked when receiving an IPv6 multicast address table from the NCP. + * When the callback is invoked, the callback MUST copy the otIp6Address objects and maintain it + * if it's not used immediately (within the callback). + * + */ + void Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback &aCallback) + { + mIp6MulticastAddressTableCallback = aCallback; + } + /** * This method enableds/disables the Thread network on the NCP. * @@ -257,6 +273,7 @@ class NcpSpinel otError SendEncodedFrame(void); otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector &aAddressTable); + otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector &aAddressList); ot::Spinel::SpinelDriver *mSpinelDriver; uint16_t mCmdTidsInUse; ///< Used transaction ids. @@ -283,8 +300,9 @@ class NcpSpinel AsyncTaskPtr mThreadDetachGracefullyTask; AsyncTaskPtr mThreadErasePersistentInfoTask; - Ip6AddressTableCallback mIp6AddressTableCallback; - NetifStateChangedCallback mNetifStateChangedCallback; + Ip6AddressTableCallback mIp6AddressTableCallback; + Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback; + NetifStateChangedCallback mNetifStateChangedCallback; }; } // namespace Ncp diff --git a/tests/scripts/expect/ncp_netif_address_update.exp b/tests/scripts/expect/ncp_netif_address_update.exp index 7c672ca9c80..974b563301c 100755 --- a/tests/scripts/expect/ncp_netif_address_update.exp +++ b/tests/scripts/expect/ncp_netif_address_update.exp @@ -62,6 +62,21 @@ expect -re {fd0d:7fc:a1b9:f050(:[0-9a-f]{1,4}){4,4}} expect -re {fe80:(:[0-9a-f]{1,4}){4,4}} expect eof +# Multicast addresses should contain: +# 1. ff01::1 +# 2. ff02::1 +# 3. ff02::2 +# 4. ff03::1 +# 5. ff03::2 +spawn ip maddr show dev wpan0 +expect eof +set maddr_output $expect_out(buffer) +if {![string match "*ff01::1*" $maddr_output]} { fail "No multicast address ff01::1" } +if {![string match "*ff02::1*" $maddr_output]} { fail "No multicast address ff02::1" } +if {![string match "*ff02::2*" $maddr_output]} { fail "No multicast address ff02::2" } +if {![string match "*ff03::1*" $maddr_output]} { fail "No multicast address ff03::1" } +if {![string match "*ff03::2*" $maddr_output]} { fail "No multicast address ff03::2" } + # Step 4. Verify the wpan isUp state spawn ip link show wpan0 expect -re {UP}