From b2a845947e009e603c16820819a0b9eef72edce1 Mon Sep 17 00:00:00 2001 From: Rongli Sun Date: Sun, 16 Feb 2020 20:08:32 +0800 Subject: [PATCH] [network-data] deregister for invalid child on new network data (#4485) --- src/core/thread/mle_router.cpp | 18 ++++++ src/core/thread/network_data.cpp | 104 +++++++++++++++++++++++++++++++ src/core/thread/network_data.hpp | 12 ++++ 3 files changed, 134 insertions(+) diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index fc666f944..8bd220f0e 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2606,6 +2606,24 @@ void MleRouter::HandleNetworkDataUpdateRouter(void) SynchronizeChildNetworkData(); + // Detect if any server entry with invalid child RLOC16 + { + NetworkData::Iterator iterator = NetworkData::kIteratorInit; + uint16_t rloc16 = Mac::kShortAddrInvalid; + + while (Get().GetNextServer(iterator, rloc16) == OT_ERROR_NONE) + { + if (!IsActiveRouter(rloc16) && RouterIdMatch(GetRloc16(), rloc16) && + mChildTable.FindChild(rloc16, Child::kInStateValid) == NULL) + { + Get().SendServerDataNotification(rloc16); + // In Thread 1.1 Specification 5.15.6.1, only one RLOC16 TLV entry may appear in SRV_DATA.ntf. + // So break here. + break; + } + } + } + exit: return; } diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 36098812d..12d6cc82f 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -1036,6 +1036,110 @@ exit: return error; } +otError NetworkData::GetNextServer(Iterator &aIterator, uint16_t &aRloc16) +{ + otError error = OT_ERROR_NOT_FOUND; + NetworkDataIterator iterator(aIterator); + NetworkDataTlv * cur = reinterpret_cast(mTlvs + iterator.GetTlvOffset()); + NetworkDataTlv * end = reinterpret_cast(mTlvs + mLength); + + for (; cur < end; cur = cur->GetNext(), iterator.SetSubTlvOffset(0), iterator.SetEntryIndex(0)) + { + NetworkDataTlv *subCur; + NetworkDataTlv *subEnd; + + VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end, error = OT_ERROR_PARSE); + + switch (cur->GetType()) + { + case NetworkDataTlv::kTypePrefix: + { + PrefixTlv *prefix = static_cast(cur); + subCur = reinterpret_cast(reinterpret_cast(prefix->GetSubTlvs()) + + iterator.GetSubTlvOffset()); + subEnd = cur->GetNext(); + + for (; subCur < subEnd; subCur = subCur->GetNext(), iterator.SetEntryIndex(0)) + { + VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd, error = OT_ERROR_PARSE); + + if (subCur->GetType() == NetworkDataTlv::kTypeBorderRouter) + { + BorderRouterTlv *borderRouter = static_cast(subCur); + uint8_t index = iterator.GetEntryIndex(); + + if (index < borderRouter->GetNumEntries()) + { + aRloc16 = borderRouter->GetEntry(index)->GetRloc(); + + iterator.SaveTlvOffset(cur, mTlvs); + iterator.SaveSubTlvOffset(subCur, prefix->GetSubTlvs()); + iterator.SetEntryIndex(index + 1); + + ExitNow(error = OT_ERROR_NONE); + } + } + else if (subCur->GetType() == NetworkDataTlv::kTypeHasRoute) + { + HasRouteTlv *hasRoute = static_cast(subCur); + uint8_t index = iterator.GetEntryIndex(); + + if (index < hasRoute->GetNumEntries()) + { + aRloc16 = hasRoute->GetEntry(index)->GetRloc(); + + iterator.SaveTlvOffset(cur, mTlvs); + iterator.SaveSubTlvOffset(subCur, prefix->GetSubTlvs()); + iterator.SetEntryIndex(index + 1); + + ExitNow(error = OT_ERROR_NONE); + } + } + } + + break; + } + case NetworkDataTlv::kTypeService: + { + ServiceTlv *service = static_cast(cur); + subCur = reinterpret_cast(reinterpret_cast(service->GetSubTlvs()) + + iterator.GetSubTlvOffset()); + subEnd = cur->GetNext(); + + for (; subCur < subEnd; subCur = subCur->GetNext()) + { + VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd, error = OT_ERROR_PARSE); + + if (subCur->GetType() == NetworkDataTlv::kTypeServer) + { + ServerTlv *server = static_cast(subCur); + aRloc16 = server->GetServer16(); + + if (subCur->GetNext() >= cur->GetNext()) + { + iterator.SaveTlvOffset(cur->GetNext(), mTlvs); + iterator.SetSubTlvOffset(0); + } + else + { + iterator.SaveTlvOffset(cur, mTlvs); + iterator.SaveSubTlvOffset(subCur->GetNext(), service->GetSubTlvs()); + } + + ExitNow(error = OT_ERROR_NONE); + } + } + break; + } + default: + break; + } + } + +exit: + return error; +} + void NetworkData::ClearResubmitDelayTimer(void) { mLastAttempt.SetValue(0); diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp index 2bde55049..57f6f3871 100644 --- a/src/core/thread/network_data.hpp +++ b/src/core/thread/network_data.hpp @@ -304,6 +304,18 @@ public: */ bool ContainsService(uint8_t aServiceId, uint16_t aRloc16); + /** + * This method provides the next server RLOC16 in the Thread Network Data. + * + * @param[inout] aIterator A reference to the Network Data iterator. + * @param[out] aRloc16 The RLOC16 value. + * + * @retval OT_ERROR_NONE Successfully found the next server. + * @retval OT_ERROR_NOT_FOUND No subsequent server exists in the Thread Network Data. + * + */ + otError GetNextServer(Iterator &aIterator, uint16_t &aRloc16); + /** * This method cancels the data resubmit delay timer. *