mirror of
https://github.com/espressif/openthread.git
synced 2026-07-25 21:44:07 +00:00
[mlr] simplify multicast address state tracking (#13089)
This commit simplifies the tracking of Multicast Listener Registration (MLR) state for IPv6 addresses by removing intermediate states and relying on the original CoAP request payload. Previously, `Mlr::Manager` used a 3-state system (`kStateToRegister`, `kStateRegistering`, `kStateRegistered`) which required core structures like `Child` and `Netif` to track transient registration states. This commit reduces the state to a single boolean (`IsMlrRegistered`) tracked in `ChildTable` and `ThreadNetif`. When a CoAP response is received, `Mlr::Manager` now uses `GetDispatchingRequest()` to retrieve the original TMR MLE request message, parses the `Ip6AddressesTlv` to determine exactly which addresses were included in the request, and updates the registration states based purely on this info (minus any explicitly failed addresses). This change improves robustness, reduces RAM usage by eliminating state-tracking arrays, and significantly cleans up the logical flow within the MLR manager.
This commit is contained in:
committed by
GitHub
parent
1f24ace91a
commit
ddfd66526e
@@ -742,6 +742,18 @@ public:
|
||||
*/
|
||||
bool MatchesPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const;
|
||||
|
||||
/**
|
||||
* Indicates whether the address matches a given other address.
|
||||
*
|
||||
* This method is intended to be used with `FindMatching()` in collections.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address to match against.
|
||||
*
|
||||
* @retval TRUE If the address matches @p aAddress.
|
||||
* @retval FALSE If the address does not match @p aAddress.
|
||||
*/
|
||||
bool Matches(const Ip6::Address &aAddress) const { return (*this == aAddress); }
|
||||
|
||||
/**
|
||||
* Sets the IPv6 address prefix.
|
||||
*
|
||||
|
||||
@@ -613,11 +613,6 @@ void Netif::MulticastAddress::InitAsManualOrigin(void)
|
||||
{
|
||||
Clear();
|
||||
mAddressOrigin = kOriginManual;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
// Make sure `Clear()` sets the "MlrState" to `Mlr::kStateToRegister` value.
|
||||
static_assert(Mlr::kStateToRegister == 0, "Mlr::kStateToRegister is not correct.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
@@ -627,11 +622,6 @@ bool Netif::MulticastAddress::IsMlrCandidate(void) const
|
||||
return (GetOrigin() == kOriginManual) && GetAddress().IsMulticastLargerThanRealmLocal();
|
||||
}
|
||||
|
||||
bool Netif::MulticastAddress::Matches(Mlr::State aMlrState) const
|
||||
{
|
||||
return IsMlrCandidate() && (GetMlrState() == aMlrState);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Ip6
|
||||
|
||||
+7
-16
@@ -290,28 +290,19 @@ public:
|
||||
bool IsMlrCandidate(void) const;
|
||||
|
||||
/**
|
||||
* Returns the current Multicast Listener Registration (MLR) state.
|
||||
* Indicates whether the multicast address is registered via Multicast Listener Registration (MLR).
|
||||
*
|
||||
* @returns The current Multicast Listener Registration state.
|
||||
* @retval TRUE If the multicast address is MLR registered.
|
||||
* @retval FALSE If the multicast address is not MLR registered.
|
||||
*/
|
||||
Mlr::State GetMlrState(void) const { return static_cast<Mlr::State>(mData); }
|
||||
bool IsMlrRegistered(void) const { return (mData != 0); }
|
||||
|
||||
/**
|
||||
* Sets the Multicast Listener Registration (MLR) state.
|
||||
* Sets whether the multicast address is registered via Multicast Listener Registration (MLR).
|
||||
*
|
||||
* @param[in] aState The new Multicast Listener Registration state.
|
||||
* @param[in] aRegistered TRUE if MLR registered, FALSE otherwise.
|
||||
*/
|
||||
void SetMlrState(Mlr::State aState) { mData = aState; }
|
||||
|
||||
/**
|
||||
* Indicates whether or not the address is an MLR candidate and matches a given MLR state.
|
||||
*
|
||||
* @param[in] aMlrState The MLR state to match against.
|
||||
*
|
||||
* @retval TRUE If the address is an MLR candidate and its state matches @p aMlrState.
|
||||
* @retval FALSE If the address is not an MLR candidate or its state does not match @p aMlrState.
|
||||
*/
|
||||
bool Matches(Mlr::State aMlrState) const;
|
||||
void SetMlrRegistered(bool aRegistered) { mData = aRegistered ? 1 : 0; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -76,38 +76,15 @@ void Child::Info::SetFrom(const Child &aChild)
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
|
||||
Mlr::State Child::Ip6AddrEntry::GetMlrState(const Child &aChild) const
|
||||
bool Child::Ip6AddrEntry::IsMlrRegistered(const Child &aChild) const
|
||||
{
|
||||
Mlr::State state = Mlr::kStateRegistering;
|
||||
Ip6AddressArray::IndexType index;
|
||||
|
||||
OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this));
|
||||
|
||||
index = aChild.mIp6Addresses.IndexOf(*this);
|
||||
|
||||
if (aChild.mMlrToRegisterSet.Has(index))
|
||||
{
|
||||
state = Mlr::kStateToRegister;
|
||||
}
|
||||
else if (aChild.mMlrRegisteredSet.Has(index))
|
||||
{
|
||||
state = Mlr::kStateRegistered;
|
||||
}
|
||||
|
||||
return state;
|
||||
return aChild.mMlrRegisteredSet.Has(aChild.mIp6Addresses.IndexOf(*this));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||
void Child::Ip6AddrEntry::SetMlrState(Mlr::State aState, Child &aChild)
|
||||
void Child::Ip6AddrEntry::SetMlrRegistered(bool aRegistered, Child &aChild)
|
||||
{
|
||||
Ip6AddressArray::IndexType index;
|
||||
|
||||
OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this));
|
||||
|
||||
index = aChild.mIp6Addresses.IndexOf(*this);
|
||||
|
||||
aChild.mMlrToRegisterSet.Update(index, aState == Mlr::kStateToRegister);
|
||||
aChild.mMlrRegisteredSet.Update(index, aState == Mlr::kStateRegistered);
|
||||
aChild.mMlrRegisteredSet.Update(aChild.mIp6Addresses.IndexOf(*this), aRegistered);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
@@ -128,7 +105,6 @@ void Child::ClearIp6Addresses(void)
|
||||
mMeshLocalIid.Clear();
|
||||
mIp6Addresses.Clear();
|
||||
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
mMlrToRegisterSet.Clear();
|
||||
mMlrRegisteredSet.Clear();
|
||||
#endif
|
||||
}
|
||||
@@ -230,9 +206,6 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
|
||||
uint16_t entryIndex = mIp6Addresses.IndexOf(*entry);
|
||||
uint16_t lastIndex = mIp6Addresses.GetLength() - 1;
|
||||
|
||||
mMlrToRegisterSet.Update(entryIndex, mMlrToRegisterSet.Has(lastIndex));
|
||||
mMlrToRegisterSet.Remove(lastIndex);
|
||||
|
||||
mMlrRegisteredSet.Update(entryIndex, mMlrRegisteredSet.Has(lastIndex));
|
||||
mMlrRegisteredSet.Remove(lastIndex);
|
||||
}
|
||||
@@ -292,7 +265,8 @@ bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
|
||||
|
||||
entry = mIp6Addresses.FindMatching(aAddress);
|
||||
VerifyOrExit(entry != nullptr);
|
||||
hasAddress = entry->GetMlrState(*this) == Mlr::kStateRegistered;
|
||||
|
||||
hasAddress = entry->IsMlrRegistered(*this);
|
||||
|
||||
exit:
|
||||
return hasAddress;
|
||||
|
||||
+20
-23
@@ -102,21 +102,22 @@ public:
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
/**
|
||||
* Gets the MLR state of the IPv6 address entry.
|
||||
* Indicates whether the IPv6 address is registered via Multicast Listener Registration (MLR) on a given child.
|
||||
*
|
||||
* @param[in] aChild The child owning this address entry.
|
||||
* @param[in] aChild The child associated with the address.
|
||||
*
|
||||
* @returns The MLR state of IPv6 address entry.
|
||||
* @retval TRUE If the address is MLR registered on @p aChild.
|
||||
* @retval FALSE If the address is not MLR registered on @p aChild.
|
||||
*/
|
||||
Mlr::State GetMlrState(const Child &aChild) const;
|
||||
bool IsMlrRegistered(const Child &aChild) const;
|
||||
|
||||
/**
|
||||
* Sets the MLR state of the IPv6 address entry.
|
||||
* Sets whether the IPv6 address is registered via Multicast Listener Registration (MLR) on a given child.
|
||||
*
|
||||
* @param[in] aState The MLR state.
|
||||
* @param[in] aChild The child owning this address entry.
|
||||
* @param[in] aRegistered TRUE if MLR registered, FALSE otherwise.
|
||||
* @param[in] aChild The child associated with the address.
|
||||
*/
|
||||
void SetMlrState(Mlr::State aState, Child &aChild);
|
||||
void SetMlrRegistered(bool aRegistered, Child &aChild);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -353,30 +354,27 @@ public:
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
/**
|
||||
* Returns if the Child has IPv6 address @p aAddress of MLR state `Mlr::kStateRegistered`.
|
||||
* Clears the Multicast Listener Registration (MLR) registered state on all IPv6 addresses of the child.
|
||||
*/
|
||||
void ClearMlrRegisteredStateOnAllIp6Addresses(void) { mMlrRegisteredSet.Clear(); }
|
||||
|
||||
/**
|
||||
* Indicates whether the child has a given IPv6 address that is MLR registered.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address.
|
||||
*
|
||||
* @retval true If the Child has IPv6 address @p aAddress of MLR state `Mlr::kStateRegistered`.
|
||||
* @retval false If the Child does not have IPv6 address @p aAddress of MLR state `Mlr::kStateRegistered`.
|
||||
* @retval TRUE If the child has the IPv6 address @p aAddress and it is MLR registered.
|
||||
* @retval FALSE If the child does not have the IPv6 address @p aAddress or it is not MLR registered.
|
||||
*/
|
||||
bool HasMlrRegisteredAddress(const Ip6::Address &aAddress) const;
|
||||
|
||||
/**
|
||||
* Returns if the Child has any IPv6 address of MLR state `Mlr::kStateRegistered`.
|
||||
* Indicates whether the child has any IPv6 address that is MLR registered.
|
||||
*
|
||||
* @retval true If the Child has any IPv6 address of MLR state `Mlr::kStateRegistered`.
|
||||
* @retval false If the Child does not have any IPv6 address of MLR state `Mlr::kStateRegistered`.
|
||||
* @retval TRUE If the child has any MLR registered IPv6 address.
|
||||
* @retval FALSE If the child does not have any MLR registered IPv6 address.
|
||||
*/
|
||||
bool HasAnyMlrRegisteredAddress(void) const { return !mMlrRegisteredSet.IsEmpty(); }
|
||||
|
||||
/**
|
||||
* Returns if the Child has any IPv6 address of MLR state `Mlr::kStateToRegister`.
|
||||
*
|
||||
* @retval true If the Child has any IPv6 address of MLR state `Mlr::kStateToRegister`.
|
||||
* @retval false If the Child does not have any IPv6 address of MLR state `Mlr::kStateToRegister`.
|
||||
*/
|
||||
bool HasAnyMlrToRegisterAddress(void) const { return !mMlrToRegisterSet.IsEmpty(); }
|
||||
#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
|
||||
private:
|
||||
@@ -387,7 +385,6 @@ private:
|
||||
Ip6::InterfaceIdentifier mMeshLocalIid;
|
||||
Ip6AddressArray mIp6Addresses;
|
||||
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
ChildIp6AddressSet mMlrToRegisterSet;
|
||||
ChildIp6AddressSet mMlrRegisteredSet;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1874,12 +1874,7 @@ Error Mle::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
|
||||
{
|
||||
for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
|
||||
{
|
||||
if (!addrEntry.IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addrEntry.GetMlrState(aChild) == Mlr::kStateRegistered)
|
||||
if (addrEntry.IsMlrRegistered(aChild))
|
||||
{
|
||||
IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry));
|
||||
}
|
||||
|
||||
+142
-232
@@ -58,7 +58,7 @@ void Manager::HandleNotifierEvents(Events aEvents)
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
if (aEvents.Contains(kEventIp6MulticastSubscribed))
|
||||
{
|
||||
UpdateLocalSubscriptions();
|
||||
HandleEventIp6MulticastSubscribed();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -89,15 +89,14 @@ void Manager::HandleBackboneRouterPrimaryUpdate(BackboneRouter::Leader::State aS
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
void Manager::UpdateLocalSubscriptions(void)
|
||||
void Manager::HandleEventIp6MulticastSubscribed(void)
|
||||
{
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
// Check multicast addresses are newly listened against Children
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.Matches(kStateToRegister) && IsAddressRegisteredByAnyChild(addr.GetAddress()))
|
||||
if (addr.IsMlrCandidate() && !addr.IsMlrRegistered() && IsAddressRegisteredByAnyChild(addr.GetAddress()))
|
||||
{
|
||||
addr.SetMlrState(kStateRegistered);
|
||||
addr.SetMlrRegistered(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -107,20 +106,18 @@ void Manager::UpdateLocalSubscriptions(void)
|
||||
|
||||
bool Manager::IsAddressRegisteredByNetif(const Ip6::Address &aAddress) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
OT_ASSERT(aAddress.IsMulticastLargerThanRealmLocal());
|
||||
bool isRegistered = false;
|
||||
|
||||
for (const Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.Matches(kStateRegistered) && (addr.GetAddress() == aAddress))
|
||||
if (addr.IsMlrRegistered() && (addr.GetAddress() == aAddress))
|
||||
{
|
||||
ret = true;
|
||||
isRegistered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return isRegistered;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
@@ -129,27 +126,26 @@ bool Manager::IsAddressRegisteredByNetif(const Ip6::Address &aAddress) const
|
||||
|
||||
bool Manager::IsAddressRegisteredByAnyChildExcept(const Ip6::Address &aAddress, const Child *aExceptChild) const
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
OT_ASSERT(aAddress.IsMulticastLargerThanRealmLocal());
|
||||
bool isRegistered = false;
|
||||
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
if (&child != aExceptChild && child.HasMlrRegisteredAddress(aAddress))
|
||||
{
|
||||
ExitNow(ret = true);
|
||||
isRegistered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
return isRegistered;
|
||||
}
|
||||
|
||||
void Manager::UpdateProxiedSubscriptions(Child &aChild, const ChildAddressArray &aOldRegisteredAddresses)
|
||||
{
|
||||
bool hasUnregistered = false;
|
||||
|
||||
VerifyOrExit(aChild.IsStateValid());
|
||||
|
||||
// Search the new multicast addresses and set its flag accordingly
|
||||
for (Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
|
||||
{
|
||||
bool isRegistered;
|
||||
@@ -162,22 +158,25 @@ void Manager::UpdateProxiedSubscriptions(Child &aChild, const ChildAddressArray
|
||||
isRegistered = aOldRegisteredAddresses.Contains(addrEntry);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
// Check if it's a new multicast address against parent Netif
|
||||
isRegistered = isRegistered || IsAddressRegisteredByNetif(addrEntry);
|
||||
#endif
|
||||
// Check if it's a new multicast address against other Children
|
||||
isRegistered = isRegistered || IsAddressRegisteredByAnyChildExcept(addrEntry, &aChild);
|
||||
|
||||
addrEntry.SetMlrState(isRegistered ? kStateRegistered : kStateToRegister, aChild);
|
||||
addrEntry.SetMlrRegistered(isRegistered, aChild);
|
||||
|
||||
if (!isRegistered)
|
||||
{
|
||||
hasUnregistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
LogMulticastAddresses();
|
||||
|
||||
if (aChild.HasAnyMlrToRegisterAddress())
|
||||
if (hasUnregistered)
|
||||
{
|
||||
ScheduleSend(Random::NonCrypto::GetUint16InRange(1, BackboneRouter::kParentAggregateDelay));
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
@@ -228,6 +227,37 @@ exit:
|
||||
return shouldRegister;
|
||||
}
|
||||
|
||||
void Manager::DetermineAddressesToRegister(AddressArray &aAddresses) const
|
||||
{
|
||||
aAddresses.Clear();
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (const Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.IsMlrCandidate() && !addr.IsMlrRegistered())
|
||||
{
|
||||
SuccessOrExit(aAddresses.AddUnique(addr.GetAddress()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (const Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (addrEntry.IsMulticastLargerThanRealmLocal() && !addrEntry.IsMlrRegistered(child))
|
||||
{
|
||||
SuccessOrExit(aAddresses.AddUnique(addrEntry));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Manager::Send(void)
|
||||
{
|
||||
Error error;
|
||||
@@ -238,59 +268,9 @@ void Manager::Send(void)
|
||||
VerifyOrExit(Get<Mle::Mle>().IsAttached(), error = kErrorInvalidState);
|
||||
VerifyOrExit(ShouldRegister(), error = kErrorInvalidState);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
// Append Netif multicast addresses
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addresses.IsFull())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr.Matches(kStateToRegister))
|
||||
{
|
||||
IgnoreError(addresses.AddUnique(addr.GetAddress()));
|
||||
addr.SetMlrState(kStateRegistering);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
// Append Child multicast addresses
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
if (addresses.IsFull())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!child.HasAnyMlrToRegisterAddress())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (!addrEntry.IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addresses.IsFull())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (addrEntry.GetMlrState(child) == kStateToRegister)
|
||||
{
|
||||
IgnoreError(addresses.AddUnique(addrEntry));
|
||||
addrEntry.SetMlrState(kStateRegistering, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DetermineAddressesToRegister(addresses);
|
||||
VerifyOrExit(!addresses.IsEmpty(), error = kErrorNotFound);
|
||||
|
||||
SuccessOrExit(error = SendMessage(addresses.GetArrayBuffer(), addresses.GetLength(), nullptr, HandleResponse));
|
||||
|
||||
mPending = true;
|
||||
@@ -304,17 +284,10 @@ void Manager::Send(void)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != kErrorNone)
|
||||
if (error == kErrorNoBufs)
|
||||
{
|
||||
SetMulticastAddressState(kStateRegistering, kStateToRegister);
|
||||
|
||||
if (error == kErrorNoBufs)
|
||||
{
|
||||
ScheduleSend(1);
|
||||
}
|
||||
ScheduleSend(1);
|
||||
}
|
||||
|
||||
LogMulticastAddresses();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
|
||||
@@ -422,26 +395,84 @@ exit:
|
||||
|
||||
void Manager::HandleResponse(Coap::Msg *aMsg, Error aResult)
|
||||
{
|
||||
uint8_t status;
|
||||
Error error;
|
||||
AddressArray failedAddresses;
|
||||
Error error;
|
||||
uint8_t status;
|
||||
AddressArray failedAddresses;
|
||||
AddressArray registeredAddresses;
|
||||
OwnedPtr<Coap::Message> requestMsg;
|
||||
|
||||
error = ParseResponse(aResult, aMsg, status, failedAddresses);
|
||||
mPending = false;
|
||||
|
||||
Finish(error == kErrorNone && status == kStatusSuccess, failedAddresses);
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Parse the response message
|
||||
|
||||
if (error == kErrorNone && status == kStatusSuccess)
|
||||
SuccessOrExit(error = ParseResponse(aResult, aMsg, status, failedAddresses));
|
||||
|
||||
if (status != kStatusSuccess)
|
||||
{
|
||||
// keep sending until all multicast addresses are registered.
|
||||
// If status is failure and the failed address list is empty,
|
||||
// all registrations failed. If a non-empty failed address
|
||||
// list is provided, only the addresses in the list failed
|
||||
// (if an address is not in the list, its registration was
|
||||
// successful).
|
||||
|
||||
VerifyOrExit(!failedAddresses.IsEmpty());
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Retrieve the original TMF MLR request message and parse it
|
||||
// to find the list of addresses included in the request. Remove
|
||||
// addresses in `failedAddresses`.
|
||||
|
||||
SuccessOrExit(error = Get<Tmf::Agent>().GetDispatchingRequest(requestMsg));
|
||||
SuccessOrExit(error = Ip6AddressesTlv::FindIn(*requestMsg, registeredAddresses));
|
||||
|
||||
for (const Ip6::Address &addr : failedAddresses)
|
||||
{
|
||||
registeredAddresses.RemoveMatching(addr);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Update the registration state of addresses on `ThreadNetif` and
|
||||
// `ChildTable`.
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.IsMlrCandidate() && !addr.IsMlrRegistered() && registeredAddresses.Contains(addr.GetAddress()))
|
||||
{
|
||||
addr.SetMlrRegistered(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (addrEntry.IsMulticastLargerThanRealmLocal() && !addrEntry.IsMlrRegistered(child) &&
|
||||
registeredAddresses.Contains(addrEntry))
|
||||
{
|
||||
addrEntry.SetMlrRegistered(true, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if ((error == kErrorNone) && (status == kStatusSuccess))
|
||||
{
|
||||
// Send an MLR request for any remaining unregistered addresses.
|
||||
ScheduleSend(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
BackboneRouter::Config config;
|
||||
|
||||
// If a registration attempt fails, retry it after a random
|
||||
// delay (same as re-registration delay).
|
||||
|
||||
BackboneRouter::Config config;
|
||||
|
||||
if (Get<BackboneRouter::Leader>().GetConfig(config) == kErrorNone)
|
||||
{
|
||||
ScheduleSend(DetermineReregistrationDelay(config));
|
||||
@@ -501,105 +532,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Manager::SetMulticastAddressState(State aFromState, State aToState)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.Matches(aFromState))
|
||||
{
|
||||
addr.SetMlrState(aToState);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (!addrEntry.IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addrEntry.GetMlrState(child) == aFromState)
|
||||
{
|
||||
addrEntry.SetMlrState(aToState, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Manager::DidRegisterSuccessfully(const Ip6::Address &aAddress, bool aSuccess, const AddressArray &aFailedAddresses)
|
||||
{
|
||||
// If the operation succeeded, all address registrations were successful.
|
||||
//
|
||||
// If it failed and the failed address list is empty, all registrations
|
||||
// failed.
|
||||
//
|
||||
// If it failed and a non-empty failed address list is provided, only the
|
||||
// addresses in the list failed (if an address is not in the list, its
|
||||
// registration was successful).
|
||||
|
||||
bool didRegister;
|
||||
|
||||
if (aSuccess)
|
||||
{
|
||||
didRegister = true;
|
||||
}
|
||||
else if (aFailedAddresses.IsEmpty())
|
||||
{
|
||||
didRegister = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
didRegister = !aFailedAddresses.Contains(aAddress);
|
||||
}
|
||||
|
||||
return didRegister;
|
||||
}
|
||||
|
||||
void Manager::Finish(bool aSuccess, const AddressArray &aFailedAddresses)
|
||||
{
|
||||
OT_ASSERT(mPending);
|
||||
|
||||
mPending = false;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.Matches(kStateRegistering))
|
||||
{
|
||||
bool didRegister = DidRegisterSuccessfully(addr.GetAddress(), aSuccess, aFailedAddresses);
|
||||
|
||||
addr.SetMlrState(didRegister ? kStateRegistered : kStateToRegister);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (!addrEntry.IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addrEntry.GetMlrState(child) == kStateRegistering)
|
||||
{
|
||||
bool didRegister = DidRegisterSuccessfully(addrEntry, aSuccess, aFailedAddresses);
|
||||
|
||||
addrEntry.SetMlrState(didRegister ? kStateRegistered : kStateToRegister, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LogMulticastAddresses();
|
||||
}
|
||||
|
||||
void Manager::HandleTimeTick(void)
|
||||
{
|
||||
if (mSendDelay > 0 && --mSendDelay == 0)
|
||||
@@ -617,9 +549,23 @@ void Manager::HandleTimeTick(void)
|
||||
|
||||
void Manager::Reregister(void)
|
||||
{
|
||||
LogInfo("MLR Reregister!");
|
||||
LogInfo("Reregister");
|
||||
|
||||
SetMulticastAddressState(kStateRegistered, kStateToRegister);
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (addr.IsMlrCandidate())
|
||||
{
|
||||
addr.SetMlrRegistered(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
child.ClearMlrRegisteredStateOnAllIp6Addresses();
|
||||
}
|
||||
#endif
|
||||
|
||||
ScheduleSend(0);
|
||||
|
||||
@@ -688,42 +634,6 @@ exit:
|
||||
UpdateTimeTickerRegistration();
|
||||
}
|
||||
|
||||
void Manager::LogMulticastAddresses(void)
|
||||
{
|
||||
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG)
|
||||
LogDebg("-------- Multicast Addresses --------");
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
for (const Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().GetMulticastAddresses())
|
||||
{
|
||||
if (!addr.IsMlrCandidate())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LogDebg("%-32s%c", addr.GetAddress().ToString().AsCString(), "-rR"[addr.GetMlrState()]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
|
||||
for (const Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses())
|
||||
{
|
||||
if (!addrEntry.IsMulticastLargerThanRealmLocal())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LogDebg("%-32s%c %04x", addrEntry.ToString().AsCString(), "-rR"[addrEntry.GetMlrState(child)],
|
||||
child.GetRloc16());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_DEBG)
|
||||
}
|
||||
|
||||
} // namespace Mlr
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ private:
|
||||
|
||||
void HandleNotifierEvents(Events aEvents);
|
||||
bool ShouldRegister(void) const;
|
||||
void DetermineAddressesToRegister(AddressArray &aAddresses) const;
|
||||
void Send(void);
|
||||
Error SendMessage(const Ip6::Address *aAddresses,
|
||||
uint8_t aAddressNum,
|
||||
@@ -164,18 +165,14 @@ private:
|
||||
|
||||
static uint16_t DetermineReregistrationDelay(const BackboneRouter::Config &aConfig);
|
||||
static uint32_t DetermineRenewDelay(const BackboneRouter::Config &aConfig);
|
||||
|
||||
static Error ParseResponse(Error aResult, Coap::Msg *aMsg, uint8_t &aStatus, AddressArray &aFailedAddresses);
|
||||
static bool DidRegisterSuccessfully(const Ip6::Address &aAddress,
|
||||
bool aSuccess,
|
||||
const AddressArray &aFailedAddresses);
|
||||
static Error ParseResponse(Error aResult, Coap::Msg *aMsg, uint8_t &aStatus, AddressArray &aFailedAddresses);
|
||||
|
||||
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
|
||||
DeclareTmfResponseHandlerIn(Manager, HandleRegisterResponse);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE
|
||||
void UpdateLocalSubscriptions(void);
|
||||
void HandleEventIp6MulticastSubscribed(void);
|
||||
bool IsAddressRegisteredByNetif(const Ip6::Address &aAddress) const;
|
||||
#endif
|
||||
|
||||
@@ -188,14 +185,11 @@ private:
|
||||
bool IsAddressRegisteredByAnyChildExcept(const Ip6::Address &aAddress, const Child *aExceptChild) const;
|
||||
#endif
|
||||
|
||||
void SetMulticastAddressState(State aFromState, State aToState);
|
||||
void Finish(bool aSuccess, const AddressArray &aFailedAddresses);
|
||||
void ScheduleSend(uint16_t aDelay);
|
||||
void UpdateTimeTickerRegistration(void);
|
||||
void ScheduleNextRegistration(RegistrationRequest aRequest);
|
||||
void Reregister(void);
|
||||
void HandleTimeTick(void);
|
||||
void LogMulticastAddresses(void);
|
||||
|
||||
#if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE) && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
|
||||
Callback<RegisterCallback> mRegisterCallback;
|
||||
|
||||
@@ -52,20 +52,6 @@ namespace Mlr {
|
||||
constexpr uint8_t kMinIp6Addresses = 1; ///< Min number of addresses in IPv6 Addresses TLV.
|
||||
constexpr uint8_t kMaxIp6Addresses = OT_IP6_MAX_MLR_ADDRESSES; ///< Max number of addresses in IPv6 Addresses TLV.
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
|
||||
|
||||
/**
|
||||
* MLR registration state for a multicast address.
|
||||
*/
|
||||
enum State : uint8_t
|
||||
{
|
||||
kStateToRegister, ///< The multicast address is to be registered.
|
||||
kStateRegistering, ///< The multicast address is being registered.
|
||||
kStateRegistered, ///< The multicast address is registered.
|
||||
};
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
|
||||
|
||||
/**
|
||||
* Multicast Listener Registration (MLR) Status values.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user