[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.
This commit is contained in:
Abtin Keshavarzian
2024-06-26 11:12:02 -04:00
committed by GitHub
parent c8681ff8e4
commit 21b5764686
8 changed files with 241 additions and 404 deletions
+1 -9
View File
@@ -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;
+69 -72
View File
@@ -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<Ip6AddressArray::IndexType>(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<Ip6AddressArray::IndexType>(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<const Ip6AddrEntry &>(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<Mle::MleRouter>().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
+86 -195
View File
@@ -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<AddressIterator>
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<Ip6AddrEntry, kNumIp6Addresses> 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<kNumIp6Addresses> ChildIp6AddressMask;
typedef Array<Ip6::Address, kNumIp6Addresses> 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<kNumIp6Addresses> 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
+5 -6
View File
@@ -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<NetworkData::Leader>().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));
}
}
+8 -4
View File
@@ -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));
}
}
}
+54 -22
View File
@@ -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<ChildTable>().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<ChildTable>().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<ChildTable>().Iterate(Child::kInStateValid))
for (const Child &child : Get<ChildTable>().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<ChildTable>().Iterate(Child::kInStateValid))
for (const Child &child : Get<ChildTable>().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
+13 -4
View File
@@ -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));
}
+5 -92
View File
@@ -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<Mle::MleRouter>().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)