Skip to content

Commit

Permalink
[ncp] integrate netif multicast address update (#2460)
Browse files Browse the repository at this point in the history
This commit integrates `Netif` multicast address update with
`NcpSpinel` so that wpan will join the multicast group that NCP joins.
  • Loading branch information
Irving-cl authored Aug 28, 2024
1 parent 5ff6ef7 commit 180e27b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/ncp/ncp_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void NcpHost::Init(void)

mNcpSpinel.Ip6SetAddressCallback(
[this](const std::vector<Ip6AddressInfo> &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); });
mNcpSpinel.Ip6SetAddressMulticastCallback(
[this](const std::vector<Ip6Address> &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); });
mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); });
}

Expand Down
33 changes: 33 additions & 0 deletions src/ncp/ncp_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ip6Address> 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;
Expand Down Expand Up @@ -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<Ip6Address> &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;
Expand Down
26 changes: 22 additions & 4 deletions src/ncp/ncp_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ class PropsObserver
class NcpSpinel
{
public:
using Ip6AddressTableCallback = std::function<void(const std::vector<Ip6AddressInfo> &)>;
using NetifStateChangedCallback = std::function<void(bool)>;
using Ip6AddressTableCallback = std::function<void(const std::vector<Ip6AddressInfo> &)>;
using Ip6MulticastAddressTableCallback = std::function<void(const std::vector<Ip6Address> &)>;
using NetifStateChangedCallback = std::function<void(bool)>;

/**
* Constructor.
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -257,6 +273,7 @@ class NcpSpinel
otError SendEncodedFrame(void);

otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector<Ip6AddressInfo> &aAddressTable);
otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector<Ip6Address> &aAddressList);

ot::Spinel::SpinelDriver *mSpinelDriver;
uint16_t mCmdTidsInUse; ///< Used transaction ids.
Expand All @@ -283,8 +300,9 @@ class NcpSpinel
AsyncTaskPtr mThreadDetachGracefullyTask;
AsyncTaskPtr mThreadErasePersistentInfoTask;

Ip6AddressTableCallback mIp6AddressTableCallback;
NetifStateChangedCallback mNetifStateChangedCallback;
Ip6AddressTableCallback mIp6AddressTableCallback;
Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback;
NetifStateChangedCallback mNetifStateChangedCallback;
};

} // namespace Ncp
Expand Down
15 changes: 15 additions & 0 deletions tests/scripts/expect/ncp_netif_address_update.exp
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down

0 comments on commit 180e27b

Please sign in to comment.