From 21b5764686b4ead0d13096db75fb8b0208b02030 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 26 Jun 2024 08:12:02 -0700 Subject: [PATCH] [child] add `GetIp6Addresses()` and simplify MLR state tracking (#10424) This commit introduces several changes to the `Child` class for managing registered IPv6 addresses by MTD children: - A new method, `Child::GetIp6Addresses()`, is added, returning the `Array` of registered IPv6 address entries. This array includes all tracked child IPv6 addresses except for the mesh-local EID, which can be retrieved using `Child::GetMeshLocalIp6Address()`. - The simplified model enables easy iteration over the address array using `Array` range-based `for` loops. With this change, the complex `AddressIterator` and `AddressIteratorBuilder` nested classes are removed, streamlining the code. - MLR state tracking for child IPv6 address entries is simplified with the introduction of a new class, `Child::Ip6AddrEntry`, representing a registered IPv6 address entry. This class provides `GetMlrState()` and `SetMlrState()`, enforcing that the MLR state can only be set on a child IPv6 address entry. --- src/core/api/thread_ftd_api.cpp | 10 +- src/core/thread/child.cpp | 141 ++++++------- src/core/thread/child.hpp | 281 ++++++++----------------- src/core/thread/mle.cpp | 11 +- src/core/thread/mle_router.cpp | 12 +- src/core/thread/mlr_manager.cpp | 76 +++++-- src/core/thread/network_diagnostic.cpp | 17 +- tests/unit/test_child.cpp | 97 +-------- 8 files changed, 241 insertions(+), 404 deletions(-) diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index ec3b9b4d4..6b3f554ee 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -250,15 +250,7 @@ otError otThreadGetChildNextIp6Address(otInstance *aInstance, VerifyOrExit(child != nullptr, error = kErrorInvalidArgs); VerifyOrExit(child->IsStateValidOrRestoring(), error = kErrorInvalidArgs); - { - Child::AddressIterator iter(*child, *aIterator); - - VerifyOrExit(!iter.IsDone(), error = kErrorNotFound); - *aAddress = *iter.GetAddress(); - - iter++; - *aIterator = iter.GetAsIndex(); - } + error = child->GetNextIp6Address(*aIterator, AsCoreType(aAddress)); exit: return error; diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index a91512587..0f4efacd9 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -44,6 +44,9 @@ namespace ot { #if OPENTHREAD_FTD +//--------------------------------------------------------------------------------------------------------------------- +// Child::Info + void Child::Info::SetFrom(const Child &aChild) { Clear(); @@ -75,51 +78,50 @@ void Child::Info::SetFrom(const Child &aChild) #endif } -const Ip6::Address *Child::AddressIterator::GetAddress(void) const +//--------------------------------------------------------------------------------------------------------------------- +// Child::Ip6AddrEntry + +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + +MlrState Child::Ip6AddrEntry::GetMlrState(const Child &aChild) const { - // `mIndex` value of zero indicates mesh-local IPv6 address. - // Non-zero value specifies the index into address array starting - // from one for first element (i.e, `mIndex - 1` gives the array - // index). + MlrState state = kMlrStateRegistering; + Ip6AddressArray::IndexType index; - const Ip6::Address *address = nullptr; + OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this)); - if (mIndex == 0) + index = aChild.mIp6Addresses.IndexOf(*this); + + if (aChild.mMlrToRegisterMask.Get(index)) { - address = &mMeshLocalAddress; - ExitNow(); + state = kMlrStateToRegister; + } + else if (aChild.mMlrRegisteredMask.Get(index)) + { + state = kMlrStateRegistered; } - VerifyOrExit(mIndex - 1 < mChild.mIp6Addresses.GetLength()); - address = &mChild.mIp6Addresses[static_cast(mIndex - 1)]; - -exit: - return address; + return state; } -void Child::AddressIterator::Update(void) +// NOLINTNEXTLINE(readability-make-member-function-const) +void Child::Ip6AddrEntry::SetMlrState(MlrState aState, Child &aChild) { - const Ip6::Address *address; + Ip6AddressArray::IndexType index; - if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone)) - { - mIndex++; - } + OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this)); - while (true) - { - address = GetAddress(); + index = aChild.mIp6Addresses.IndexOf(*this); - VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex); - - VerifyOrExit(!address->MatchesFilter(mFilter)); - mIndex++; - } - -exit: - return; + aChild.mMlrToRegisterMask.Set(index, aState == kMlrStateToRegister); + aChild.mMlrRegisteredMask.Set(index, aState == kMlrStateRegistered); } +#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + +//--------------------------------------------------------------------------------------------------------------------- +// Child + void Child::Clear(void) { Instance &instance = GetInstance(); @@ -164,6 +166,29 @@ exit: return error; } +Error Child::GetNextIp6Address(AddressIterator &aIterator, Ip6::Address &aAddress) const +{ + Error error = kErrorNone; + + if (aIterator == 0) + { + aIterator++; + + if (GetMeshLocalIp6Address(aAddress) == kErrorNone) + { + ExitNow(); + } + } + + VerifyOrExit(aIterator - 1 < mIp6Addresses.GetLength(), error = kErrorNotFound); + + aAddress = mIp6Addresses[static_cast(aIterator - 1)]; + aIterator++; + +exit: + return error; +} + Error Child::AddIp6Address(const Ip6::Address &aAddress) { Error error = kErrorNone; @@ -177,8 +202,8 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) ExitNow(); } - VerifyOrExit(!mIp6Addresses.Contains(aAddress), error = kErrorAlready); - error = mIp6Addresses.PushBack(aAddress); + VerifyOrExit(!mIp6Addresses.ContainsMatching(aAddress), error = kErrorAlready); + error = mIp6Addresses.PushBack(static_cast(aAddress)); exit: return error; @@ -187,7 +212,7 @@ exit: Error Child::RemoveIp6Address(const Ip6::Address &aAddress) { Error error = kErrorNotFound; - Ip6::Address *entry; + Ip6AddrEntry *entry; if (Get().IsMeshLocalAddress(aAddress)) { @@ -200,7 +225,7 @@ Error Child::RemoveIp6Address(const Ip6::Address &aAddress) ExitNow(); } - entry = mIp6Addresses.Find(aAddress); + entry = mIp6Addresses.FindMatching(aAddress); VerifyOrExit(entry != nullptr); #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE @@ -239,7 +264,7 @@ bool Child::HasIp6Address(const Ip6::Address &aAddress) const ExitNow(); } - hasAddress = mIp6Addresses.Contains(aAddress); + hasAddress = mIp6Addresses.ContainsMatching(aAddress); exit: return hasAddress; @@ -266,49 +291,21 @@ exit: #endif #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const { - bool has = false; + bool hasAddress = false; + const Ip6AddrEntry *entry; - VerifyOrExit(mMlrRegisteredMask.HasAny()); - - for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) - { - if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress) - { - ExitNow(has = true); - } - } + entry = mIp6Addresses.FindMatching(aAddress); + VerifyOrExit(entry != nullptr); + hasAddress = entry->GetMlrState(*this) == kMlrStateRegistered; exit: - return has; + return hasAddress; } -MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const -{ - uint16_t addressIndex; - - OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - - addressIndex = mIp6Addresses.IndexOf(aAddress); - - return mMlrToRegisterMask.Get(addressIndex) - ? kMlrStateToRegister - : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering); -} - -void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState) -{ - uint16_t addressIndex; - - OT_ASSERT(mIp6Addresses.IsInArrayBuffer(&aAddress)); - - addressIndex = mIp6Addresses.IndexOf(aAddress); - - mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister); - mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered); -} -#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#endif #endif // OPENTHREAD_FTD diff --git a/src/core/thread/child.hpp b/src/core/thread/child.hpp index d2f707f72..1069c7393 100644 --- a/src/core/thread/child.hpp +++ b/src/core/thread/child.hpp @@ -42,6 +42,10 @@ namespace ot { #if OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD < 2 +#error OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD should be at least set to 2. +#endif + /** * Represents a Thread Child. * @@ -54,11 +58,27 @@ class Child : public Neighbor, public CslTxScheduler::ChildInfo #endif { - class AddressIteratorBuilder; - public: static constexpr uint8_t kMaxRequestTlvs = 6; + /** + * Maximum number of registered IPv6 addresses per child (excluding the mesh-local EID). + * + */ + static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; + + /** + * Represents the iterator for registered IPv6 address list of an MTD child. + * + */ + typedef otChildIp6AddressIterator AddressIterator; + + /** + * The initial value for an `AddressIterator`. + * + */ + static constexpr AddressIterator kAddressIteratorInit = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; + /** * Represents diagnostic information for a Thread Child. * @@ -76,146 +96,53 @@ public: }; /** - * Defines an iterator used to go through IPv6 address entries of a child. + * Represents an IPv6 address entry registered by an MTD child. * */ - class AddressIterator : public Unequatable + class Ip6AddrEntry : public Ip6::Address { - friend class AddressIteratorBuilder; - public: /** - * Represents an index indicating the current IPv6 address entry to which the iterator is pointing. + * Indicates whether the entry matches a given IPv6 address. + * + * @param[in] aAddress The IPv6 address. + * + * @retval TRUE The entry matches @p aAddress. + * @retval FALSE The entry does not match @p aAddress. * */ - typedef otChildIp6AddressIterator Index; + bool Matches(const Ip6::Address &aAddress) const { return (*this == aAddress); } + +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + /** + * Gets the MLR state of the IPv6 address entry. + * + * @param[in] aChild The child owning this address entry. + * + * @returns The MLR state of IPv6 address entry. + * + */ + MlrState GetMlrState(const Child &aChild) const; /** - * Initializes the iterator associated with a given `Child` starting from beginning of the - * IPv6 address list. + * Sets the MLR state of the IPv6 address entry. * - * @param[in] aChild A reference to a child entry. - * @param[in] aFilter An IPv6 address type filter restricting iterator to certain type of addresses. + * @param[in] aState The MLR state. + * @param[in] aChild The child owning this address entry. * */ - explicit AddressIterator(const Child &aChild, Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) - : AddressIterator(aChild, 0, aFilter) - { - } - - /** - * Initializes the iterator associated with a given `Child` starting from a given index - * - * @param[in] aChild A reference to the child entry. - * @param[in] aIndex An index (`Index`) with which to initialize the iterator. - * @param[in] aFilter An IPv6 address type filter restricting iterator to certain type of addresses. - * - */ - AddressIterator(const Child &aChild, Index aIndex, Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) - : mChild(aChild) - , mFilter(aFilter) - , mIndex(aIndex) - { - Update(); - } - - /** - * Converts the iterator into an index. - * - * @returns An index corresponding to the iterator. - * - */ - Index GetAsIndex(void) const { return mIndex; } - - /** - * Gets the iterator's associated `Child` entry. - * - * @returns The associated child entry. - * - */ - const Child &GetChild(void) const { return mChild; } - - /** - * Gets the current `Child` IPv6 Address to which the iterator is pointing. - * - * @returns A pointer to the associated IPv6 Address, or `nullptr` if iterator is done. - * - */ - const Ip6::Address *GetAddress(void) const; - - /** - * Indicates whether the iterator has reached end of the list. - * - * @retval TRUE There are no more entries in the list (reached end of the list). - * @retval FALSE The current entry is valid. - * - */ - bool IsDone(void) const { return (mIndex >= kMaxIndex); } - - /** - * Overloads `++` operator (pre-increment) to advance the iterator. - * - * The iterator is moved to point to the next `Address` entry. If there are no more `Ip6::Address` entries - * `IsDone()` returns `true`. - * - */ - void operator++(void) { mIndex++, Update(); } - - /** - * Overloads `++` operator (post-increment) to advance the iterator. - * - * The iterator is moved to point to the next `Address` entry. If there are no more `Ip6::Address` entries - * `IsDone()` returns `true`. - * - */ - void operator++(int) { mIndex++, Update(); } - - /** - * Overloads the `*` dereference operator and gets a reference to `Ip6::Address` to which the - * iterator is currently pointing. - * - * MUST be used when the iterator is not done (i.e., `IsDone()` returns `false`). - * - * @returns A reference to the `Ip6::Address` entry currently pointed by the iterator. - * - */ - const Ip6::Address &operator*(void) const { return *GetAddress(); } - - /** - * Overloads operator `==` to evaluate whether or not two `Iterator` instances are equal. - * - * MUST be used when the two iterators are associated with the same `Child` entry. - * - * @param[in] aOther The other `Iterator` to compare with. - * - * @retval TRUE If the two `Iterator` objects are equal. - * @retval FALSE If the two `Iterator` objects are not equal. - * - */ - bool operator==(const AddressIterator &aOther) const { return (mIndex == aOther.mIndex); } - - private: - enum IteratorType : uint8_t - { - kEndIterator, - }; - - static constexpr uint16_t kMaxIndex = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD; - - AddressIterator(const Child &aChild, IteratorType) - : mChild(aChild) - , mIndex(kMaxIndex) - { - } - - void Update(void); - - const Child &mChild; - Ip6::Address::TypeFilter mFilter; - Index mIndex; - Ip6::Address mMeshLocalAddress; + void SetMlrState(MlrState aState, Child &aChild); +#endif }; + /** + * Represents an array of IPv6 address entries registered by an MTD child. + * + * This array does not include the mesh-local EID. + * + */ + typedef Array Ip6AddressArray; + /** * Initializes the `Child` object. * @@ -264,26 +191,37 @@ public: const Ip6::InterfaceIdentifier &GetMeshLocalIid(void) const { return mMeshLocalIid; } /** - * Enables range-based `for` loop iteration over all (or a subset of) IPv6 addresses. + * Gets an array of registered IPv6 address entries by the child. * - * Should be used as follows: to iterate over all addresses + * The array does not include the mesh-local EID. The ML-EID can retrieved using `GetMeshLocalIp6Address()`. * - * for (const Ip6::Address &address : child.IterateIp6Addresses()) { ... } - * - * or to iterate over a subset of IPv6 addresses determined by a given address type filter - * - * for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticast)) { ... } - * - * @param[in] aFilter An IPv6 address type filter restricting iteration to certain type of addresses (default is - * to accept any address type). - * - * @returns An IteratorBuilder instance. + * @returns The array of registered IPv6 addresses by the child. * */ - AddressIteratorBuilder IterateIp6Addresses(Ip6::Address::TypeFilter aFilter = Ip6::Address::kTypeAny) const - { - return AddressIteratorBuilder(*this, aFilter); - } + const Ip6AddressArray &GetIp6Addresses(void) const { return mIp6Addresses; } + + /** + * Gets an array of registered IPv6 address entries by the child. + * + * The array does not include the mesh-local EID. The ML-EID can retrieved using `GetMeshLocalIp6Address()`. + * + * @returns The array of registered IPv6 addresses by the child. + * + */ + Ip6AddressArray &GetIp6Addresses(void) { return mIp6Addresses; } + + /** + * Iterates over all registered IPv6 addresses (using an iterator). + * + * @param[in,out] aIterator The iterator to use. On success the iterator will be updated. + * To get the first IPv6 address the iterator should be set to `kAddressIteratorInit` + * @param[out] aAddress A reference to an IPv6 address to return the address. + * + * @retval kErrorNone Successfully got the next IPv6 address. @p aIterator and @p aAddress are updated. + * @retval kErrorNotFound No more address. + * + */ + Error GetNextIp6Address(AddressIterator &aIterator, Ip6::Address &aAddress) const; /** * Adds an IPv6 address to the list. @@ -441,30 +379,7 @@ public: */ void ResetSecondsSinceLastSupervision(void) { mSecondsSinceSupervision = 0; } -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - /** - * Returns MLR state of an IPv6 multicast address. - * - * @note The @p aAddress reference MUST be from `IterateIp6Addresses()` or `AddressIterator`. - * - * @param[in] aAddress The IPv6 multicast address. - * - * @returns MLR state of the IPv6 multicast address. - * - */ - MlrState GetAddressMlrState(const Ip6::Address &aAddress) const; - - /** - * Sets MLR state of an IPv6 multicast address. - * - * @note The @p aAddress reference MUST be from `IterateIp6Addresses()` or `AddressIterator`. - * - * @param[in] aAddress The IPv6 multicast address. - * @param[in] aState The target MLR state. - * - */ - void SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState); - +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE /** * Returns if the Child has IPv6 address @p aAddress of MLR state `kMlrStateRegistered`. * @@ -493,40 +408,16 @@ public: * */ bool HasAnyMlrToRegisterAddress(void) const { return mMlrToRegisterMask.HasAny(); } -#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE private: -#if OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD < 2 -#error OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD should be at least set to 2. -#endif - - static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; - - typedef BitVector ChildIp6AddressMask; - typedef Array Ip6AddressArray; - - class AddressIteratorBuilder - { - public: - AddressIteratorBuilder(const Child &aChild, Ip6::Address::TypeFilter aFilter) - : mChild(aChild) - , mFilter(aFilter) - { - } - - AddressIterator begin(void) { return AddressIterator(mChild, mFilter); } - AddressIterator end(void) { return AddressIterator(mChild, AddressIterator::kEndIterator); } - - private: - const Child &mChild; - Ip6::Address::TypeFilter mFilter; - }; + typedef BitVector ChildIp6AddressMask; uint32_t mTimeout; Ip6::InterfaceIdentifier mMeshLocalIid; Ip6AddressArray mIp6Addresses; -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE +#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE ChildIp6AddressMask mMlrToRegisterMask; ChildIp6AddressMask mMlrRegisteredMask; #endif diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 62cc1b4c7..4a009cad9 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -4844,19 +4844,18 @@ Error Mle::TxMessage::AppendAddressRegistrationTlv(Child &aChild) tlv.SetType(Tlv::kAddressRegistration); SuccessOrExit(error = Append(tlv)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + // The parent must echo back all registered IPv6 addresses except + // for the ML-EID, which is excluded by `Child::GetIp6Addresses()`. + + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { if (address.IsMulticast() || Get().GetContext(address, context) != kErrorNone) { SuccessOrExit(error = AppendAddressEntry(address)); } - else if (context.mContextId != kMeshLocalPrefixContextId) - { - SuccessOrExit(error = AppendCompressedAddressEntry(context.mContextId, address)); - } else { - continue; + SuccessOrExit(error = AppendCompressedAddressEntry(context.mContextId, address)); } } diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 9e9b21caa..9ee57cfa6 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1790,12 +1790,16 @@ Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) { OT_ASSERT(aChild.IsStateValid()); - for (const Ip6::Address &childAddress : - aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) { - if (aChild.GetAddressMlrState(childAddress) == kMlrStateRegistered) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) { - IgnoreError(oldMlrRegisteredAddresses.PushBack(childAddress)); + continue; + } + + if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered) + { + IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry)); } } } diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 76d7378c3..43f896e70 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -151,18 +151,25 @@ void MlrManager::UpdateProxiedSubscriptions(Child &aChild, const MlrAddressArray VerifyOrExit(aChild.IsStateValid()); // Search the new multicast addresses and set its flag accordingly - for (const Ip6::Address &address : aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) { - bool isMlrRegistered = aOldMlrRegisteredAddresses.Contains(address); + bool isMlrRegistered; + + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + isMlrRegistered = aOldMlrRegisteredAddresses.Contains(addrEntry); #if OPENTHREAD_CONFIG_MLR_ENABLE // Check if it's a new multicast address against parent Netif - isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByNetif(address); + isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByNetif(addrEntry); #endif // Check if it's a new multicast address against other Children - isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByAnyChildExcept(address, &aChild); + isMlrRegistered = isMlrRegistered || IsAddressMlrRegisteredByAnyChildExcept(addrEntry, &aChild); - aChild.SetAddressMlrState(address, isMlrRegistered ? kMlrStateRegistered : kMlrStateToRegister); + addrEntry.SetMlrState(isMlrRegistered ? kMlrStateRegistered : kMlrStateToRegister, aChild); } exit: @@ -253,17 +260,22 @@ void MlrManager::SendMlr(void) continue; } - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + if (addresses.IsFull()) { break; } - if (child.GetAddressMlrState(address) == kMlrStateToRegister) + if (addrEntry.GetMlrState(child) == kMlrStateToRegister) { - addresses.AddUnique(address); - child.SetAddressMlrState(address, kMlrStateRegistering); + addresses.AddUnique(addrEntry); + addrEntry.SetMlrState(kMlrStateRegistering, child); } } } @@ -514,11 +526,16 @@ void MlrManager::SetMulticastAddressMlrState(MlrState aFromState, MlrState aToSt #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - if (child.GetAddressMlrState(address) == aFromState) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) { - child.SetAddressMlrState(address, aToState); + continue; + } + + if (addrEntry.GetMlrState(child) == aFromState) + { + addrEntry.SetMlrState(aToState, child); } } } @@ -546,13 +563,18 @@ void MlrManager::FinishMlr(bool aSuccess, const AddressArray &aFailedAddresses) #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - if (child.GetAddressMlrState(address) == kMlrStateRegistering) + if (!addrEntry.IsMulticastLargerThanRealmLocal()) { - bool success = aSuccess || !aFailedAddresses.IsEmptyOrContains(address); + continue; + } - child.SetAddressMlrState(address, success ? kMlrStateRegistered : kMlrStateToRegister); + if (addrEntry.GetMlrState(child) == kMlrStateRegistering) + { + bool success = aSuccess || !aFailedAddresses.IsEmptyOrContains(addrEntry); + + addrEntry.SetMlrState(success ? kMlrStateRegistered : kMlrStateToRegister, child); } } } @@ -648,11 +670,16 @@ void MlrManager::LogMulticastAddresses(void) #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - for (Child &child : Get().Iterate(Child::kInStateValid)) + for (const Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - LogDebg("%-32s%c %04x", address.ToString().AsCString(), "-rR"[child.GetAddressMlrState(address)], + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + LogDebg("%-32s%c %04x", addrEntry.ToString().AsCString(), "-rR"[addrEntry.GetMlrState(child)], child.GetRloc16()); } } @@ -709,11 +736,16 @@ void MlrManager::CheckInvariants(void) const } #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - for (Child &child : Get().Iterate(Child::kInStateValid)) + for (const Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Ip6::Address &address : child.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) + for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) { - registeringNum += (child.GetAddressMlrState(address) == kMlrStateRegistering); + if (!addrEntry.IsMulticastLargerThanRealmLocal()) + { + continue; + } + + registeringNum += (addrEntry.GetMlrState(child) == kMlrStateRegistering); } } #endif diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index af92d417a..6e168c290 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -750,14 +750,18 @@ exit: Error Server::AppendChildIp6AddressListTlv(Coap::Message &aAnswer, const Child &aChild) { Error error = kErrorNone; - uint16_t numIp6Addr = 0; + uint16_t numIp6Addr = aChild.GetIp6Addresses().GetLength(); ChildIp6AddressListTlvValue tlvValue; + Ip6::Address mlEid; - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + if (aChild.GetMeshLocalIp6Address(mlEid) == kErrorNone) { - OT_UNUSED_VARIABLE(address); numIp6Addr++; } + else + { + mlEid.Clear(); + } VerifyOrExit(numIp6Addr > 0); @@ -782,7 +786,12 @@ Error Server::AppendChildIp6AddressListTlv(Coap::Message &aAnswer, const Child & SuccessOrExit(error = aAnswer.Append(tlvValue)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + if (!mlEid.IsUnspecified()) + { + SuccessOrExit(error = aAnswer.Append(mlEid)); + } + + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { SuccessOrExit(error = aAnswer.Append(address)); } diff --git a/tests/unit/test_child.cpp b/tests/unit/test_child.cpp index feec4b573..560fc9a9f 100644 --- a/tests/unit/test_child.cpp +++ b/tests/unit/test_child.cpp @@ -57,7 +57,7 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co memset(addressObserved, 0, sizeof(addressObserved)); - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) + for (const Ip6::Address &address : aChild.GetIp6Addresses()) { bool addressIsInList = false; @@ -78,14 +78,16 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co { Ip6::Address address; - VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); - if (sInstance->Get().IsMeshLocalAddress(aAddressList[index])) { SuccessOrQuit(aChild.GetMeshLocalIp6Address(address)); VerifyOrQuit(address == aAddressList[index], "GetMeshLocalIp6Address() did not return expected address"); hasMeshLocal = true; } + else + { + VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); + } } if (!hasMeshLocal) @@ -95,95 +97,6 @@ void VerifyChildIp6Addresses(const Child &aChild, uint8_t aAddressListLength, co VerifyOrQuit(aChild.GetMeshLocalIp6Address(address) == kErrorNotFound, "Child::GetMeshLocalIp6Address() returned an address not in the expected list"); } - - // Iterate over unicast and multicast addresses separately. - - memset(addressObserved, 0, sizeof(addressObserved)); - - for (Ip6::Address::TypeFilter filter : filters) - { - for (const Ip6::Address &address : aChild.IterateIp6Addresses(filter)) - { - bool addressIsInList = false; - - switch (filter) - { - case Ip6::Address::kTypeMulticast: - VerifyOrQuit(address.IsMulticast(), "Address::TypeFilter failed"); - break; - - case Ip6::Address::kTypeUnicast: - VerifyOrQuit(!address.IsMulticast(), "Address::TypeFilter failed"); - break; - - default: - break; - } - - VerifyOrQuit(address.MatchesFilter(filter)); - - for (uint8_t index = 0; index < aAddressListLength; index++) - { - if (address == aAddressList[index]) - { - VerifyOrQuit(addressObserved[index] == false, - "Child::IterateIp6Addresses() returned duplicate addr"); - addressObserved[index] = true; - addressIsInList = true; - break; - } - } - - VerifyOrQuit(addressIsInList, "Child::IterateIp6Addresses() returned an address not in the expected list"); - } - } - - for (uint8_t index = 0; index < aAddressListLength; index++) - { - VerifyOrQuit(addressObserved[index], "Child::IterateIp6Addresses() missed an entry from the expected list"); - } - - // Verify behavior of `Child::AddressIterator - { - Child::AddressIterator iter1(aChild); - Child::AddressIterator iter2(aChild); - Child::AddressIterator::Index iterIndex; - - for (const Ip6::Address &address : aChild.IterateIp6Addresses()) - { - VerifyOrQuit(iter1 == iter2); - VerifyOrQuit(!iter1.IsDone()); - VerifyOrQuit(*iter1.GetAddress() == address); - VerifyOrQuit(*iter1.GetAddress() == *iter2.GetAddress()); - - iterIndex = iter1.GetAsIndex(); - VerifyOrQuit(iter2.GetAsIndex() == iterIndex); - - { - Child::AddressIterator iter3(aChild, iterIndex); - VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed"); - - iter3++; - VerifyOrQuit(iter3 != iter1, "AddressIterator(iterIndex) failed"); - } - - iter1++; - VerifyOrQuit(iter1 != iter2); - iter2++; - } - - VerifyOrQuit(iter1.IsDone()); - VerifyOrQuit(iter2.IsDone()); - VerifyOrQuit(iter1 == iter2); - - iterIndex = iter1.GetAsIndex(); - VerifyOrQuit(iter2.GetAsIndex() == iterIndex); - - { - Child::AddressIterator iter3(aChild, iterIndex); - VerifyOrQuit(iter3 == iter1, "AddressIterator(iterIndex) failed"); - } - } } void TestChildIp6Address(void)