[child-table] introducing ChildTable class (#2642)

This commit introduces a new class `ChildTable` as part of OpenThread
core. This class provides methods for iterating through the child
table and searching for a specific child (based on short/extended
address and/or child state). This commit also adds a unit test for the
newly added `ChildTable class.
This commit is contained in:
Abtin Keshavarzian
2018-04-16 10:18:59 -07:00
committed by Jonathan Hui
parent 96ed7ccd24
commit 8e6be519da
24 changed files with 1295 additions and 508 deletions
+2
View File
@@ -124,6 +124,7 @@
<ClCompile Include="..\..\src\core\net\udp6.cpp" />
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp" />
<ClCompile Include="..\..\src\core\thread\announce_begin_server.cpp" />
<ClCompile Include="..\..\src\core\thread\child_table.cpp" />
<ClCompile Include="..\..\src\core\thread\energy_scan_server.cpp" />
<ClCompile Include="..\..\src\core\thread\data_poll_manager.cpp" />
<ClCompile Include="..\..\src\core\thread\key_manager.cpp" />
@@ -208,6 +209,7 @@
<ClInclude Include="..\..\src\core\net\dhcp6.hpp" />
<ClInclude Include="..\..\src\core\net\dhcp6_client.hpp" />
<ClInclude Include="..\..\src\core\net\dhcp6_server.hpp" />
<ClInclude Include="..\..\src\core\thread\child_table.hpp" />
<ClInclude Include="..\..\src\core\thread\data_poll_manager.hpp" />
<ClInclude Include="..\..\src\core\thread\key_manager.hpp" />
<ClInclude Include="..\..\src\core\thread\link_quality.hpp" />
@@ -204,6 +204,9 @@
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\child_table.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\data_poll_manager.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
@@ -452,6 +455,9 @@
<ClInclude Include="..\..\src\core\thread\announce_begin_server.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\child_table.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\data_poll_manager.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
@@ -132,6 +132,7 @@
<ClCompile Include="..\..\src\core\net\udp6.cpp" />
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp" />
<ClCompile Include="..\..\src\core\thread\announce_begin_server.cpp" />
<ClCompile Include="..\..\src\core\thread\child_table.cpp" />
<ClCompile Include="..\..\src\core\thread\data_poll_manager.cpp" />
<ClCompile Include="..\..\src\core\thread\energy_scan_server.cpp" />
<ClCompile Include="..\..\src\core\thread\key_manager.cpp" />
@@ -241,6 +242,7 @@
<ClInclude Include="..\..\src\core\openthread-core-default-config.h" />
<ClInclude Include="..\..\src\core\thread\address_resolver.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_server.hpp" />
<ClInclude Include="..\..\src\core\thread\child_table.hpp" />
<ClInclude Include="..\..\src\core\thread\data_poll_manager.hpp" />
<ClInclude Include="..\..\src\core\thread\energy_scan_server.hpp" />
<ClInclude Include="..\..\src\core\thread\key_manager.hpp" />
@@ -204,6 +204,9 @@
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\child_table.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\data_poll_manager.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
@@ -449,6 +452,9 @@
<ClInclude Include="..\..\src\core\thread\address_resolver.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\child_table.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\data_poll_manager.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
+2
View File
@@ -172,6 +172,7 @@ SOURCES_COMMON = \
net/udp6.cpp \
thread/address_resolver.cpp \
thread/announce_begin_server.cpp \
thread/child_table.cpp \
thread/data_poll_manager.cpp \
thread/energy_scan_server.cpp \
thread/key_manager.cpp \
@@ -291,6 +292,7 @@ HEADERS_COMMON = \
net/udp6.hpp \
thread/address_resolver.hpp \
thread/announce_begin_server.hpp \
thread/child_table.hpp \
thread/data_poll_manager.hpp \
thread/energy_scan_server.hpp \
thread/key_manager.hpp \
+2 -5
View File
@@ -47,19 +47,16 @@ using namespace ot;
uint8_t otThreadGetMaxAllowedChildren(otInstance *aInstance)
{
uint8_t aNumChildren;
Instance &instance = *static_cast<Instance *>(aInstance);
(void)instance.GetThreadNetif().GetMle().GetChildren(&aNumChildren);
return aNumChildren;
return instance.GetThreadNetif().GetMle().GetChildTable().GetMaxChildrenAllowed();
}
otError otThreadSetMaxAllowedChildren(otInstance *aInstance, uint8_t aMaxChildren)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetMle().SetMaxAllowedChildren(aMaxChildren);
return instance.GetThreadNetif().GetMle().GetChildTable().SetMaxChildrenAllowed(aMaxChildren);
}
bool otThreadIsRouterRoleEnabled(otInstance *aInstance)
+5
View File
@@ -245,6 +245,11 @@ template <> Mle::MleRouter &Instance::Get(void)
return GetThreadNetif().GetMle();
}
template <> ChildTable &Instance::Get(void)
{
return GetThreadNetif().GetMle().GetChildTable();
}
template <> Ip6::Netif &Instance::Get(void)
{
return GetThreadNetif();
+6 -15
View File
@@ -542,8 +542,6 @@ void AddressResolver::HandleAddressError(Coap::Header &aHeader, Message &aMessag
otError error = OT_ERROR_NONE;
ThreadTargetTlv targetTlv;
ThreadMeshLocalEidTlv mlIidTlv;
Child * children;
uint8_t numChildren;
Mac::ExtAddress macAddr;
Ip6::Address destination;
@@ -577,16 +575,14 @@ void AddressResolver::HandleAddressError(Coap::Header &aHeader, Message &aMessag
}
}
children = netif.GetMle().GetChildren(&numChildren);
memcpy(&macAddr, mlIidTlv.GetIid(), sizeof(macAddr));
macAddr.m8[0] ^= 0x2;
for (int i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
Child &child = children[i];
Child &child = *iter.GetChild();
if (child.GetState() != Neighbor::kStateValid || child.IsFullThreadDevice())
if (child.IsFullThreadDevice())
{
continue;
}
@@ -635,8 +631,6 @@ void AddressResolver::HandleAddressQuery(Coap::Header &aHeader, Message &aMessag
ThreadTargetTlv targetTlv;
ThreadMeshLocalEidTlv mlIidTlv;
ThreadLastTransactionTimeTlv lastTransactionTimeTlv;
Child * children;
uint8_t numChildren;
char stringBuffer[Ip6::Address::kIp6AddressStringSize];
VerifyOrExit(aHeader.GetType() == OT_COAP_TYPE_NON_CONFIRMABLE && aHeader.GetCode() == OT_COAP_CODE_POST);
@@ -659,14 +653,11 @@ void AddressResolver::HandleAddressQuery(Coap::Header &aHeader, Message &aMessag
ExitNow();
}
children = netif.GetMle().GetChildren(&numChildren);
for (int i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
Child &child = children[i];
Child &child = *iter.GetChild();
if (child.GetState() != Neighbor::kStateValid || child.IsFullThreadDevice() ||
child.GetLinkFailures() >= Mle::kFailedChildTransmissions)
if (child.IsFullThreadDevice() || child.GetLinkFailures() >= Mle::kFailedChildTransmissions)
{
continue;
}
+278
View File
@@ -0,0 +1,278 @@
/*
* Copyright (c) 2016-2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for Thread child table.
*/
#include "child_table.hpp"
#include "common/code_utils.hpp"
#include "common/instance.hpp"
namespace ot {
#if OPENTHREAD_FTD
ChildTable::Iterator::Iterator(Instance &aInstance, StateFilter aFilter)
: InstanceLocator(aInstance)
, mFilter(aFilter)
, mStart(NULL)
, mChild(NULL)
{
Reset();
}
ChildTable::Iterator::Iterator(Instance &aInstance, StateFilter aFilter, Child *aStartingChild)
: InstanceLocator(aInstance)
, mFilter(aFilter)
, mStart(aStartingChild)
, mChild(NULL)
{
Reset();
}
void ChildTable::Iterator::Reset(void)
{
ChildTable &childTable = GetInstance().Get<ChildTable>();
if (mStart == NULL)
{
mStart = &childTable.mChildren[0];
}
mChild = mStart;
if (!MatchesFilter(*mChild, mFilter))
{
Advance();
}
}
void ChildTable::Iterator::Advance(void)
{
ChildTable &childTable = GetInstance().Get<ChildTable>();
Child * listStart = &childTable.mChildren[0];
Child * listEnd = &childTable.mChildren[childTable.mMaxChildrenAllowed];
VerifyOrExit(mChild != NULL);
do
{
mChild++;
if (mChild >= listEnd)
{
mChild = listStart;
}
VerifyOrExit(mChild != mStart, mChild = NULL);
} while (!MatchesFilter(*mChild, mFilter));
exit:
return;
}
ChildTable::ChildTable(Instance &aInstance)
: InstanceLocator(aInstance)
, mMaxChildrenAllowed(kMaxChildren)
{
memset(mChildren, 0, sizeof(mChildren));
}
Child *ChildTable::GetChildAtIndex(uint8_t aChildIndex)
{
Child *child = NULL;
VerifyOrExit(aChildIndex < mMaxChildrenAllowed);
child = &mChildren[aChildIndex];
exit:
return child;
}
Child *ChildTable::GetNewChild(void)
{
Child *child = mChildren;
for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
{
if (child->GetState() == Child::kStateInvalid)
{
memset(child, 0, sizeof(Child));
ExitNow();
}
}
child = NULL;
exit:
return child;
}
Child *ChildTable::FindChild(uint16_t aRloc16, StateFilter aFilter)
{
Child *child = mChildren;
for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
{
if (MatchesFilter(*child, aFilter) && (child->GetRloc16() == aRloc16))
{
ExitNow();
}
}
child = NULL;
exit:
return child;
}
Child *ChildTable::FindChild(const Mac::ExtAddress &aAddress, StateFilter aFilter)
{
Child *child = mChildren;
for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
{
if (MatchesFilter(*child, aFilter) && (child->GetExtAddress() == aAddress))
{
ExitNow();
}
}
child = NULL;
exit:
return child;
}
Child *ChildTable::FindChild(const Mac::Address &aAddress, StateFilter aFilter)
{
Child *child = NULL;
switch (aAddress.GetType())
{
case Mac::Address::kTypeShort:
child = FindChild(aAddress.GetShort(), aFilter);
break;
case Mac::Address::kTypeExtended:
child = FindChild(aAddress.GetExtended(), aFilter);
break;
default:
break;
}
return child;
}
bool ChildTable::HasChildren(StateFilter aFilter) const
{
bool rval = false;
const Child *child = mChildren;
for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
{
if (MatchesFilter(*child, aFilter))
{
ExitNow(rval = true);
}
}
exit:
return rval;
}
uint8_t ChildTable::GetNumChildren(StateFilter aFilter) const
{
uint8_t numChildren = 0;
const Child *child = mChildren;
for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
{
if (MatchesFilter(*child, aFilter))
{
numChildren++;
}
}
return numChildren;
}
otError ChildTable::SetMaxChildrenAllowed(uint8_t aMaxChildren)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(aMaxChildren > 0 && aMaxChildren <= kMaxChildren, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(!HasChildren(kInStateAnyExceptInvalid), error = OT_ERROR_INVALID_STATE);
mMaxChildrenAllowed = aMaxChildren;
exit:
return error;
}
bool ChildTable::MatchesFilter(const Child &aChild, StateFilter aFilter)
{
bool rval = false;
switch (aFilter)
{
case kInStateValid:
rval = (aChild.GetState() == Child::kStateValid);
break;
case kInStateValidOrRestoring:
rval = aChild.IsStateValidOrRestoring();
break;
case kInStateChildIdRequest:
rval = (aChild.GetState() == Child::kStateChildIdRequest);
break;
case kInStateValidOrAttaching:
rval = aChild.IsStateValidOrAttaching();
break;
case kInStateAnyExceptInvalid:
rval = (aChild.GetState() != Child::kStateInvalid);
break;
case kInStateAnyExceptValidOrRestoing:
rval = !aChild.IsStateValidOrRestoring();
break;
}
return rval;
}
#endif // OPENTHREAD_FTD
} // namespace ot
+339
View File
@@ -0,0 +1,339 @@
/*
* Copyright (c) 2016-2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for Thread child table.
*/
#ifndef CHILD_TABLE_HPP_
#define CHILD_TABLE_HPP_
#include "openthread-core-config.h"
#include "common/locator.hpp"
#include "thread/topology.hpp"
namespace ot {
#if OPENTHREAD_FTD
/**
* This class represents the Thread child table.
*
*/
class ChildTable : public InstanceLocator
{
public:
/**
* This enumeration defines child state filters used for finding a child or iterating through the child table.
*
* Each filter definition accepts a subset of `Child:State` values.
*
*/
enum StateFilter
{
kInStateValid, ///< Accept child only in `Child::kStateValid`.
kInStateValidOrRestoring, ///< Accept child with `Child::IsStateValidOrRestoring()` being `true`.
kInStateChildIdRequest, ///< Accept child only in `Child:kStateChildIdRequest`.
kInStateValidOrAttaching, ///< Accept child with `Child::IsStateValidOrAttaching()` being `true`.
kInStateAnyExceptInvalid, ///< Accept child in any state except `Child:kStateInvalid`.
kInStateAnyExceptValidOrRestoing, ///< Accept child in any state except `Child::IsStateValidOrRestoring()`.
};
/**
* This class represents an iterator for iterating through the child entries in the child table.
*
*/
class Iterator : public InstanceLocator
{
public:
/**
* This constructor initializes an `Iterator` instance to start from beginning of the child table.
*
* @param[in] aInstance A reference to the OpenThread instance.
* @param[in] aFilter A child state filter.
*
*/
Iterator(Instance &aInstance, StateFilter aFilter);
/**
* This constructor initializes an `Iterator` instance to start from a given child.
*
* This constructor allows the iterator to start from a given `Child` entry. The iterator will start from the
* given child and will go through all entries in the child table (matching the filter) till it gets back to
* the starting `Child` entry.
*
* If the given starting `Child` pointer is `NULL`, then the iterator starts from beginning of the child table.
*
* @param[in] aInstance A reference to the OpenThread instance.
* @param[in] aFilter A child state filter.
* @param[in] aStartingChild A pointer to a child. If non-NULL, the iterator starts from the given entry.
*
*/
Iterator(Instance &aInstance, StateFilter aFilter, Child *aStartingChild);
/**
* This method resets the iterator to start over.
*
*/
void Reset(void);
/**
* This method indicates whether there are no more `Child` entries in the list (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 (mChild == NULL); }
/**
* This method advances the iterator.
*
* The iterator is moved to point to the next `Child` entry matching the given state filter in the constructor.
* If there are no more `Child` entries matching the given filter, the iterator becomes empty (i.e.,
* `GetChild()` returns `NULL` and `IsDone()` returns `true`.
*
*/
void Advance(void);
/**
* This method gets the `Child` entry to which the iterator is currently pointing.
*
* @returns A pointer to the `Child` entry, or `NULL` if the iterator is done and/or empty.
*
*/
Child *GetChild(void) { return mChild; }
private:
StateFilter mFilter;
Child * mStart;
Child * mChild;
};
/**
* This constructor initializes a `ChildTable` instance.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit ChildTable(Instance &aIntsance);
/**
* This method clears the child table.
*
*/
void Clear(void) { memset(mChildren, 0, sizeof(mChildren)); }
/**
* This method returns the child table index for a given `Child` instance.
*
* @param[in] aChild A reference to a `Child`
*
* @returns The index corresponding to @p aChild.
*
*/
uint8_t GetChildIndex(const Child &aChild) const { return static_cast<uint8_t>(&aChild - mChildren); }
/**
* This method returns a pointer to a `Child` entry at a given index, or `NULL` if the index is out of bounds,
* i.e., index is larger or equal to maximum number of children allowed (@sa GetMaxChildrenAllowed()).
*
* @param[in] aChildIndex A child index.
*
* @returns A pointer to the `Child` corresponding to the given index, or `NULL` if the index is out of bounds.
*
*/
Child *GetChildAtIndex(uint8_t aChildIndex);
/**
* This method gets a new/unused `Child` entry from the child table.
*
* @note The returned child entry will be cleared (`memset` to zero).
*
* @returns A pointer to a new `Child` entry, or `NULL` if all `Child` entries are in use.
*
*/
Child *GetNewChild(void);
/**
* This method searches the child table for a `Child` with a given RLOC16 also matching a given state filter.
*
* @param[in] aRloc16 A RLCO16 address.
* @param[in] aFilter A child state filter.
*
* @returns A pointer to the `Child` entry if one is found, or `NULL` otherwise.
*
*/
Child *FindChild(uint16_t aRloc16, StateFilter aFilter);
/**
* This method searches the child table for a `Child` with a given extended address also matching a given state
* filter.
*
* @param[in] aAddress A reference to an extended address.
* @param[in] aFilter A child state filter.
*
* @returns A pointer to the `Child` entry if one is found, or `NULL` otherwise.
*
*/
Child *FindChild(const Mac::ExtAddress &aAddress, StateFilter aFilter);
/**
* This method searches the child table for a `Child` with a given address also matching a given state filter.
*
* @param[in] aAddress A reference to a MAC address.
* @param[in] aFilter A child state filter.
*
* @returns A pointer to the `Child` entry if one is found, or `NULL` otherwise.
*
*/
Child *FindChild(const Mac::Address &aAddress, StateFilter aFilter);
/**
* This method indicates whether the child table contains any child matching a given state filter.
*
* @param[in] aFilter A child state filter.
*
* @returns TRUE if the table contains at least one child table matching the given filter, FALSE otherwise.
*
*/
bool HasChildren(StateFilter aFilter) const;
/**
* This method returns the number of children in the child table matching a given state filter.
*
* @param[in] aFilter A child state filter.
*
* @returns Number of children matching the given state filer.
*
*/
uint8_t GetNumChildren(StateFilter aFilter) const;
/**
* This method returns the maximum number of children that can be supported (build-time constant).
*
* @note Number of children allowed (from `GetMaxChildrenAllowed()`) can be less than maximum number of supported
* children.
*
* @returns The maximum number of children supported
*
*/
uint8_t GetMaxChildren(void) const { return kMaxChildren; }
/**
* This method get the maximum number of children allowed.
*
* @returns The maximum number of children allowed.
*
*/
uint8_t GetMaxChildrenAllowed(void) const { return mMaxChildrenAllowed; }
/**
* This method sets the maximum number of children allowed.
*
* The number of children allowed must be at least one and at most same as maximum supported children (@sa
* GetMaxChildren()). It can be changed only if the child table is empty.
*
* @param[in] aMaxChildren Maximum number of children allowed.
*
* @retval OT_ERROR_NONE The number of allowed children changed successfully.
* @retval OT_ERROR_INVALID_ARGS If @p aMaxChildren is not in the range [1, Max supported children].
* @retval OT_ERROR_INVALID_STATE The child table is not empty.
*
*/
otError SetMaxChildrenAllowed(uint8_t aMaxChildren);
private:
enum
{
kMaxChildren = OPENTHREAD_CONFIG_MAX_CHILDREN,
};
static bool MatchesFilter(const Child &aChild, StateFilter aFilter);
uint8_t mMaxChildrenAllowed;
Child mChildren[kMaxChildren];
};
#endif // OPENTHREAD_FTD
#if OPENTHREAD_MTD
class ChildTable : public InstanceLocator
{
public:
enum StateFilter
{
kInStateValid,
kInStateValidOrRestoring,
kInStateChildIdRequest,
kInStateValidOrAttaching,
kInStateAnyExceptInvalid,
};
class Iterator
{
public:
Iterator(Instance &, StateFilter) {}
Iterator(Instance &, StateFilter, Child *) {}
void Reset(void) {}
bool IsDone(void) const { return true; }
void Advance(void) {}
Child *GetChild(void) { return NULL; }
};
explicit ChildTable(Instance &aIntsance)
: InstanceLocator(aIntsance)
{
}
void Clear(void) {}
uint8_t GetChildIndex(const Child &) const { return 0; }
Child * GetChildAtIndex(uint8_t) { return NULL; }
Child *GetNewChild(void) { return NULL; }
Child *FindChild(uint16_t, StateFilter) { return NULL; }
Child *FindChild(const Mac::ExtAddress &, StateFilter) { return NULL; }
Child *FindChild(const Mac::Address &, StateFilter) { return NULL; }
bool HasChildren(StateFilter) const { return false; }
uint8_t GetNumChildren(StateFilter) const { return 0; }
uint8_t GetMaxChildren(void) const { return 0; }
uint8_t GetMaxChildrenAllowed(void) const { return 0; }
otError SetMaxChildrenAllowed(uint8_t) { return OT_ERROR_INVALID_STATE; }
};
#endif // OPENTHREAD_MTD
} // namespace ot
#endif // CHILD_TABLE_HPP_
+4 -7
View File
@@ -121,7 +121,6 @@ otError KeyManager::SetMasterKey(const otMasterKey &aKey)
{
otError error = OT_ERROR_NONE;
Router *routers;
Child * children;
uint8_t num;
VerifyOrExit(memcmp(&mMasterKey, &aKey, sizeof(mMasterKey)) != 0);
@@ -147,13 +146,11 @@ otError KeyManager::SetMasterKey(const otMasterKey &aKey)
}
// reset child frame counters
children = GetNetif().GetMle().GetChildren(&num);
for (uint8_t i = 0; i < num; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptInvalid); !iter.IsDone(); iter.Advance())
{
children[i].SetKeySequence(0);
children[i].SetLinkFrameCounter(0);
children[i].SetMleFrameCounter(0);
iter.GetChild()->SetKeySequence(0);
iter.GetChild()->SetLinkFrameCounter(0);
iter.GetChild()->SetMleFrameCounter(0);
}
GetNotifier().SetFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER | OT_CHANGED_MASTER_KEY);
+6 -10
View File
@@ -82,7 +82,7 @@ MeshForwarder::MeshForwarder(Instance &aInstance)
, mSendMessageFrameCounter(0)
, mSendMessageKeyId(0)
, mSendMessageDataSequenceNumber(0)
, mStartChildIndex(0)
, mIndirectStartingChild(NULL)
#endif
, mDataPollManager(aInstance)
{
@@ -148,14 +148,9 @@ exit:
void MeshForwarder::RemoveMessage(Message &aMessage)
{
Child * children;
uint8_t numChildren;
children = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptInvalid); !iter.IsDone(); iter.Advance())
{
IgnoreReturnValue(RemoveMessageFromSleepyChild(aMessage, children[i]));
IgnoreReturnValue(RemoveMessageFromSleepyChild(aMessage, *iter.GetChild()));
}
if (mSendMessage == &aMessage)
@@ -569,8 +564,9 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
// The case where the current message requires fragmentation is
// already checked and handled in `SendFragment()` method.
if (((child = netif.GetMle().GetChild(macDest)) != NULL) && !child->IsRxOnWhenIdle() &&
(child->GetIndirectMessageCount() > 1))
child = netif.GetMle().GetChildTable().FindChild(macDest, ChildTable::kInStateValidOrRestoring);
if ((child != NULL) && !child->IsRxOnWhenIdle() && (child->GetIndirectMessageCount() > 1))
{
aFrame.SetFramePending(true);
}
+1 -1
View File
@@ -378,7 +378,7 @@ private:
uint32_t mSendMessageFrameCounter;
uint8_t mSendMessageKeyId;
uint8_t mSendMessageDataSequenceNumber;
uint8_t mStartChildIndex;
Child * mIndirectStartingChild;
#endif
DataPollManager mDataPollManager;
+52 -71
View File
@@ -44,13 +44,11 @@ namespace ot {
otError MeshForwarder::SendMessage(Message &aMessage)
{
ThreadNetif &netif = GetNetif();
otError error = OT_ERROR_NONE;
ThreadNetif &netif = GetNetif();
ChildTable & childTable = netif.GetMle().GetChildTable();
otError error = OT_ERROR_NONE;
Neighbor * neighbor;
uint8_t numChildren;
Child * child;
switch (aMessage.GetType())
{
case Message::kTypeIp6:
@@ -73,30 +71,34 @@ otError MeshForwarder::SendMessage(Message &aMessage)
if (aMessage.GetSubType() != Message::kSubTypeMplRetransmission)
{
child = netif.GetMle().GetChildren(&numChildren);
if (ip6Header.GetDestination() == netif.GetMle().GetLinkLocalAllThreadNodesAddress() ||
ip6Header.GetDestination() == netif.GetMle().GetRealmLocalAllThreadNodesAddress())
{
// destined for all sleepy children
for (uint8_t i = 0; i < numChildren; i++, child++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone();
iter.Advance())
{
if (child->IsStateValidOrRestoring() && !child->IsRxOnWhenIdle())
Child &child = *iter.GetChild();
if (!child.IsRxOnWhenIdle())
{
aMessage.SetChildMask(i);
mSourceMatchController.IncrementMessageCount(*child);
aMessage.SetChildMask(childTable.GetChildIndex(child));
mSourceMatchController.IncrementMessageCount(child);
}
}
}
else
{
// destined for some sleepy children which subscribed the multicast address.
for (uint8_t i = 0; i < numChildren; i++, child++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone();
iter.Advance())
{
if (netif.GetMle().IsSleepyChildSubscribed(ip6Header.GetDestination(), *child))
Child &child = *iter.GetChild();
if (netif.GetMle().IsSleepyChildSubscribed(ip6Header.GetDestination(), child))
{
aMessage.SetChildMask(i);
mSourceMatchController.IncrementMessageCount(*child);
aMessage.SetChildMask(childTable.GetChildIndex(child));
mSourceMatchController.IncrementMessageCount(child);
}
}
}
@@ -106,9 +108,9 @@ otError MeshForwarder::SendMessage(Message &aMessage)
!neighbor->IsRxOnWhenIdle() && !aMessage.GetDirectTransmission())
{
// destined for a sleepy child
child = static_cast<Child *>(neighbor);
aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
mSourceMatchController.IncrementMessageCount(*child);
Child &child = *static_cast<Child *>(neighbor);
aMessage.SetChildMask(childTable.GetChildIndex(child));
mSourceMatchController.IncrementMessageCount(child);
}
else
{
@@ -120,13 +122,15 @@ otError MeshForwarder::SendMessage(Message &aMessage)
}
case Message::kTypeSupervision:
child = netif.GetChildSupervisor().GetDestination(aMessage);
{
Child *child = netif.GetChildSupervisor().GetDestination(aMessage);
VerifyOrExit(child != NULL, error = OT_ERROR_DROP);
VerifyOrExit(!child->IsRxOnWhenIdle(), error = OT_ERROR_DROP);
aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
aMessage.SetChildMask(childTable.GetChildIndex(*child));
mSourceMatchController.IncrementMessageCount(*child);
break;
}
default:
aMessage.SetDirectTransmission();
@@ -192,7 +196,7 @@ void MeshForwarder::ClearChildIndirectMessages(Child &aChild)
{
nextMessage = message->GetNext();
message->ClearChildMask(GetNetif().GetMle().GetChildIndex(aChild));
message->ClearChildMask(GetNetif().GetMle().GetChildTable().GetChildIndex(aChild));
if (!message->IsChildPending() && !message->GetDirectTransmission())
{
@@ -215,21 +219,15 @@ exit:
void MeshForwarder::UpdateIndirectMessages(void)
{
Child * children;
uint8_t numChildren;
children = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptValidOrRestoing); !iter.IsDone();
iter.Advance())
{
Child *child = &children[i];
if (child->IsStateValidOrRestoring() || (child->GetIndirectMessageCount() == 0))
if (iter.GetChild()->GetIndirectMessageCount() == 0)
{
continue;
}
ClearChildIndirectMessages(*child);
ClearChildIndirectMessages(*iter.GetChild());
}
}
@@ -255,7 +253,7 @@ exit:
otError MeshForwarder::RemoveMessageFromSleepyChild(Message &aMessage, Child &aChild)
{
otError error = OT_ERROR_NONE;
uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
uint8_t childIndex = GetNetif().GetMle().GetChildTable().GetChildIndex(aChild);
VerifyOrExit(aMessage.GetChildMask(childIndex) == true, error = OT_ERROR_NOT_FOUND);
@@ -350,14 +348,10 @@ void MeshForwarder::RemoveDataResponseMessages(void)
if (!(ip6Header.GetDestination().IsMulticast()))
{
Child * children;
uint8_t numChildren;
children = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptInvalid); !iter.IsDone();
iter.Advance())
{
IgnoreReturnValue(RemoveMessageFromSleepyChild(*message, children[i]));
IgnoreReturnValue(RemoveMessageFromSleepyChild(*message, *iter.GetChild()));
}
}
@@ -376,32 +370,15 @@ otError MeshForwarder::GetIndirectTransmission(void)
{
otError error = OT_ERROR_NOT_FOUND;
ThreadNetif &netif = GetNetif();
uint8_t numChildren;
uint8_t childIndex;
uint8_t nextIndex;
Child * children;
UpdateIndirectMessages();
children = netif.GetMle().GetChildren(&numChildren);
if (mStartChildIndex >= numChildren)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring, mIndirectStartingChild);
!iter.IsDone(); iter.Advance())
{
mStartChildIndex = 0;
}
Child &child = *iter.GetChild();
childIndex = mStartChildIndex;
for (uint8_t iterations = numChildren; iterations > 0; iterations--, childIndex = nextIndex)
{
Child &child = children[childIndex];
if ((nextIndex = childIndex + 1) == numChildren)
{
nextIndex = 0;
}
if (!child.IsStateValidOrRestoring() || !child.IsDataRequestPending())
if (!child.IsDataRequestPending())
{
continue;
}
@@ -434,9 +411,9 @@ otError MeshForwarder::GetIndirectTransmission(void)
child.GetMacAddress(mMacDest);
}
// Record current child index, and move it to next index after this indirect transmission has completed.
// Remember the current child and move it to next one in the list after the indirect transmission has completed.
mStartChildIndex = childIndex;
mIndirectStartingChild = &child;
netif.GetMac().SendFrameRequest(mMacSender);
ExitNow(error = OT_ERROR_NONE);
@@ -450,7 +427,7 @@ Message *MeshForwarder::GetIndirectTransmission(Child &aChild)
{
Message *message = NULL;
Message *next;
uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
uint8_t childIndex = GetNetif().GetMle().GetChildTable().GetChildIndex(aChild);
for (message = mSendQueue.GetHead(); message; message = next)
{
@@ -569,7 +546,9 @@ void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const otTh
VerifyOrExit(netif.GetMle().GetRole() != OT_DEVICE_ROLE_DETACHED);
VerifyOrExit((child = netif.GetMle().GetChild(aMacSource)) != NULL);
child = netif.GetMle().GetChildTable().FindChild(aMacSource, ChildTable::kInStateValidOrRestoring);
VerifyOrExit(child != NULL);
child->SetLastHeard(TimerMilli::GetNow());
child->ResetLinkFailures();
indirectMsgCount = child->GetIndirectMessageCount();
@@ -593,7 +572,7 @@ void MeshForwarder::HandleSentFrameToChild(const Mac::Frame &aFrame, otError aEr
ThreadNetif &netif = GetNetif();
Child * child;
child = netif.GetMle().GetChild(aMacDest);
child = netif.GetMle().GetChildTable().FindChild(aMacDest, ChildTable::kInStateValidOrRestoring);
VerifyOrExit(child != NULL);
child->SetDataRequestPending(false);
@@ -604,12 +583,14 @@ void MeshForwarder::HandleSentFrameToChild(const Mac::Frame &aFrame, otError aEr
{
// To ensure fairness in handling of data requests from sleepy
// children, once a message is completed for indirect transmission to a
// child (no matter succeed or failed), the `mStartChildIndex` is updated to
// the next index after the current child. Subsequent call to
// `ScheduleTransmissionTask()` will begin the iteration through
// the children list from this index.
// child (on both success or failure), the `mIndirectStartingChild` is
// updated to the next `Child` entry after the current one. Subsequent
// call to `ScheduleTransmissionTask()` will begin the iteration
// through the children list from this child.
mStartChildIndex++;
ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring, mIndirectStartingChild);
iter.Advance();
mIndirectStartingChild = iter.GetChild();
if (aError == OT_ERROR_NONE)
{
@@ -685,7 +666,7 @@ void MeshForwarder::HandleSentFrameToChild(const Mac::Frame &aFrame, otError aEr
mSourceMatchController.SetSrcMatchAsShort(*child, true);
}
childIndex = netif.GetMle().GetChildIndex(*child);
childIndex = netif.GetMle().GetChildTable().GetChildIndex(*child);
if (mSendMessage->GetChildMask(childIndex))
{
+89 -256
View File
@@ -64,7 +64,7 @@ MleRouter::MleRouter(Instance &aInstance)
, mAddressRelease(OT_URI_PATH_ADDRESS_RELEASE, &MleRouter::HandleAddressRelease, this)
, mRouterIdSequence(0)
, mRouterIdSequenceLastUpdated(0)
, mMaxChildrenAllowed(kMaxChildren)
, mChildTable(aInstance)
, mChildTableChangedCallback(NULL)
, mChallengeTimeout(0)
, mNextChildId(kMaxChildId)
@@ -82,7 +82,6 @@ MleRouter::MleRouter(Instance &aInstance)
{
mDeviceMode |= ModeTlv::kModeFFD | ModeTlv::kModeFullNetworkData;
memset(mChildren, 0, sizeof(mChildren));
memset(mRouters, 0, sizeof(mRouters));
SetRouterId(kInvalidRouterId);
@@ -448,11 +447,11 @@ otError MleRouter::SetStateRouter(uint16_t aRloc16)
}
// remove children that do not have matching RLOC16
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
if (mChildren[i].IsStateValidOrRestoring() && GetRouterId(mChildren[i].GetRloc16()) != mRouterId)
if (GetRouterId(iter.GetChild()->GetRloc16()) != mRouterId)
{
RemoveNeighbor(mChildren[i]);
RemoveNeighbor(*iter.GetChild());
}
}
@@ -495,11 +494,11 @@ otError MleRouter::SetStateLeader(uint16_t aRloc16)
netif.GetAddressResolver().Clear();
// remove children that do not have matching RLOC16
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
if (mChildren[i].IsStateValidOrRestoring() && GetRouterId(mChildren[i].GetRloc16()) != mRouterId)
if (GetRouterId(iter.GetChild()->GetRloc16()) != mRouterId)
{
RemoveNeighbor(mChildren[i]);
RemoveNeighbor(*iter.GetChild());
}
}
@@ -1104,51 +1103,6 @@ exit:
return error;
}
Child *MleRouter::NewChild(void)
{
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() == Neighbor::kStateInvalid)
{
return &mChildren[i];
}
}
return NULL;
}
Child *MleRouter::FindChild(uint16_t aChildId)
{
Child *rval = NULL;
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() != Neighbor::kStateInvalid && GetChildId(mChildren[i].GetRloc16()) == aChildId)
{
ExitNow(rval = &mChildren[i]);
}
}
exit:
return rval;
}
Child *MleRouter::FindChild(const Mac::ExtAddress &aAddress)
{
Child *rval = NULL;
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() != Neighbor::kStateInvalid && mChildren[i].GetExtAddress() == aAddress)
{
ExitNow(rval = &mChildren[i]);
}
}
exit:
return rval;
}
uint8_t MleRouter::LinkQualityToCost(uint8_t aLinkQuality)
{
switch (aLinkQuality)
@@ -1762,11 +1716,11 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kChallenge, sizeof(challenge), challenge));
VerifyOrExit(challenge.IsValid(), error = OT_ERROR_PARSE);
child = FindChild(macAddr);
child = GetChildTable().FindChild(macAddr, ChildTable::kInStateAnyExceptInvalid);
if (child == NULL)
{
VerifyOrExit((child = NewChild()) != NULL);
VerifyOrExit((child = GetChildTable().GetNewChild()) != NULL);
memset(child, 0, sizeof(*child));
@@ -1897,11 +1851,12 @@ void MleRouter::HandleStateUpdateTimer(void)
}
// update children state
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptInvalid); !iter.IsDone(); iter.Advance())
{
Child & child = *iter.GetChild();
uint32_t timeout = 0;
switch (mChildren[i].GetState())
switch (child.GetState())
{
case Neighbor::kStateInvalid:
case Neighbor::kStateChildIdRequest:
@@ -1911,7 +1866,7 @@ void MleRouter::HandleStateUpdateTimer(void)
case Neighbor::kStateValid:
case Neighbor::kStateRestored:
case Neighbor::kStateChildUpdateRequest:
timeout = TimerMilli::SecToMsec(mChildren[i].GetTimeout());
timeout = TimerMilli::SecToMsec(child.GetTimeout());
break;
case Neighbor::kStateParentResponse:
@@ -1920,15 +1875,15 @@ void MleRouter::HandleStateUpdateTimer(void)
break;
}
if ((TimerMilli::GetNow() - mChildren[i].GetLastHeard()) >= timeout)
if ((TimerMilli::GetNow() - child.GetLastHeard()) >= timeout)
{
otLogInfoMle(GetInstance(), "Child timeout expired");
RemoveNeighbor(mChildren[i]);
RemoveNeighbor(child);
}
else if ((mRole == OT_DEVICE_ROLE_ROUTER || mRole == OT_DEVICE_ROLE_LEADER) &&
(mChildren[i].GetState() == Neighbor::kStateRestored))
(child.GetState() == Neighbor::kStateRestored))
{
SendChildUpdateRequest(mChildren[i]);
SendChildUpdateRequest(child);
}
}
@@ -2140,16 +2095,15 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse
// table is timed out and then trying to register its globally unique
// IPv6 address as the new child.
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone();
iter.Advance())
{
Child &child = mChildren[i];
if (!child.IsStateValidOrRestoring() || (&child == &aChild))
if (iter.GetChild() == &aChild)
{
continue;
}
IgnoreReturnValue(child.RemoveIp6Address(GetInstance(), address));
IgnoreReturnValue(iter.GetChild()->RemoveIp6Address(GetInstance(), address));
}
}
@@ -2202,7 +2156,8 @@ otError MleRouter::HandleChildIdRequest(const Message & aMessage,
// Find Child
aMessageInfo.GetPeerAddr().ToExtAddress(macAddr);
VerifyOrExit((child = FindChild(macAddr)) != NULL, error = OT_ERROR_ALREADY);
child = GetChildTable().FindChild(macAddr, ChildTable::kInStateAnyExceptInvalid);
VerifyOrExit(child != NULL, error = OT_ERROR_ALREADY);
// Response
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kResponse, sizeof(response), response));
@@ -2364,7 +2319,7 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
// Find Child
aMessageInfo.GetPeerAddr().ToExtAddress(macAddr);
child = FindChild(macAddr);
child = GetChildTable().FindChild(macAddr, ChildTable::kInStateAnyExceptInvalid);
tlvs[tlvslength++] = Tlv::kSourceAddress;
@@ -2471,7 +2426,7 @@ otError MleRouter::HandleChildUpdateResponse(const Message & aMessage,
// Find Child
aMessageInfo.GetPeerAddr().ToExtAddress(macAddr);
child = FindChild(macAddr);
child = GetChildTable().FindChild(macAddr, ChildTable::kInStateAnyExceptInvalid);
if (child == NULL)
{
@@ -2644,12 +2599,12 @@ void MleRouter::SynchronizeChildNetworkData(void)
VerifyOrExit(mRole == OT_DEVICE_ROLE_ROUTER || mRole == OT_DEVICE_ROLE_LEADER);
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
Child & child = mChildren[i];
Child & child = *iter.GetChild();
uint8_t version;
if (child.GetState() != Neighbor::kStateValid || child.IsRxOnWhenIdle())
if (child.IsRxOnWhenIdle())
{
continue;
}
@@ -2907,7 +2862,7 @@ otError MleRouter::SendChildIdResponse(Child &aChild)
{
mNextChildId = kMinChildId;
}
} while (FindChild(mNextChildId) != NULL);
} while (GetChildTable().FindChild(mNextChildId, ChildTable::kInStateAnyExceptInvalid) != NULL);
// allocate Child ID
aChild.SetRloc16(netif.GetMac().GetShortAddress() | mNextChildId);
@@ -2979,7 +2934,7 @@ otError MleRouter::SendChildUpdateRequest(Child &aChild)
if (!aChild.IsRxOnWhenIdle())
{
uint8_t childIndex = netif.GetMle().GetChildIndex(aChild);
uint8_t childIndex = netif.GetMle().GetChildTable().GetChildIndex(aChild);
for (message = netif.GetMeshForwarder().GetSendQueue().GetHead(); message; message = message->GetNext())
{
@@ -3190,64 +3145,6 @@ exit:
return error;
}
Child *MleRouter::GetChild(uint16_t aAddress)
{
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].IsStateValidOrRestoring() && mChildren[i].GetRloc16() == aAddress)
{
return &mChildren[i];
}
}
return NULL;
}
Child *MleRouter::GetChild(const Mac::ExtAddress &aAddress)
{
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].IsStateValidOrRestoring() && mChildren[i].GetExtAddress() == aAddress)
{
return &mChildren[i];
}
}
return NULL;
}
Child *MleRouter::GetChild(const Mac::Address &aAddress)
{
switch (aAddress.GetType())
{
case Mac::Address::kTypeShort:
return GetChild(aAddress.GetShort());
case Mac::Address::kTypeExtended:
return GetChild(aAddress.GetExtended());
default:
break;
}
return NULL;
}
uint8_t MleRouter::GetChildIndex(const Child &aChild)
{
return static_cast<uint8_t>(&aChild - mChildren);
}
Child *MleRouter::GetChildren(uint8_t *aNumChildren)
{
if (aNumChildren != NULL)
{
*aNumChildren = mMaxChildrenAllowed;
}
return mChildren;
}
bool MleRouter::IsMinimalChild(uint16_t aRloc16)
{
ThreadNetif &netif = GetNetif();
@@ -3265,23 +3162,6 @@ bool MleRouter::IsMinimalChild(uint16_t aRloc16)
return rval;
}
otError MleRouter::SetMaxAllowedChildren(uint8_t aMaxChildren)
{
otError error = OT_ERROR_NONE;
// Ensure the value is between 1 and kMaxChildren
VerifyOrExit(aMaxChildren > 0 && aMaxChildren <= kMaxChildren, error = OT_ERROR_INVALID_ARGS);
// Do not allow setting max children if MLE is running
VerifyOrExit(mRole == OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE);
// Save the value
mMaxChildrenAllowed = aMaxChildren;
exit:
return error;
}
otError MleRouter::RemoveNeighbor(const Mac::Address &aAddress)
{
otError error = OT_ERROR_NONE;
@@ -3394,13 +3274,8 @@ Neighbor *MleRouter::GetNeighbor(uint16_t aAddress)
case OT_DEVICE_ROLE_ROUTER:
case OT_DEVICE_ROLE_LEADER:
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].IsStateValidOrRestoring() && mChildren[i].GetRloc16() == aAddress)
{
ExitNow(rval = &mChildren[i]);
}
}
rval = GetChildTable().FindChild(aAddress, ChildTable::kInStateValidOrRestoring);
VerifyOrExit(rval == NULL);
if (IsActiveRouter(aAddress))
{
@@ -3436,13 +3311,8 @@ Neighbor *MleRouter::GetNeighbor(const Mac::ExtAddress &aAddress)
case OT_DEVICE_ROLE_ROUTER:
case OT_DEVICE_ROLE_LEADER:
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].IsStateValidOrRestoring() && mChildren[i].GetExtAddress() == aAddress)
{
ExitNow(rval = &mChildren[i]);
}
}
rval = GetChildTable().FindChild(aAddress, ChildTable::kInStateValidOrRestoring);
VerifyOrExit(rval == NULL);
for (int i = 0; i <= kMaxRouterId; i++)
{
@@ -3518,14 +3388,9 @@ Neighbor *MleRouter::GetNeighbor(const Ip6::Address &aAddress)
context.mContextId = 0xff;
}
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
child = &mChildren[i];
if (!child->IsStateValidOrRestoring())
{
continue;
}
child = iter.GetChild();
if (context.mContextId == 0 && aAddress.mFields.m16[4] == HostSwap16(0x0000) &&
aAddress.mFields.m16[5] == HostSwap16(0x00ff) && aAddress.mFields.m16[6] == HostSwap16(0xfe00) &&
@@ -3748,7 +3613,9 @@ otError MleRouter::GetChildInfoById(uint16_t aChildId, otChildInfo &aChildInfo)
aChildId = GetChildId(aChildId);
}
VerifyOrExit((child = FindChild(aChildId)) != NULL, error = OT_ERROR_NOT_FOUND);
child = GetChildTable().FindChild(aChildId, ChildTable::kInStateAnyExceptInvalid);
VerifyOrExit(child != NULL, error = OT_ERROR_NOT_FOUND);
error = GetChildInfo(*child, aChildInfo);
exit:
@@ -3758,9 +3625,12 @@ exit:
otError MleRouter::GetChildInfoByIndex(uint8_t aChildIndex, otChildInfo &aChildInfo)
{
otError error = OT_ERROR_NONE;
Child * child = NULL;
VerifyOrExit(aChildIndex < mMaxChildrenAllowed, error = OT_ERROR_INVALID_ARGS);
error = GetChildInfo(mChildren[aChildIndex], aChildInfo);
child = GetChildTable().GetChildAtIndex(aChildIndex);
VerifyOrExit(child != NULL, error = OT_ERROR_NOT_FOUND);
error = GetChildInfo(*child, aChildInfo);
exit:
return error;
@@ -3771,11 +3641,13 @@ otError MleRouter::GetChildNextIp6Address(uint8_t aChildIndex
Ip6::Address & aAddress)
{
otError error = OT_ERROR_NONE;
Child * child = NULL;
VerifyOrExit(aChildIndex < mMaxChildrenAllowed, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(mChildren[aChildIndex].IsStateValidOrRestoring(), error = OT_ERROR_INVALID_ARGS);
child = GetChildTable().GetChildAtIndex(aChildIndex);
VerifyOrExit(child != NULL, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(child->IsStateValidOrRestoring(), error = OT_ERROR_INVALID_ARGS);
error = mChildren[aChildIndex].GetNextIp6Address(GetInstance(), aIterator, aAddress);
error = child->GetNextIp6Address(GetInstance(), aIterator, aAddress);
exit:
return error;
@@ -3792,11 +3664,12 @@ void MleRouter::RestoreChildren(void)
Child * child;
const Settings::ChildInfo &childInfo = iter.GetChildInfo();
child = FindChild(*static_cast<const Mac::ExtAddress *>(&childInfo.mExtAddress));
child = GetChildTable().FindChild(*static_cast<const Mac::ExtAddress *>(&childInfo.mExtAddress),
ChildTable::kInStateAnyExceptInvalid);
if (child == NULL)
{
VerifyOrExit((child = NewChild()) != NULL, error = OT_ERROR_NO_BUFS);
VerifyOrExit((child = GetChildTable().GetNewChild()) != NULL, error = OT_ERROR_NO_BUFS);
}
else
{
@@ -3817,7 +3690,7 @@ void MleRouter::RestoreChildren(void)
exit:
if (foundDuplicate || (numChildren > kMaxChildren) || (error != OT_ERROR_NONE))
if (foundDuplicate || (numChildren > GetChildTable().GetMaxChildren()) || (error != OT_ERROR_NONE))
{
// If there is any error, e.g., there are more saved children
// in non-volatile settings than could be restored or there are
@@ -3852,7 +3725,8 @@ otError MleRouter::StoreChild(uint16_t aChildRloc16)
Child * child;
Settings::ChildInfo childInfo;
VerifyOrExit((child = FindChild(GetChildId(aChildRloc16))) != NULL, error = OT_ERROR_NOT_FOUND);
child = GetChildTable().FindChild(GetChildId(aChildRloc16), ChildTable::kInStateAnyExceptInvalid);
VerifyOrExit(child != NULL, error = OT_ERROR_NOT_FOUND);
IgnoreReturnValue(RemoveStoredChild(aChildRloc16));
@@ -3874,12 +3748,9 @@ otError MleRouter::RefreshStoredChildren(void)
SuccessOrExit(error = GetInstance().GetSettings().DeleteChildInfo());
for (uint8_t i = 0; i < kMaxChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateAnyExceptInvalid); !iter.IsDone(); iter.Advance())
{
if (mChildren[i].GetState() != Neighbor::kStateInvalid)
{
SuccessOrExit(error = StoreChild(mChildren[i].GetRloc16()));
}
SuccessOrExit(error = StoreChild(iter.GetChild()->GetRloc16()));
}
exit:
@@ -3959,15 +3830,22 @@ otError MleRouter::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, otNeig
memset(&aNeighInfo, 0, sizeof(aNeighInfo));
// Non-negative iterator value gives the current index into mChildren array
// Non-negative iterator value gives the Child index into child table
if (aIterator >= 0)
{
for (index = aIterator; index < mMaxChildrenAllowed; index++)
for (index = aIterator;; index++)
{
if (mChildren[index].GetState() == Neighbor::kStateValid)
Child *child = GetChildTable().GetChildAtIndex(static_cast<uint8_t>(index));
if (child == NULL)
{
neighbor = &mChildren[index];
break;
}
if (child->GetState() == Neighbor::kStateValid)
{
neighbor = child;
aNeighInfo.mIsChild = true;
index++;
aIterator = index;
@@ -4068,7 +3946,7 @@ otError MleRouter::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, I
else if (GetRouterId(aMeshDest) == mRouterId)
{
// mesh destination is a child of this device
if (GetChild(aMeshDest))
if (GetChildTable().FindChild(aMeshDest, ChildTable::kInStateValidOrRestoring))
{
return OT_ERROR_NONE;
}
@@ -4294,26 +4172,9 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Header * aHeader,
SendLinkRequest(NULL);
// send child id responses
for (int i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateChildIdRequest); !iter.IsDone(); iter.Advance())
{
switch (mChildren[i].GetState())
{
case Neighbor::kStateChildIdRequest:
SendChildIdResponse(mChildren[i]);
break;
case Neighbor::kStateParentResponse:
case Neighbor::kStateLinkRequest:
assert(false);
break;
case Neighbor::kStateInvalid:
case Neighbor::kStateParentRequest:
case Neighbor::kStateValid:
case Neighbor::kStateRestored:
case Neighbor::kStateChildUpdateRequest:
break;
}
SendChildIdResponse(*iter.GetChild());
}
exit:
@@ -4535,7 +4396,6 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
ConnectivityTlv &tlv = aTlv;
uint8_t cost;
uint8_t linkQuality;
uint8_t numChildren = 0;
int8_t parentPriority = kParentPriorityMedium;
if (mParentPriority != kParentPriorityUnspecified)
@@ -4544,15 +4404,10 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
}
else
{
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() == Neighbor::kStateValid)
{
numChildren++;
}
}
uint8_t numChildren = GetChildTable().GetNumChildren(ChildTable::kInStateValid);
uint8_t maxAllowed = GetChildTable().GetMaxChildrenAllowed();
if ((mMaxChildrenAllowed - numChildren) < (mMaxChildrenAllowed / 3))
if ((maxAllowed - numChildren) < (maxAllowed / 3))
{
parentPriority = kParentPriorityLow;
}
@@ -4877,29 +4732,14 @@ exit:
bool MleRouter::HasChildren(void)
{
bool hasChildren = false;
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() == Neighbor::kStateRestored ||
mChildren[i].GetState() >= Neighbor::kStateChildIdRequest)
{
ExitNow(hasChildren = true);
}
}
exit:
return hasChildren;
return GetChildTable().HasChildren(ChildTable::kInStateValidOrAttaching);
}
void MleRouter::RemoveChildren(void)
{
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
if (mChildren[i].IsStateValidOrRestoring())
{
RemoveNeighbor(mChildren[i]);
}
RemoveNeighbor(*iter.GetChild());
}
}
@@ -4910,13 +4750,7 @@ bool MleRouter::HasSmallNumberOfChildren(void)
VerifyOrExit(routerCount > mRouterDowngradeThreshold);
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
{
if (mChildren[i].GetState() == Neighbor::kStateValid)
{
numChildren++;
}
}
numChildren = GetChildTable().GetNumChildren(ChildTable::kInStateValid);
return numChildren < (routerCount - mRouterDowngradeThreshold) * 3;
@@ -4976,21 +4810,18 @@ otError MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
VerifyOrExit(mRole == OT_DEVICE_ROLE_ROUTER || mRole == OT_DEVICE_ROLE_LEADER, error = OT_ERROR_INVALID_STATE);
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
if (mChildren[i].GetState() != Neighbor::kStateValid)
Child &child = *iter.GetChild();
if (child.IsFullThreadDevice())
{
continue;
}
if (mChildren[i].IsFullThreadDevice())
if (child.GetTimeout() > aTimeout)
{
continue;
}
if (mChildren[i].GetTimeout() > aTimeout)
{
aTimeout = mChildren[i].GetTimeout();
aTimeout = child.GetTimeout();
}
error = OT_ERROR_NONE;
@@ -5029,14 +4860,16 @@ bool MleRouter::HasSleepyChildrenSubscribed(const Ip6::Address &aAddress)
{
bool rval = false;
for (uint8_t i = 0; i < mMaxChildrenAllowed; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
if (!mChildren[i].IsStateValidOrRestoring() || mChildren[i].IsRxOnWhenIdle())
Child &child = *iter.GetChild();
if (child.IsRxOnWhenIdle())
{
continue;
}
if (IsSleepyChildSubscribed(aAddress, mChildren[i]))
if (IsSleepyChildSubscribed(aAddress, child))
{
ExitNow(rval = true);
}
+6 -63
View File
@@ -48,6 +48,7 @@
#include "meshcop/meshcop_tlvs.hpp"
#include "net/icmp6.hpp"
#include "net/udp6.hpp"
#include "thread/child_table.hpp"
#include "thread/mle.hpp"
#include "thread/mle_tlvs.hpp"
#include "thread/thread_tlvs.hpp"
@@ -378,66 +379,12 @@ public:
otError RemoveNeighbor(Neighbor &aNeighbor);
/**
* This method returns a pointer to a Child object.
* This method gets the `ChildTable` object.
*
* @param[in] aAddress The address of the Child.
*
* @returns A pointer to the Child object.
* @returns A reference to the `ChildTable`.
*
*/
Child *GetChild(uint16_t aAddress);
/**
* This method returns a pointer to a Child object.
*
* @param[in] aAddress A reference to the address of the Child.
*
* @returns A pointer to the Child object.
*
*/
Child *GetChild(const Mac::ExtAddress &aAddress);
/**
* This method returns a pointer to a Child object.
*
* @param[in] aAddress A reference to the address of the Child.
*
* @returns A pointer to the Child corresponding to @p aAddress, NULL otherwise.
*
*/
Child *GetChild(const Mac::Address &aAddress);
/**
* This method returns a child index for the Child object.
*
* @param[in] aChild A reference to the Child object.
*
* @returns The index for the Child corresponding to @p aChild.
*
*/
uint8_t GetChildIndex(const Child &aChild);
/**
* This method returns a pointer to a Child array.
*
* @param[out] aNumChildren A pointer to output the number of children.
*
* @returns A pointer to the Child array.
*
*/
Child *GetChildren(uint8_t *aNumChildren);
/**
* This method sets the max children allowed value for this Thread interface.
*
* @param[in] aMaxChildren The max children allowed value.
*
* @retval OT_ERROR_NONE Successfully set the max.
* @retval OT_ERROR_INVALID_ARGS If @p aMaxChildren is not in the range [1, kMaxChildren].
* @retval OT_ERROR_INVALID_STATE If MLE has already been started.
*
*/
otError SetMaxAllowedChildren(uint8_t aMaxChildren);
ChildTable &GetChildTable(void) { return mChildTable; }
/**
* This method restores children information from non-volatile memory.
@@ -882,10 +829,6 @@ private:
void HandlePartitionChange(void);
Child *NewChild(void);
Child *FindChild(uint16_t aChildId);
Child *FindChild(const Mac::ExtAddress &aMacAddr);
void SetChildStateToValid(Child &aChild);
bool HasChildren(void);
void RemoveChildren(void);
@@ -914,8 +857,8 @@ private:
uint8_t mRouterIdSequence;
uint32_t mRouterIdSequenceLastUpdated;
Router mRouters[kMaxRouterId + 1];
uint8_t mMaxChildrenAllowed;
Child mChildren[kMaxChildren];
ChildTable mChildTable;
otThreadChildTableCallback mChildTableChangedCallback;
+5 -15
View File
@@ -38,6 +38,7 @@
#include "utils/wrap_string.h"
#include "thread/child_table.hpp"
#include "thread/mle.hpp"
#include "thread/mle_tlvs.hpp"
#include "thread/thread_tlvs.hpp"
@@ -52,6 +53,7 @@ class MleRouter : public Mle
public:
explicit MleRouter(Instance &aInstance)
: Mle(aInstance)
, mChildTable(aInstance)
{
}
@@ -83,21 +85,7 @@ public:
otError RemoveNeighbor(const Mac::Address &) { return BecomeDetached(); }
otError RemoveNeighbor(Neighbor &) { return BecomeDetached(); }
Child *GetChild(uint16_t) { return NULL; }
Child *GetChild(const Mac::ExtAddress &) { return NULL; }
Child *GetChild(const Mac::Address &) { return NULL; }
uint8_t GetChildIndex(const Child &) { return 0; }
Child *GetChildren(uint8_t *aNumChildren)
{
if (aNumChildren != NULL)
{
*aNumChildren = 0;
}
return NULL;
}
ChildTable &GetChildTable(void) { return mChildTable; }
bool IsMinimalChild(uint16_t) { return false; }
@@ -176,6 +164,8 @@ private:
OT_UNUSED_VARIABLE(aRoute);
return OT_ERROR_NONE;
}
ChildTable mChildTable;
};
} // namespace Mle
+15 -25
View File
@@ -235,43 +235,33 @@ otError NetworkDiagnostic::AppendChildTable(Message &aMessage)
otError error = OT_ERROR_NONE;
uint8_t count = 0;
uint8_t timeout = 0;
uint8_t numChildren;
const Child * children = netif.GetMle().GetChildren(&numChildren);
ChildTableTlv tlv;
ChildTableEntry entry;
tlv.Init();
for (int i = 0; i < numChildren; i++)
{
if (children[i].GetState() == Neighbor::kStateValid)
{
count++;
}
}
count = netif.GetMle().GetChildTable().GetNumChildren(ChildTable::kInStateValid);
tlv.SetLength(count * sizeof(ChildTableEntry));
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(ChildTableTlv)));
for (int i = 0; i < numChildren; i++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
if (children[i].GetState() == Neighbor::kStateValid)
Child &child = *iter.GetChild();
timeout = 0;
while (static_cast<uint32_t>(1 << timeout) < child.GetTimeout())
{
timeout = 0;
while (static_cast<uint32_t>(1 << timeout) < children[i].GetTimeout())
{
timeout++;
}
entry.SetReserved(0);
entry.SetTimeout(timeout + 4);
entry.SetChildId(netif.GetMle().GetChildId(children[i].GetRloc16()));
entry.SetMode(children[i].GetDeviceMode());
SuccessOrExit(error = aMessage.Append(&entry, sizeof(ChildTableEntry)));
timeout++;
}
entry.SetReserved(0);
entry.SetTimeout(timeout + 4);
entry.SetChildId(netif.GetMle().GetChildId(child.GetRloc16()));
entry.SetMode(child.GetDeviceMode());
SuccessOrExit(error = aMessage.Append(&entry, sizeof(ChildTableEntry)));
}
exit:
+4 -8
View File
@@ -218,17 +218,13 @@ exit:
otError SourceMatchController::AddPendingEntries(void)
{
otError error = OT_ERROR_NONE;
uint8_t numChildren;
Child * child;
child = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++, child++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValidOrRestoring); !iter.IsDone(); iter.Advance())
{
if (child->IsStateValidOrRestoring() && child->IsIndirectSourceMatchPending())
if (iter.GetChild()->IsIndirectSourceMatchPending())
{
SuccessOrExit(error = AddAddress(*child));
child->SetIndirectSourceMatchPending(false);
SuccessOrExit(error = AddAddress(*iter.GetChild()));
iter.GetChild()->SetIndirectSourceMatchPending(false);
}
}
+23
View File
@@ -47,6 +47,29 @@ void Neighbor::GenerateChallenge(void)
Random::FillBuffer(mValidPending.mPending.mChallenge, sizeof(mValidPending.mPending.mChallenge));
}
bool Child::IsStateValidOrAttaching(void) const
{
bool rval = false;
switch (GetState())
{
case kStateInvalid:
case kStateParentRequest:
case kStateParentResponse:
break;
case kStateRestored:
case kStateChildIdRequest:
case kStateLinkRequest:
case kStateChildUpdateRequest:
case kStateValid:
rval = true;
break;
}
return rval;
}
void Child::ClearIp6Addresses(void)
{
memset(mMeshLocalIid, 0, sizeof(mMeshLocalIid));
+14 -2
View File
@@ -87,7 +87,7 @@ public:
void SetState(State aState) { mState = static_cast<uint8_t>(aState); }
/**
* Check if the neighbor/child is being restored.
* This method indicates whether the neighbor/child is being restored.
*
* @returns TRUE if the neighbor is being restored, FALSE otherwise.
*
@@ -95,7 +95,8 @@ public:
bool IsStateRestoring(void) const { return (mState == kStateRestored) || (mState == kStateChildUpdateRequest); }
/**
* Check if the neighbor/child is in valid state or if it is being restored.
* This method indicates whether the neighbor/child is in valid state or if it is being restored.
*
* When in these states messages can be sent to and/or received from the neighbor/child.
*
* @returns TRUE if the neighbor is in valid, restored, or being restored states, FALSE otherwise.
@@ -414,6 +415,17 @@ public:
otChildIp6AddressIterator mIndex;
};
/**
* This method indicates if the child state is valid or being attached or being restored.
*
* The states `kStateRestored`, `kStateChildIdRequest`, `kStateChildUpdateRequest`, `kStateValid`, (and
* `kStateLinkRequest) are considered as attached or being restored.
*
* @returns TRUE if the child is attached or being restored.
*
*/
bool IsStateValidOrAttaching(void) const;
/**
* This method clears the IPv6 address list for the child.
*
+11 -30
View File
@@ -68,14 +68,11 @@ Child *ChildSupervisor::GetDestination(const Message &aMessage) const
{
Child * child = NULL;
uint8_t childIndex;
uint8_t numChildren;
VerifyOrExit(aMessage.GetType() == Message::kTypeSupervision);
aMessage.Read(0, sizeof(childIndex), &childIndex);
child = GetNetif().GetMle().GetChildren(&numChildren);
VerifyOrExit(childIndex < numChildren, child = NULL);
child += childIndex;
child = GetNetif().GetMle().GetChildTable().GetChildAtIndex(childIndex);
exit:
return child;
@@ -97,7 +94,7 @@ void ChildSupervisor::SendMessage(Child &aChild)
// the destination of the message to be later retrieved using
// `ChildSupervisor::GetDestination(message)`.
childIndex = netif.GetMle().GetChildIndex(aChild);
childIndex = netif.GetMle().GetChildTable().GetChildIndex(aChild);
SuccessOrExit(message->Append(&childIndex, sizeof(childIndex)));
SuccessOrExit(netif.SendMessage(*message));
@@ -125,25 +122,17 @@ void ChildSupervisor::HandleTimer(Timer &aTimer)
void ChildSupervisor::HandleTimer(void)
{
Child * child;
uint8_t numChildren;
VerifyOrExit(mSupervisionInterval != 0);
child = GetNetif().GetMle().GetChildren(&numChildren);
for (uint8_t i = 0; i < numChildren; i++, child++)
for (ChildTable::Iterator iter(GetInstance(), ChildTable::kInStateValid); !iter.IsDone(); iter.Advance())
{
if (child->GetState() != Child::kStateValid)
{
continue;
}
Child &child = *iter.GetChild();
child->IncrementSecondsSinceLastSupervision();
child.IncrementSecondsSinceLastSupervision();
if ((child->GetSecondsSinceLastSupervision() >= mSupervisionInterval) && (child->IsRxOnWhenIdle() == false))
if ((child.GetSecondsSinceLastSupervision() >= mSupervisionInterval) && (child.IsRxOnWhenIdle() == false))
{
SendMessage(*child);
SendMessage(child);
}
}
@@ -155,23 +144,15 @@ exit:
void ChildSupervisor::CheckState(void)
{
bool shouldRun = false;
uint8_t numChildren = 0;
Mle::MleRouter &mle = GetInstance().Get<Mle::MleRouter>();
bool shouldRun = false;
Mle::MleRouter &mle = GetInstance().Get<Mle::MleRouter>();
// Child Supervision should run if `mSupervisionInterval` is not
// zero, Thread MLE operation is enabled, and there is at least one
// "valid" child in the child table.
VerifyOrExit(mSupervisionInterval != 0);
VerifyOrExit(mle.GetRole() != OT_DEVICE_ROLE_DISABLED);
for (Child *child = mle.GetChildren(&numChildren); numChildren > 0; child++, numChildren--)
{
VerifyOrExit(child->GetState() != Child::kStateValid, shouldRun = true);
}
exit:
shouldRun = ((mSupervisionInterval != 0) && (mle.GetRole() != OT_DEVICE_ROLE_DISABLED) &&
mle.GetChildTable().HasChildren(ChildTable::kInStateValid));
if (shouldRun && !mTimer.IsRunning())
{
+5
View File
@@ -85,6 +85,7 @@ endif # OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
check_PROGRAMS = \
test-aes \
test-child \
test-child-table \
test-heap \
test-hmac-sha256 \
test-lowpan \
@@ -147,6 +148,9 @@ test_aes_SOURCES = test_platform.cpp test_aes.cpp
test_child_LDADD = $(COMMON_LDADD)
test_child_SOURCES = test_platform.cpp test_child.cpp
test_child_table_LDADD = $(COMMON_LDADD)
test_child_table_SOURCES = test_platform.cpp test_child_table.cpp
test_heap_LDADD = $(COMMON_LDADD)
test_heap_SOURCES = test_platform.cpp test_heap.cpp
@@ -212,6 +216,7 @@ PRETTY_FILES = \
$(test_address_sanitizer_SOURCES) \
$(test_aes_SOURCES) \
$(test_child_SOURCES) \
$(test_child_table_SOURCES) \
$(test_heap_SOURCES) \
$(test_hmac_sha256_SOURCES) \
$(test_link_quality_SOURCES) \
+412
View File
@@ -0,0 +1,412 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_platform.h"
#include <openthread/config.h>
#include <openthread/openthread.h>
#include "test_util.h"
#include "common/instance.hpp"
#include "thread/child_table.hpp"
namespace ot {
static ot::Instance *sInstance;
enum
{
kMaxChildren = OPENTHREAD_CONFIG_MAX_CHILDREN,
};
struct TestChild
{
Child::State mState;
uint16_t mRloc16;
otExtAddress mExtAddress;
};
const ChildTable::StateFilter kAllFilters[] = {
ChildTable::kInStateValid,
ChildTable::kInStateValidOrRestoring,
ChildTable::kInStateChildIdRequest,
ChildTable::kInStateValidOrAttaching,
ChildTable::kInStateAnyExceptInvalid,
};
// Checks whether a `Child` matches the `TestChild` struct.
static bool ChildMatches(const Child &aChild, const TestChild &aTestChild)
{
return (aChild.GetState() == aTestChild.mState) && (aChild.GetRloc16() == aTestChild.mRloc16) &&
(aChild.GetExtAddress() == static_cast<const Mac::ExtAddress &>(aTestChild.mExtAddress));
}
// Checks whether a `Child::State` matches a `ChildTable::StateFilter`.
static bool StateMatchesFilter(Child::State aState, ChildTable::StateFilter aFilter)
{
bool rval = false;
Child child;
child.SetState(aState);
switch (aFilter)
{
case ChildTable::kInStateAnyExceptInvalid:
rval = (aState != Child::kStateInvalid);
break;
case ChildTable::kInStateValid:
rval = (aState == Child::kStateValid);
break;
case ChildTable::kInStateValidOrRestoring:
rval = child.IsStateValidOrRestoring();
break;
case ChildTable::kInStateChildIdRequest:
rval = (aState == Child::kStateChildIdRequest);
break;
case ChildTable::kInStateValidOrAttaching:
rval = child.IsStateValidOrAttaching();
break;
case ChildTable::kInStateAnyExceptValidOrRestoing:
rval = !child.IsStateValidOrRestoring();
break;
}
return rval;
}
// Verifies that `ChildTable` contains a given list of `TestChild` entries.
void VerifyChildTableContent(ChildTable &aTable, uint8_t aChildListLength, const TestChild *aChildList)
{
printf("Test ChildTable with %d entries", aChildListLength);
for (uint8_t k = 0; k < sizeof(kAllFilters) / sizeof(kAllFilters[0]); k++)
{
ChildTable::StateFilter filter = kAllFilters[k];
// Verify that we can find all children from given list by rloc or extended address.
for (uint8_t listIndex = 0; listIndex < aChildListLength; listIndex++)
{
Child * child;
Mac::Address address;
if (!StateMatchesFilter(aChildList[listIndex].mState, filter))
{
continue;
}
child = aTable.FindChild(aChildList[listIndex].mRloc16, filter);
VerifyOrQuit(child != NULL, "FindChild(rloc) failed");
VerifyOrQuit(ChildMatches(*child, aChildList[listIndex]), "FindChild(rloc) returned incorrect child");
child = aTable.FindChild(static_cast<const Mac::ExtAddress &>(aChildList[listIndex].mExtAddress), filter);
VerifyOrQuit(child != NULL, "FindChild(ExtAddress) failed");
VerifyOrQuit(ChildMatches(*child, aChildList[listIndex]), "FindChild(ExtAddress) returned incorrect child");
address.SetShort(aChildList[listIndex].mRloc16);
child = aTable.FindChild(address, filter);
VerifyOrQuit(child != NULL, "FindChild(address) failed");
VerifyOrQuit(ChildMatches(*child, aChildList[listIndex]), "FindChild(address) returned incorrect child");
address.SetExtended(static_cast<const Mac::ExtAddress &>(aChildList[listIndex].mExtAddress));
child = aTable.FindChild(address, filter);
VerifyOrQuit(child != NULL, "FindChild(address) failed");
VerifyOrQuit(ChildMatches(*child, aChildList[listIndex]), "FindChild(address) returned incorrect child");
}
// Verify `ChildTable::Iterator` behavior when starting from different child entries.
for (uint8_t listIndex = 0; listIndex <= aChildListLength; listIndex++)
{
Child *startingChild = NULL;
if (listIndex < aChildListLength)
{
startingChild = aTable.FindChild(aChildList[listIndex].mRloc16, ChildTable::kInStateAnyExceptInvalid);
VerifyOrQuit(startingChild != NULL, "FindChild() failed");
}
// Test an iterator starting from `startingChild`.
{
ChildTable::Iterator iter(*sInstance, filter, startingChild);
bool childObserved[kMaxChildren];
uint8_t numChildren = 0;
memset(childObserved, 0, sizeof(childObserved));
// Check if the first entry matches the `startingChild`
if ((startingChild != NULL) && StateMatchesFilter(startingChild->GetState(), filter))
{
VerifyOrQuit(!iter.IsDone(), "iterator IsDone() failed");
VerifyOrQuit(iter.GetChild() != NULL, "iterator GetChild() failed");
VerifyOrQuit(iter.GetChild() == startingChild,
"Iterator failed to start from the given child entry");
iter.Advance();
iter.Reset();
VerifyOrQuit(iter.GetChild() == startingChild, "iterator Reset() failed");
}
// Use the iterator and verify that each returned `Child` entry is in the expected list.
for (; !iter.IsDone(); iter.Advance())
{
Child * child = iter.GetChild();
bool didFind = false;
uint8_t childIndex;
VerifyOrQuit(child != NULL, "iter.GetChild() failed");
childIndex = aTable.GetChildIndex(*child);
VerifyOrQuit(childIndex < aTable.GetMaxChildrenAllowed(), "Child Index is out of bound");
VerifyOrQuit(aTable.GetChildAtIndex(childIndex) == child, "GetChildAtIndex() failed");
for (uint8_t index = 0; index < aChildListLength; index++)
{
if (ChildMatches(*iter.GetChild(), aChildList[index]))
{
childObserved[index] = true;
numChildren++;
didFind = true;
break;
}
}
VerifyOrQuit(didFind, "ChildTable::Iterator returned an entry not in the expected list");
}
// Verify that when iterator is done, it points to `NULL`.
VerifyOrQuit(iter.GetChild() == NULL, "iterator GetChild() failed");
iter.Advance();
VerifyOrQuit(iter.IsDone(), "iterator Advance() (after iterator is done) failed");
VerifyOrQuit(iter.GetChild() == NULL, "iterator GetChild() failed");
// Verify that the number of children matches the number of entries we get from iterator.
VerifyOrQuit(aTable.GetNumChildren(filter) == numChildren, "GetNumChildren() failed");
VerifyOrQuit(aTable.HasChildren(filter) == (numChildren != 0), "HasChildren() failed");
// Verify that there is no missing or extra entry between the expected list
// and what was observed/returned by the iterator.
for (uint8_t index = 0; index < aChildListLength; index++)
{
if (StateMatchesFilter(aChildList[index].mState, filter))
{
VerifyOrQuit(childObserved[index], "iterator failed to return an expected entry");
}
else
{
VerifyOrQuit(!childObserved[index], "iterator returned an extra unexpected entry");
}
}
}
}
}
printf(" -- PASS\n");
}
void TestChildTable(void)
{
const TestChild testChildList[] = {
{
Child::kStateValid,
0x8001,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x16}},
},
{
Child::kStateParentRequest,
0x8002,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x17}},
},
{
Child::kStateValid,
0x8003,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x18}},
},
{
Child::kStateValid,
0x8004,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x19}},
},
{
Child::kStateRestored,
0x8005,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x20}},
},
{
Child::kStateValid,
0x8006,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x21}},
},
{
Child::kStateChildIdRequest,
0x8007,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x22}},
},
{
Child::kStateChildUpdateRequest,
0x8008,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x23}},
},
{
Child::kStateParentResponse,
0x8009,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x24}},
},
{
Child::kStateRestored,
0x800a,
{{0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x25}},
},
};
const uint8_t testListLength = sizeof(testChildList) / sizeof(testChildList[0]);
uint8_t testNumAllowedChildren = 2;
ChildTable *table;
otError error;
sInstance = testInitInstance();
VerifyOrQuit(sInstance != NULL, "Null instance");
table = &sInstance->Get<ChildTable>();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
printf("Checking initial state after child table is constructed");
VerifyOrQuit(table->GetMaxChildrenAllowed() == table->GetMaxChildren(),
"GetMaxChildrenAllowed() initial value is incorrect ");
for (uint8_t i = 0; i < sizeof(kAllFilters) / sizeof(kAllFilters[0]); i++)
{
ChildTable::StateFilter filter = kAllFilters[i];
VerifyOrQuit(table->HasChildren(filter) == false, "HasChildren() failed after init");
VerifyOrQuit(table->GetNumChildren(filter) == 0, "GetNumChildren() failed after init");
}
printf(" -- PASS\n");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VerifyChildTableContent(*table, 0, testChildList);
VerifyOrQuit(table->GetMaxChildrenAllowed() >= testListLength,
"Default child table size is too small for the unit test");
// Add the child entries from test list one by one and verify the table content
for (uint8_t i = 0; i < testListLength; i++)
{
Child *child;
child = table->GetNewChild();
VerifyOrQuit(child != NULL, "GetNewChild() failed");
child->SetState(testChildList[i].mState);
child->SetRloc16(testChildList[i].mRloc16);
child->SetExtAddress((static_cast<const Mac::ExtAddress &>(testChildList[i].mExtAddress)));
VerifyChildTableContent(*table, i + 1, testChildList);
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Verify Child Table clear
table->Clear();
VerifyChildTableContent(*table, 0, testChildList);
// Add the child entries from test list in reverse order and verify the table content
for (uint8_t i = testListLength; i > 0; i--)
{
Child *child;
child = table->GetNewChild();
VerifyOrQuit(child != NULL, "GetNewChild() failed");
child->SetState(testChildList[i - 1].mState);
child->SetRloc16(testChildList[i - 1].mRloc16);
child->SetExtAddress((static_cast<const Mac::ExtAddress &>(testChildList[i - 1].mExtAddress)));
VerifyChildTableContent(*table, testListLength - i + 1, &testChildList[i - 1]);
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
printf("Test Get/SetMaxChildrenAllowed");
error = table->SetMaxChildrenAllowed(kMaxChildren - 1);
VerifyOrQuit(error == OT_ERROR_INVALID_STATE, "SetMaxChildrenAllowed() should fail when table is not empty");
table->Clear();
error = table->SetMaxChildrenAllowed(kMaxChildren + 1);
VerifyOrQuit(error == OT_ERROR_INVALID_ARGS, "SetMaxChildrenAllowed() did not fail with an invalid arg");
error = table->SetMaxChildrenAllowed(0);
VerifyOrQuit(error == OT_ERROR_INVALID_ARGS, "SetMaxChildrenAllowed() did not fail with an invalid arg");
error = table->SetMaxChildrenAllowed(testNumAllowedChildren);
VerifyOrQuit(error == OT_ERROR_NONE, "SetMaxChildrenAllowed() failed");
VerifyOrQuit(table->GetMaxChildrenAllowed() == testNumAllowedChildren, "GetMaxChildrenAllowed() failed");
for (uint8_t num = 0; num < testNumAllowedChildren; num++)
{
Child *child = table->GetNewChild();
VerifyOrQuit(child != NULL, "GetNewChild() failed");
child->SetState(Child::kStateValid);
}
VerifyOrQuit(table->GetNewChild() == NULL, "GetNewChild() did not fail when table was full");
printf(" -- PASS\n");
testFreeInstance(sInstance);
}
} // namespace ot
#ifdef ENABLE_TEST_MAIN
int main(void)
{
ot::TestChildTable();
printf("\nAll tests passed.\n");
return 0;
}
#endif