diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index 30d7da47f..518d2eabd 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -259,7 +259,7 @@ otError otThreadGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChi OT_ASSERT(aChildInfo != nullptr); - return instance.Get().GetChildInfoById(aChildId, *static_cast(aChildInfo)); + return instance.Get().GetChildInfoById(aChildId, *static_cast(aChildInfo)); } otError otThreadGetChildInfoByIndex(otInstance *aInstance, uint16_t aChildIndex, otChildInfo *aChildInfo) @@ -268,7 +268,7 @@ otError otThreadGetChildInfoByIndex(otInstance *aInstance, uint16_t aChildIndex, OT_ASSERT(aChildInfo != nullptr); - return instance.Get().GetChildInfoByIndex(aChildIndex, *static_cast(aChildInfo)); + return instance.Get().GetChildInfoByIndex(aChildIndex, *static_cast(aChildInfo)); } otError otThreadGetChildNextIp6Address(otInstance * aInstance, diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 0ea49178f..d85dfb13e 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -311,7 +311,7 @@ otError Ip6::InsertMplOption(Message &aMessage, Header &aHeader, MessageInfo &aM { #if OPENTHREAD_FTD if (aHeader.GetDestination().IsMulticastLargerThanRealmLocal() && - Get().HasSleepyChildrenSubscribed(aHeader.GetDestination())) + Get().HasSleepyChildWithAddress(aHeader.GetDestination())) { Message *messageCopy = nullptr; @@ -517,7 +517,7 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t if (aMessageInfo.GetPeerAddr().IsMulticastLargerThanRealmLocal()) { #if OPENTHREAD_FTD - if (Get().HasSleepyChildrenSubscribed(header.GetDestination())) + if (Get().HasSleepyChildWithAddress(header.GetDestination())) { Message *messageCopy = nullptr; @@ -1193,7 +1193,7 @@ otError Ip6::HandleDatagram(Message &aMessage, Netif *aNetif, const void *aLinkM #if OPENTHREAD_FTD if (header.GetDestination().IsMulticastLargerThanRealmLocal() && - Get().HasSleepyChildrenSubscribed(header.GetDestination())) + Get().HasSleepyChildWithAddress(header.GetDestination())) { forward = true; } diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index f6035867d..909f55aa6 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -225,6 +225,155 @@ exit: return error; } +otError ChildTable::GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo) +{ + otError error = OT_ERROR_NONE; + Child * child; + uint16_t rloc16; + + if ((aChildId & ~Mle::kMaxChildId) != 0) + { + aChildId = Mle::Mle::ChildIdFromRloc16(aChildId); + } + + rloc16 = Get().GetShortAddress() | aChildId; + child = FindChild(rloc16, Child::kInStateValidOrRestoring); + VerifyOrExit(child != nullptr, error = OT_ERROR_NOT_FOUND); + + aChildInfo.SetFrom(*child); + +exit: + return error; +} + +otError ChildTable::GetChildInfoByIndex(uint16_t aChildIndex, Child::Info &aChildInfo) +{ + otError error = OT_ERROR_NONE; + Child * child = nullptr; + + child = GetChildAtIndex(aChildIndex); + VerifyOrExit((child != nullptr) && child->IsStateValidOrRestoring(), error = OT_ERROR_NOT_FOUND); + + aChildInfo.SetFrom(*child); + +exit: + return error; +} + +void ChildTable::Restore(void) +{ + otError error = OT_ERROR_NONE; + bool foundDuplicate = false; + uint16_t numChildren = 0; + + for (const Settings::ChildInfo &childInfo : Get().IterateChildInfo()) + { + Child *child; + + child = FindChild(childInfo.GetExtAddress(), Child::kInStateAnyExceptInvalid); + + if (child == nullptr) + { + VerifyOrExit((child = GetNewChild()) != nullptr, error = OT_ERROR_NO_BUFS); + } + else + { + foundDuplicate = true; + } + + child->Clear(); + + child->SetExtAddress(childInfo.GetExtAddress()); + child->GetLinkInfo().Clear(); + child->SetRloc16(childInfo.GetRloc16()); + child->SetTimeout(childInfo.GetTimeout()); + child->SetDeviceMode(Mle::DeviceMode(childInfo.GetMode())); + child->SetState(Neighbor::kStateRestored); + child->SetLastHeard(TimerMilli::GetNow()); + child->SetVersion(static_cast(childInfo.GetVersion())); + Get().SetChildUseShortAddress(*child, true); + numChildren++; + } + +exit: + + if (foundDuplicate || (numChildren > 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 + // duplicate entries with same extended address, refresh the stored + // children info to ensure that the non-volatile settings remain + // consistent with the child table. + + RefreshStoredChildren(); + } +} + +void ChildTable::RemoveStoredChild(const Child &aChild) +{ + for (Settings::ChildInfoIterator iter(GetInstance()); !iter.IsDone(); iter++) + { + if (iter.GetChildInfo().GetRloc16() == aChild.GetRloc16()) + { + IgnoreError(iter.Delete()); + break; + } + } +} + +otError ChildTable::StoreChild(const Child &aChild) +{ + Settings::ChildInfo childInfo; + + RemoveStoredChild(aChild); + + childInfo.Init(); + childInfo.SetExtAddress(aChild.GetExtAddress()); + childInfo.SetTimeout(aChild.GetTimeout()); + childInfo.SetRloc16(aChild.GetRloc16()); + childInfo.SetMode(aChild.GetDeviceMode().Get()); + childInfo.SetVersion(aChild.GetVersion()); + + return Get().AddChildInfo(childInfo); +} + +void ChildTable::RefreshStoredChildren(void) +{ + const Child *child = &mChildren[0]; + + SuccessOrExit(Get().DeleteAllChildInfo()); + + for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) + { + if (child->IsStateInvalid()) + { + continue; + } + + SuccessOrExit(StoreChild(*child)); + } + +exit: + return; +} + +bool ChildTable::HasSleepyChildWithAddress(const Ip6::Address &aIp6Address) const +{ + bool hasChild = false; + const Child *child = &mChildren[0]; + + for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) + { + if (child->IsStateValidOrRestoring() && !child->IsRxOnWhenIdle() && child->HasIp6Address(aIp6Address)) + { + hasChild = true; + break; + } + } + + return hasChild; +} + #endif // OPENTHREAD_FTD } // namespace ot diff --git a/src/core/thread/child_table.hpp b/src/core/thread/child_table.hpp index 87300376f..eafcf6833 100644 --- a/src/core/thread/child_table.hpp +++ b/src/core/thread/child_table.hpp @@ -320,6 +320,61 @@ public: */ IteratorBuilder Iterate(Child::StateFilter aFilter) { return IteratorBuilder(GetInstance(), aFilter); } + /** + * This method retains diagnostic information for an attached child by Child ID or RLOC16. + * + * @param[in] aChildId The Child ID or RLOC16 for an attached child. + * @param[out] aChildInfo A reference to a `Child::Info` to populate with the child information. + * + */ + otError GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo); + + /** + * This method retains diagnostic information for an attached child by the internal table index. + * + * @param[in] aChildIndex The table index. + * @param[out] aChildInfo A reference to a `Child::Info` to populate with the child information. + * + */ + otError GetChildInfoByIndex(uint16_t aChildIndex, Child::Info &aChildInfo); + + /** + * This method restores child table from non-volatile memory. + * + */ + void Restore(void); + + /** + * This method removes a stored child information from non-volatile memory. + * + * @param[in] aChildRloc16 A reference to the child to remove from non-volatile memory. + * + */ + void RemoveStoredChild(const Child &aChild); + + /** + * This method store a child information into non-volatile memory. + * + * @param[in] aChild A reference to the child to store. + * + * @retval OT_ERROR_NONE Successfully store child. + * @retval OT_ERROR_NO_BUFS Insufficient available buffers to store child. + * + */ + otError StoreChild(const Child &aChild); + + /** + * This method indicates whether the child table contains any sleepy child (in states valid or restoring) with a + * given IPv6 address. + * + * @param[in] aIp6Address An IPv6 address. + * + * @retval TRUE If the child table contains any sleepy child with @p aIp6Address. + * @retval FALSE If the child table does not contain any sleepy child with @p aIp6Address. + * + */ + bool HasSleepyChildWithAddress(const Ip6::Address &aIp6ddress) const; + private: enum { @@ -342,6 +397,8 @@ private: Child::StateFilter mFilter; }; + void RefreshStoredChildren(void); + uint16_t mMaxChildrenAllowed; Child mChildren[kMaxChildren]; }; diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 7909884fe..144708a56 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -93,7 +93,7 @@ otError MeshForwarder::SendMessage(Message &aMessage) // destined for some sleepy children which subscribed the multicast address. for (Child &child : Get().Iterate(Child::kInStateValidOrRestoring)) { - if (mle.IsSleepyChildSubscribed(ip6Header.GetDestination(), child)) + if (!child.IsRxOnWhenIdle() && child.HasIp6Address(ip6Header.GetDestination())) { mIndirectSender.AddMessageForSleepyChild(aMessage, child); } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index cf50c22d4..5ed9d22cb 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -434,7 +434,7 @@ otError Mle::Restore(void) { Get().SetRouterId(RouterIdFromRloc16(GetRloc16())); Get().SetPreviousPartitionId(networkInfo.GetPreviousPartitionId()); - Get().RestoreChildren(); + Get().Restore(); } #endif diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 1608a11ca..70085abe4 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2548,7 +2548,7 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage, { if (childDidChange) { - IgnoreError(StoreChild(*child)); + IgnoreError(mChildTable.StoreChild(*child)); } } @@ -3402,7 +3402,7 @@ void MleRouter::RemoveNeighbor(Neighbor &aNeighbor) Get().Remove(aNeighbor.GetRloc16()); } - IgnoreError(RemoveStoredChild(aNeighbor.GetRloc16())); + mChildTable.RemoveStoredChild(static_cast(aNeighbor)); } else if (aNeighbor.IsStateValid()) { @@ -3663,136 +3663,6 @@ void MleRouter::SetRouterId(uint8_t aRouterId) mPreviousRouterId = mRouterId; } -otError MleRouter::GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo) -{ - otError error = OT_ERROR_NONE; - Child * child; - uint16_t rloc16; - - if ((aChildId & ~kMaxChildId) != 0) - { - aChildId = ChildIdFromRloc16(aChildId); - } - - rloc16 = Get().GetShortAddress() | aChildId; - child = mChildTable.FindChild(rloc16, Child::kInStateValidOrRestoring); - VerifyOrExit(child != nullptr, error = OT_ERROR_NOT_FOUND); - - aChildInfo.SetFrom(*child); - -exit: - return error; -} - -otError MleRouter::GetChildInfoByIndex(uint16_t aChildIndex, Child::Info &aChildInfo) -{ - otError error = OT_ERROR_NONE; - Child * child = nullptr; - - child = mChildTable.GetChildAtIndex(aChildIndex); - VerifyOrExit((child != nullptr) && child->IsStateValidOrRestoring(), error = OT_ERROR_NOT_FOUND); - - aChildInfo.SetFrom(*child); - -exit: - return error; -} - -void MleRouter::RestoreChildren(void) -{ - otError error = OT_ERROR_NONE; - bool foundDuplicate = false; - uint16_t numChildren = 0; - - for (const Settings::ChildInfo &childInfo : Get().IterateChildInfo()) - { - Child *child; - - child = mChildTable.FindChild(childInfo.GetExtAddress(), Child::kInStateAnyExceptInvalid); - - if (child == nullptr) - { - VerifyOrExit((child = mChildTable.GetNewChild()) != nullptr, error = OT_ERROR_NO_BUFS); - } - else - { - foundDuplicate = true; - } - - child->Clear(); - - child->SetExtAddress(childInfo.GetExtAddress()); - child->GetLinkInfo().Clear(); - child->SetRloc16(childInfo.GetRloc16()); - child->SetTimeout(childInfo.GetTimeout()); - child->SetDeviceMode(DeviceMode(childInfo.GetMode())); - child->SetState(Neighbor::kStateRestored); - child->SetLastHeard(TimerMilli::GetNow()); - child->SetVersion(static_cast(childInfo.GetVersion())); - Get().SetChildUseShortAddress(*child, true); - numChildren++; - } - -exit: - - if (foundDuplicate || (numChildren > mChildTable.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 - // duplicate entries with same extended address, refresh the stored - // children info to ensure that the non-volatile settings remain - // consistent with the child table. - - RefreshStoredChildren(); - } -} - -otError MleRouter::RemoveStoredChild(uint16_t aChildRloc16) -{ - otError error = OT_ERROR_NOT_FOUND; - - for (Settings::ChildInfoIterator iter(GetInstance()); !iter.IsDone(); iter++) - { - if (iter.GetChildInfo().GetRloc16() == aChildRloc16) - { - error = iter.Delete(); - ExitNow(); - } - } - -exit: - return error; -} - -otError MleRouter::StoreChild(const Child &aChild) -{ - Settings::ChildInfo childInfo; - - IgnoreError(RemoveStoredChild(aChild.GetRloc16())); - - childInfo.Init(); - childInfo.SetExtAddress(aChild.GetExtAddress()); - childInfo.SetTimeout(aChild.GetTimeout()); - childInfo.SetRloc16(aChild.GetRloc16()); - childInfo.SetMode(aChild.GetDeviceMode().Get()); - childInfo.SetVersion(aChild.GetVersion()); - - return Get().AddChildInfo(childInfo); -} - -void MleRouter::RefreshStoredChildren(void) -{ - SuccessOrExit(Get().DeleteAllChildInfo()); - - for (Child &child : Get().Iterate(Child::kInStateAnyExceptInvalid)) - { - SuccessOrExit(StoreChild(child)); - } - -exit: - return; -} - otError MleRouter::GetNextNeighborInfo(otNeighborInfoIterator &aIterator, Neighbor::Info &aNeighInfo) { otError error = OT_ERROR_NONE; @@ -4628,7 +4498,7 @@ void MleRouter::SetChildStateToValid(Child &aChild) VerifyOrExit(!aChild.IsStateValid(), OT_NOOP); aChild.SetState(Neighbor::kStateValid); - IgnoreError(StoreChild(aChild)); + IgnoreError(mChildTable.StoreChild(aChild)); #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE Get().UpdateProxiedSubscriptions(aChild, nullptr, 0); @@ -4755,32 +4625,6 @@ void MleRouter::Signal(otNeighborTableEvent aEvent, Neighbor &aNeighbor) } } -bool MleRouter::HasSleepyChildrenSubscribed(const Ip6::Address &aAddress) -{ - bool rval = false; - - for (Child &child : Get().Iterate(Child::kInStateValidOrRestoring)) - { - if (child.IsRxOnWhenIdle()) - { - continue; - } - - if (IsSleepyChildSubscribed(aAddress, child)) - { - ExitNow(rval = true); - } - } - -exit: - return rval; -} - -bool MleRouter::IsSleepyChildSubscribed(const Ip6::Address &aAddress, Child &aChild) -{ - return aChild.IsStateValidOrRestoring() && !aChild.IsRxOnWhenIdle() && aChild.HasIp6Address(aAddress); -} - #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE void MleRouter::HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor) { diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index dced56aa5..004fbb175 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -344,34 +344,6 @@ public: */ void RemoveRouterLink(Router &aRouter); - /** - * This method restores children information from non-volatile memory. - * - */ - void RestoreChildren(void); - - /** - * This method remove a stored child information from non-volatile memory. - * - * @param[in] aChildRloc16 The child RLOC16 to remove. - * - * @retval OT_ERROR_NONE Successfully remove child. - * @retval OT_ERROR_NOT_FOUND There is no specified child stored in non-volatile memory. - * - */ - otError RemoveStoredChild(uint16_t aChildRloc16); - - /** - * This method store a child information into non-volatile memory. - * - * @param[in] aChild A reference to the child to store. - * - * @retval OT_ERROR_NONE Successfully store child. - * @retval OT_ERROR_NO_BUFS Insufficient available buffers to store child. - * - */ - otError StoreChild(const Child &aChild); - /** * This method returns a pointer to a Neighbor object. * @@ -423,24 +395,6 @@ public: */ Neighbor *GetRxOnlyNeighborRouter(const Mac::Address &aAddress); - /** - * This method retains diagnostic information for an attached child by Child ID or RLOC16. - * - * @param[in] aChildId The Child ID or RLOC16 for an attached child. - * @param[out] aChildInfo The child information. - * - */ - otError GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo); - - /** - * This method retains diagnostic information for an attached child by the internal table index. - * - * @param[in] aChildIndex The table index. - * @param[out] aChildInfo The child information. - * - */ - otError GetChildInfoByIndex(uint16_t aChildIndex, Child::Info &aChildInfo); - /** * This method indicates whether or not the RLOC16 is an MTD child of this device. * @@ -610,29 +564,6 @@ public: */ void Signal(otNeighborTableEvent aEvent, Neighbor &aNeighbor); - /** - * This method returns whether the device has any sleepy children subscribed the address. - * - * @param[in] aAddress The reference of the address. - * - * @retval TRUE If the device has any sleepy children subscribed the address @p aAddress. - * @retval FALSE If the device doesn't have any sleepy children subscribed the address @p aAddress. - * - */ - bool HasSleepyChildrenSubscribed(const Ip6::Address &aAddress); - - /** - * This method returns whether the specific child subscribed the address. - * - * @param[in] aAddress The reference of the address. - * @param[in] aChild The reference of the child. - * - * @retval TRUE If the sleepy child @p aChild subscribed the address @p aAddress. - * @retval FALSE If the sleepy child @p aChild did not subscribe the address @p aAddress. - * - */ - bool IsSleepyChildSubscribed(const Ip6::Address &aAddress, Child &aChild); - /** * This method resets the MLE Advertisement Trickle timer interval. * @@ -706,7 +637,6 @@ private: otError AppendRoute(Message &aMessage); otError AppendActiveDataset(Message &aMessage); otError AppendPendingDataset(Message &aMessage); - void RefreshStoredChildren(void); void HandleDetachStart(void); void HandleChildStart(AttachMode aMode); void HandleLinkRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Neighbor *aNeighbor);