From 6792eb76afb5ef61c815b3617d935ef1c156d097 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 17 May 2021 22:20:40 -0700 Subject: [PATCH] [netdata] add `TlvIterator` and `FindSubTlv()` (#6621) This commit contains the following changes: - It adds `TlvIterator` to help iterate over TLVs of a given type in a given sequence of TLVs or sub-TLVs of another TLV. - It adds helper method `PrefixTlv::FindSubTlv()` to search within the sub-TLVs for a specific one. - It moves the `static` helper methods which find a TLV (with a given type) to `NetworkDataTlv` (from `NetworkData`). --- Android.mk | 1 + src/core/BUILD.gn | 1 + src/core/CMakeLists.txt | 1 + src/core/Makefile.am | 1 + src/core/thread/network_data.cpp | 109 +----- src/core/thread/network_data.hpp | 254 +------------ src/core/thread/network_data_leader.cpp | 33 +- src/core/thread/network_data_leader_ftd.cpp | 61 ++-- src/core/thread/network_data_local.cpp | 2 +- src/core/thread/network_data_service.cpp | 2 +- src/core/thread/network_data_tlvs.cpp | 120 ++++++ src/core/thread/network_data_tlvs.hpp | 386 ++++++++++++++++++-- 12 files changed, 526 insertions(+), 445 deletions(-) create mode 100644 src/core/thread/network_data_tlvs.cpp diff --git a/Android.mk b/Android.mk index 40834bd93..ae3dd9e82 100644 --- a/Android.mk +++ b/Android.mk @@ -320,6 +320,7 @@ LOCAL_SRC_FILES := \ src/core/thread/network_data_local.cpp \ src/core/thread/network_data_notifier.cpp \ src/core/thread/network_data_service.cpp \ + src/core/thread/network_data_tlvs.cpp \ src/core/thread/network_data_types.cpp \ src/core/thread/network_diagnostic.cpp \ src/core/thread/panid_query_server.cpp \ diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 0ce713bb5..1f6ff5924 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -589,6 +589,7 @@ openthread_core_files = [ "thread/network_data_notifier.hpp", "thread/network_data_service.cpp", "thread/network_data_service.hpp", + "thread/network_data_tlvs.cpp", "thread/network_data_tlvs.hpp", "thread/network_data_types.cpp", "thread/network_data_types.hpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 20ad44041..ede7ea51b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -193,6 +193,7 @@ set(COMMON_SOURCES thread/network_data_local.cpp thread/network_data_notifier.cpp thread/network_data_service.cpp + thread/network_data_tlvs.cpp thread/network_data_types.cpp thread/network_diagnostic.cpp thread/panid_query_server.cpp diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 08c05b583..f6156c06b 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -270,6 +270,7 @@ SOURCES_COMMON = \ thread/network_data_local.cpp \ thread/network_data_notifier.cpp \ thread/network_data_service.cpp \ + thread/network_data_tlvs.cpp \ thread/network_data_types.cpp \ thread/network_diagnostic.cpp \ thread/panid_query_server.cpp \ diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 1d5b355a4..b2bb8a252 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -54,52 +54,6 @@ NetworkData::NetworkData(Instance &aInstance, Type aType) mLength = 0; } -void NetworkData::Clear(void) -{ - mLength = 0; -} - -const NetworkDataTlv *NetworkData::FindTlv(const NetworkDataTlv *aStart, - const NetworkDataTlv *aEnd, - NetworkDataTlv::Type aType) -{ - const NetworkDataTlv *tlv; - - for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) - { - if (tlv->GetType() == aType) - { - ExitNow(); - } - } - - tlv = nullptr; - -exit: - return tlv; -} - -const NetworkDataTlv *NetworkData::FindTlv(const NetworkDataTlv *aStart, - const NetworkDataTlv *aEnd, - NetworkDataTlv::Type aType, - bool aStable) -{ - const NetworkDataTlv *tlv; - - for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) - { - if ((tlv->GetType() == aType) && (tlv->IsStable() == aStable)) - { - ExitNow(); - } - } - - tlv = nullptr; - -exit: - return tlv; -} - Error NetworkData::GetNetworkData(bool aStable, uint8_t *aData, uint8_t &aDataLength) const { Error error = kErrorNone; @@ -503,7 +457,7 @@ void NetworkData::RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength, Pref case NetworkDataTlv::kTypeBorderRouter: { BorderRouterTlv *borderRouter = static_cast(cur); - ContextTlv * context = FindContext(aPrefix); + ContextTlv * context = aPrefix.FindSubTlv(); // Replace p_border_router_16 for (BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry(); @@ -587,31 +541,6 @@ void NetworkData::RemoveTemporaryData(uint8_t *aData, uint8_t &aDataLength, Serv } } -const BorderRouterTlv *NetworkData::FindBorderRouter(const PrefixTlv &aPrefix) -{ - return FindTlv(aPrefix.GetSubTlvs(), aPrefix.GetNext()); -} - -const BorderRouterTlv *NetworkData::FindBorderRouter(const PrefixTlv &aPrefix, bool aStable) -{ - return FindTlv(aPrefix.GetSubTlvs(), aPrefix.GetNext(), aStable); -} - -const HasRouteTlv *NetworkData::FindHasRoute(const PrefixTlv &aPrefix) -{ - return FindTlv(aPrefix.GetSubTlvs(), aPrefix.GetNext()); -} - -const HasRouteTlv *NetworkData::FindHasRoute(const PrefixTlv &aPrefix, bool aStable) -{ - return FindTlv(aPrefix.GetSubTlvs(), aPrefix.GetNext(), aStable); -} - -const ContextTlv *NetworkData::FindContext(const PrefixTlv &aPrefix) -{ - return FindTlv(aPrefix.GetSubTlvs(), aPrefix.GetNext()); -} - const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const { return FindPrefix(aPrefix, aPrefixLength, mTlvs, mLength); @@ -622,27 +551,17 @@ const PrefixTlv *NetworkData::FindPrefix(const uint8_t *aPrefix, const uint8_t *aTlvs, uint8_t aTlvsLength) { - const NetworkDataTlv *start = reinterpret_cast(aTlvs); - const NetworkDataTlv *end = reinterpret_cast(aTlvs + aTlvsLength); - const PrefixTlv * prefixTlv; + TlvIterator tlvIterator(aTlvs, aTlvsLength); + const PrefixTlv *prefixTlv; - while (start < end) + while ((prefixTlv = tlvIterator.Iterate()) != nullptr) { - prefixTlv = FindTlv(start, end); - - VerifyOrExit(prefixTlv != nullptr); - if (prefixTlv->IsEqual(aPrefix, aPrefixLength)) { - ExitNow(); + break; } - - start = prefixTlv->GetNext(); } - prefixTlv = nullptr; - -exit: return prefixTlv; } @@ -670,30 +589,20 @@ const ServiceTlv *NetworkData::FindService(uint32_t aEnterpriseNumber, const uint8_t *aTlvs, uint8_t aTlvsLength) { - const NetworkDataTlv *start = reinterpret_cast(aTlvs); - const NetworkDataTlv *end = reinterpret_cast(aTlvs + aTlvsLength); - const ServiceTlv * serviceTlv; + TlvIterator tlvIterator(aTlvs, aTlvsLength); + const ServiceTlv *serviceTlv; - while (start < end) + while ((serviceTlv = tlvIterator.Iterate()) != nullptr) { - serviceTlv = FindTlv(start, end); - - VerifyOrExit(serviceTlv != nullptr); - if ((serviceTlv->GetEnterpriseNumber() == aEnterpriseNumber) && (serviceTlv->GetServiceDataLength() >= aServiceDataLength) && (!aExactServiceDataMatch || (serviceTlv->GetServiceDataLength() == aServiceDataLength)) && (memcmp(serviceTlv->GetServiceData(), aServiceData, aServiceDataLength) == 0)) { - ExitNow(); + break; } - - start = serviceTlv->GetNext(); } - serviceTlv = nullptr; - -exit: return serviceTlv; } diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp index eef3b04a4..8b2029dcf 100644 --- a/src/core/thread/network_data.hpp +++ b/src/core/thread/network_data.hpp @@ -139,7 +139,7 @@ public: * This method clears the network data. * */ - void Clear(void); + void Clear(void) { mLength = 0; } /** * This method provides a full or stable copy of the Thread Network Data. @@ -340,125 +340,6 @@ protected: */ const NetworkDataTlv *GetTlvsEnd(void) const { return reinterpret_cast(mTlvs + mLength); } - /** - * This method returns a pointer to the Border Router TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Border Router TLV if one is found or nullptr if no Border Router TLV exists. - * - */ - static BorderRouterTlv *FindBorderRouter(PrefixTlv &aPrefix) - { - return const_cast(FindBorderRouter(const_cast(aPrefix))); - } - - /** - * This method returns a pointer to the Border Router TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Border Router TLV if one is found or nullptr if no Border Router TLV exists. - * - */ - static const BorderRouterTlv *FindBorderRouter(const PrefixTlv &aPrefix); - - /** - * This method returns a pointer to the stable or non-stable Border Router TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.. - * - * @returns A pointer to the Border Router TLV if one is found or nullptr if no Border Router TLV exists. - * - */ - static BorderRouterTlv *FindBorderRouter(PrefixTlv &aPrefix, bool aStable) - { - return const_cast(FindBorderRouter(const_cast(aPrefix), aStable)); - } - - /** - * This method returns a pointer to the stable or non-stable Border Router TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable.. - * - * @returns A pointer to the Border Router TLV if one is found or nullptr if no Border Router TLV exists. - * - */ - static const BorderRouterTlv *FindBorderRouter(const PrefixTlv &aPrefix, bool aStable); - - /** - * This method returns a pointer to the Has Route TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Has Route TLV if one is found or nullptr if no Has Route TLV exists. - * - */ - static HasRouteTlv *FindHasRoute(PrefixTlv &aPrefix) - { - return const_cast(FindHasRoute(const_cast(aPrefix))); - } - - /** - * This method returns a pointer to the Has Route TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Has Route TLV if one is found or nullptr if no Has Route TLV exists. - * - */ - static const HasRouteTlv *FindHasRoute(const PrefixTlv &aPrefix); - - /** - * This method returns a pointer to the stable or non-stable Has Route TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the Has Route TLV if one is found or nullptr if no Has Route TLV exists. - * - */ - static HasRouteTlv *FindHasRoute(PrefixTlv &aPrefix, bool aStable) - { - return const_cast(FindHasRoute(const_cast(aPrefix), aStable)); - } - - /** - * This method returns a pointer to the stable or non-stable Has Route TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the Has Route TLV if one is found or nullptr if no Has Route TLV exists. - * - */ - static const HasRouteTlv *FindHasRoute(const PrefixTlv &aPrefix, bool aStable); - - /** - * This method returns a pointer to the Context TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Context TLV if one is found or nullptr if no Context TLV exists. - * - */ - static ContextTlv *FindContext(PrefixTlv &aPrefix) - { - return const_cast(FindContext(const_cast(aPrefix))); - } - - /** - * This method returns a pointer to the Context TLV within a given Prefix TLV. - * - * @param[in] aPrefix A reference to the Prefix TLV. - * - * @returns A pointer to the Context TLV if one is found or nullptr if no Context TLV exists. - * - */ - static const ContextTlv *FindContext(const PrefixTlv &aPrefix); - /** * This method returns a pointer to a Prefix TLV. * @@ -710,139 +591,6 @@ protected: */ Error SendServerDataNotification(uint16_t aRloc16, Coap::ResponseHandler aHandler, void *aContext); - /** - * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param[in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aType The TLV type to find. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - static NetworkDataTlv *FindTlv(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, NetworkDataTlv::Type aType) - { - return const_cast( - FindTlv(const_cast(aStart), const_cast(aEnd), aType)); - } - - /** - * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param[in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aType The TLV type to find. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - static const NetworkDataTlv *FindTlv(const NetworkDataTlv *aStart, - const NetworkDataTlv *aEnd, - NetworkDataTlv::Type aType); - - /** - * This static template method searches in a given sequence of TLVs to find the first TLV with a give template - * `TlvType`. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param[in] aEnd A pointer to the end of the sequence of TLVs. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - template static TlvType *FindTlv(NetworkDataTlv *aStart, NetworkDataTlv *aEnd) - { - return static_cast(FindTlv(aStart, aEnd, static_cast(TlvType::kType))); - } - - /** - * This static template method searches in a given sequence of TLVs to find the first TLV with a give template - * `TlvType`. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param[in] aEnd A pointer to the end of the sequence of TLVs. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - template static const TlvType *FindTlv(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd) - { - return static_cast(FindTlv(aStart, aEnd, static_cast(TlvType::kType))); - } - - /** - * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type and stable - * flag. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param [in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aType The TLV type to find. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - static NetworkDataTlv *FindTlv(NetworkDataTlv * aStart, - NetworkDataTlv * aEnd, - NetworkDataTlv::Type aType, - bool aStable) - { - return const_cast(FindTlv(const_cast(aStart), - const_cast(aEnd), aType, aStable)); - } - - /** - * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type and stable - * flag. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param [in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aType The TLV type to find. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - static const NetworkDataTlv *FindTlv(const NetworkDataTlv *aStart, - const NetworkDataTlv *aEnd, - NetworkDataTlv::Type aType, - bool aStable); - - /** - * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type and - * stable flag. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param [in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - template static TlvType *FindTlv(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, bool aStable) - { - return static_cast( - FindTlv(aStart, aEnd, static_cast(TlvType::kType), aStable)); - } - - /** - * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV Type and - * stable flag. - * - * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. - * @param [in] aEnd A pointer to the end of the sequence of TLVs. - * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. - * - * @returns A pointer to the TLV if found, or nullptr if not found. - * - */ - template - static const TlvType *FindTlv(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, bool aStable) - { - return static_cast( - FindTlv(aStart, aEnd, static_cast(TlvType::kType), aStable)); - } - uint8_t mTlvs[kMaxSize]; ///< The Network Data buffer. uint8_t mLength; ///< The number of valid bytes in @var mTlvs. diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 922dfc8ad..f9ea1e79a 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -96,17 +96,16 @@ exit: const PrefixTlv *LeaderBase::FindNextMatchingPrefix(const Ip6::Address &aAddress, const PrefixTlv *aPrevTlv) const { const PrefixTlv *prefixTlv; + TlvIterator tlvIterator((aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(), GetTlvsEnd()); - for (const NetworkDataTlv *start = (aPrevTlv == nullptr) ? GetTlvsStart() : aPrevTlv->GetNext(); - (prefixTlv = FindTlv(start, GetTlvsEnd())) != nullptr; start = prefixTlv->GetNext()) + while ((prefixTlv = tlvIterator.Iterate()) != nullptr) { if (aAddress.MatchesPrefix(prefixTlv->GetPrefix(), prefixTlv->GetPrefixLength())) { - ExitNow(); + break; } } -exit: return prefixTlv; } @@ -126,7 +125,7 @@ Error LeaderBase::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aCon while ((prefix = FindNextMatchingPrefix(aAddress, prefix)) != nullptr) { - contextTlv = FindContext(*prefix); + contextTlv = prefix->FindSubTlv(); if (contextTlv == nullptr) { @@ -147,6 +146,7 @@ Error LeaderBase::GetContext(const Ip6::Address &aAddress, Lowpan::Context &aCon Error LeaderBase::GetContext(uint8_t aContextId, Lowpan::Context &aContext) const { Error error = kErrorNotFound; + TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd()); const PrefixTlv *prefix; if (aContextId == Mle::kMeshLocalPrefixContextId) @@ -157,10 +157,9 @@ Error LeaderBase::GetContext(uint8_t aContextId, Lowpan::Context &aContext) cons ExitNow(error = kErrorNone); } - for (const NetworkDataTlv *start = GetTlvsStart(); (prefix = FindTlv(start, GetTlvsEnd())) != nullptr; - start = prefix->GetNext()) + while ((prefix = tlvIterator.Iterate()) != nullptr) { - const ContextTlv *contextTlv = FindContext(*prefix); + const ContextTlv *contextTlv = prefix->FindSubTlv(); if ((contextTlv == nullptr) || (contextTlv->GetContextId() != aContextId)) { @@ -189,7 +188,7 @@ bool LeaderBase::IsOnMesh(const Ip6::Address &aAddress) const // check both stable and temporary Border Router TLVs for (int i = 0; i < 2; i++) { - const BorderRouterTlv *borderRouter = FindBorderRouter(*prefix, /* aStable */ (i == 0)); + const BorderRouterTlv *borderRouter = prefix->FindSubTlv(/* aStable */ (i == 0)); if (borderRouter == nullptr) { @@ -247,15 +246,16 @@ Error LeaderBase::ExternalRouteLookup(uint8_t aDomainId, uint16_t * aRloc16) const { Error error = kErrorNoRoute; + TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd()); const PrefixTlv * prefixTlv; const HasRouteEntry *bestRouteEntry = nullptr; uint8_t bestMatchLength = 0; - for (const NetworkDataTlv *start = GetTlvsStart(); (prefixTlv = FindTlv(start, GetTlvsEnd())) != nullptr; - start = prefixTlv->GetNext()) + while ((prefixTlv = tlvIterator.Iterate()) != nullptr) { const HasRouteTlv *hasRoute; uint8_t prefixLength = prefixTlv->GetPrefixLength(); + TlvIterator subTlvIterator(*prefixTlv); if (prefixTlv->GetDomainId() != aDomainId) { @@ -272,9 +272,7 @@ Error LeaderBase::ExternalRouteLookup(uint8_t aDomainId, continue; } - for (const NetworkDataTlv *subStart = prefixTlv->GetSubTlvs(); - (hasRoute = FindTlv(subStart, prefixTlv->GetNext())) != nullptr; - subStart = hasRoute->GetNext()) + while ((hasRoute = subTlvIterator.Iterate()) != nullptr) { for (const HasRouteEntry *entry = hasRoute->GetFirstEntry(); entry <= hasRoute->GetLastEntry(); entry = entry->GetNext()) @@ -314,12 +312,11 @@ Error LeaderBase::ExternalRouteLookup(uint8_t aDomainId, Error LeaderBase::DefaultRouteLookup(const PrefixTlv &aPrefix, uint16_t *aRloc16) const { Error error = kErrorNoRoute; + TlvIterator subTlvIterator(aPrefix); const BorderRouterTlv * borderRouter; const BorderRouterEntry *route = nullptr; - for (const NetworkDataTlv *start = aPrefix.GetSubTlvs(); - (borderRouter = FindTlv(start, aPrefix.GetNext())) != nullptr; - start = borderRouter->GetNext()) + while ((borderRouter = subTlvIterator.Iterate()) != nullptr) { for (const BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry(); entry = entry->GetNext()) @@ -421,7 +418,7 @@ exit: const CommissioningDataTlv *LeaderBase::GetCommissioningData(void) const { - return FindTlv(GetTlvsStart(), GetTlvsEnd()); + return NetworkDataTlv::Find(GetTlvsStart(), GetTlvsEnd()); } const MeshCoP::Tlv *LeaderBase::GetCommissioningDataSubTlv(MeshCoP::Tlv::Type aType) const diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index 60f653536..dea0200fc 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -575,7 +575,7 @@ bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const // Check whether `aPrefix` has a Has Route sub-TLV with stable // flag `aStable` containing a matching entry to `aEntry`. - return (aPrefix == nullptr) ? false : ContainsMatchingEntry(FindHasRoute(*aPrefix, aStable), aEntry); + return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv(aStable), aEntry); } bool Leader::ContainsMatchingEntry(const HasRouteTlv *aHasRoute, const HasRouteEntry &aEntry) @@ -604,7 +604,7 @@ bool Leader::ContainsMatchingEntry(const PrefixTlv *aPrefix, bool aStable, const // Check whether `aPrefix` has a Border Router sub-TLV with stable // flag `aStable` containing a matching entry to `aEntry`. - return (aPrefix == nullptr) ? false : ContainsMatchingEntry(FindBorderRouter(*aPrefix, aStable), aEntry); + return (aPrefix == nullptr) ? false : ContainsMatchingEntry(aPrefix->FindSubTlv(aStable), aEntry); } bool Leader::ContainsMatchingEntry(const BorderRouterTlv *aBorderRouter, const BorderRouterEntry &aEntry) @@ -634,22 +634,23 @@ bool Leader::ContainsMatchingServer(const ServiceTlv *aService, const ServerTlv // Check whether the `aService` has a matching Server sub-TLV // same as `aServer`. - bool contains = false; - const ServerTlv *server; + bool contains = false; - VerifyOrExit(aService != nullptr); - - for (const NetworkDataTlv *start = aService->GetSubTlvs(); - (server = FindTlv(start, aService->GetNext(), aServer.IsStable())) != nullptr; - start = server->GetNext()) + if (aService != nullptr) { - if (*server == aServer) + const ServerTlv *server; + TlvIterator subTlvIterator(*aService); + + while ((server = subTlvIterator.Iterate(aServer.IsStable())) != nullptr) { - ExitNow(contains = true); + if (*server == aServer) + { + contains = true; + break; + } } } -exit: return contains; } @@ -804,7 +805,7 @@ Error Leader::AddService(const ServiceTlv &aService, ChangedFlags &aChangedFlags aService.GetServiceDataLength()); } - server = FindTlv(aService.GetSubTlvs(), aService.GetNext()); + server = NetworkDataTlv::Find(aService.GetSubTlvs(), aService.GetNext()); OT_ASSERT(server != nullptr); SuccessOrExit(error = AddServer(*server, *dstService, aChangedFlags)); @@ -827,7 +828,7 @@ exit: Error Leader::AddHasRoute(const HasRouteTlv &aHasRoute, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags) { Error error = kErrorNone; - HasRouteTlv * dstHasRoute = FindHasRoute(aDstPrefix, aHasRoute.IsStable()); + HasRouteTlv * dstHasRoute = aDstPrefix.FindSubTlv(aHasRoute.IsStable()); const HasRouteEntry *entry = aHasRoute.GetFirstEntry(); if (dstHasRoute == nullptr) @@ -864,8 +865,8 @@ exit: Error Leader::AddBorderRouter(const BorderRouterTlv &aBorderRouter, PrefixTlv &aDstPrefix, ChangedFlags &aChangedFlags) { Error error = kErrorNone; - BorderRouterTlv * dstBorderRouter = FindBorderRouter(aDstPrefix, aBorderRouter.IsStable()); - ContextTlv * dstContext = FindContext(aDstPrefix); + BorderRouterTlv * dstBorderRouter = aDstPrefix.FindSubTlv(aBorderRouter.IsStable()); + ContextTlv * dstContext = aDstPrefix.FindSubTlv(); uint8_t contextId = 0; const BorderRouterEntry *entry = aBorderRouter.GetFirstEntry(); @@ -976,20 +977,17 @@ Error Leader::AllocateServiceId(uint8_t &aServiceId) const const ServiceTlv *Leader::FindServiceById(uint8_t aServiceId) const { - const NetworkDataTlv *start = GetTlvsStart(); - const ServiceTlv * service; + const ServiceTlv *service; + TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd()); - while ((service = FindTlv(start, GetTlvsEnd())) != nullptr) + while ((service = tlvIterator.Iterate()) != nullptr) { if (service->GetServiceId() == aServiceId) { - ExitNow(); + break; } - - start = service->GetNext(); } -exit: return service; } @@ -1154,7 +1152,7 @@ void Leader::RemoveRlocInPrefix(PrefixTlv & aPrefix, cur = cur->GetNext(); } - if ((context = FindContext(aPrefix)) != nullptr) + if ((context = aPrefix.FindSubTlv()) != nullptr) { if (aPrefix.GetSubTlvsLength() == sizeof(ContextTlv)) { @@ -1181,7 +1179,7 @@ void Leader::RemoveRlocInService(ServiceTlv & aService, NetworkDataTlv *start = aService.GetSubTlvs(); ServerTlv * server; - while ((server = FindTlv(start, aService.GetNext())) != nullptr) + while ((server = NetworkDataTlv::Find(start, aService.GetNext())) != nullptr) { if (RlocMatch(server->GetServer16(), aRloc16, aMatchMode) && !ContainsMatchingServer(aExcludeService, *server)) { @@ -1260,7 +1258,7 @@ void Leader::RemoveContext(uint8_t aContextId) NetworkDataTlv *start = GetTlvsStart(); PrefixTlv * prefix; - while ((prefix = FindTlv(start, GetTlvsEnd())) != nullptr) + while ((prefix = NetworkDataTlv::Find(start, GetTlvsEnd())) != nullptr) { RemoveContext(*prefix, aContextId); @@ -1279,7 +1277,7 @@ void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId) NetworkDataTlv *start = aPrefix.GetSubTlvs(); ContextTlv * context; - while ((context = FindTlv(start, aPrefix.GetNext())) != nullptr) + while ((context = NetworkDataTlv::Find(start, aPrefix.GetNext())) != nullptr) { if (context->GetContextId() == aContextId) { @@ -1295,13 +1293,12 @@ void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId) void Leader::UpdateContextsAfterReset(void) { - NetworkDataTlv *start; - PrefixTlv * prefix; + const PrefixTlv *prefix; + TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd()); - for (start = GetTlvsStart(); (prefix = FindTlv(start, GetTlvsEnd())) != nullptr; - start = prefix->GetNext()) + while ((prefix = tlvIterator.Iterate()) != nullptr) { - ContextTlv *context = FindContext(*prefix); + const ContextTlv *context = prefix->FindSubTlv(); if (context == nullptr) { diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp index d6bda8b43..106964d71 100644 --- a/src/core/thread/network_data_local.cpp +++ b/src/core/thread/network_data_local.cpp @@ -143,7 +143,7 @@ Error Local::RemovePrefix(const Ip6::Prefix &aPrefix, NetworkDataTlv::Type aSubT PrefixTlv *tlv; VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr, error = kErrorNotFound); - VerifyOrExit(FindTlv(tlv->GetSubTlvs(), tlv->GetNext(), aSubTlvType) != nullptr, error = kErrorNotFound); + VerifyOrExit(tlv->FindSubTlv(aSubTlvType) != nullptr, error = kErrorNotFound); RemoveTlv(tlv); exit: diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 37c8d1187..e1493dd19 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -255,7 +255,7 @@ Error Manager::IterateToNextServer(Iterator &aIterator) const VerifyOrExit(aIterator.mServiceTlv != nullptr); - aIterator.mServerSubTlv = NetworkData::FindTlv( + aIterator.mServerSubTlv = NetworkDataTlv::Find( /* aStart */ (aIterator.mServerSubTlv != nullptr) ? aIterator.mServerSubTlv->GetNext() : aIterator.mServiceTlv->GetSubTlvs(), /* aEnd */ aIterator.mServiceTlv->GetNext()); diff --git a/src/core/thread/network_data_tlvs.cpp b/src/core/thread/network_data_tlvs.cpp new file mode 100644 index 000000000..d8c44b266 --- /dev/null +++ b/src/core/thread/network_data_tlvs.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016-21, 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 implements methods for generating and processing Thread Network Data TLVs. + */ + +#include "network_data_tlvs.hpp" + +namespace ot { +namespace NetworkData { + +//--------------------------------------------------------------------------------------------------------------------- +// NetworkDataTlv + +const NetworkDataTlv *NetworkDataTlv::Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, Type aType) +{ + const NetworkDataTlv *tlv; + + for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) + { + if (tlv->GetType() == aType) + { + ExitNow(); + } + } + + tlv = nullptr; + +exit: + return tlv; +} + +const NetworkDataTlv *NetworkDataTlv::Find(const NetworkDataTlv *aStart, + const NetworkDataTlv *aEnd, + Type aType, + bool aStable) +{ + const NetworkDataTlv *tlv; + + for (tlv = aStart; (tlv + 1 <= aEnd) && (tlv->GetNext() <= aEnd); tlv = tlv->GetNext()) + { + if ((tlv->GetType() == aType) && (tlv->IsStable() == aStable)) + { + ExitNow(); + } + } + + tlv = nullptr; + +exit: + return tlv; +} + +//--------------------------------------------------------------------------------------------------------------------- +// PrefixTlv + +const NetworkDataTlv *PrefixTlv::FindSubTlv(Type aType) const +{ + return Find(GetSubTlvs(), GetNext(), aType); +} + +const NetworkDataTlv *PrefixTlv::FindSubTlv(Type aType, bool aStable) const +{ + return Find(GetSubTlvs(), GetNext(), aType, aStable); +} + +//--------------------------------------------------------------------------------------------------------------------- +// TlvIterator + +const NetworkDataTlv *TlvIterator::Iterate(NetworkDataTlv::Type aType) +{ + const NetworkDataTlv *tlv = NetworkDataTlv::Find(mStart, mEnd, aType); + + VerifyOrExit(tlv != nullptr); + mStart = tlv->GetNext(); + +exit: + return tlv; +} + +const NetworkDataTlv *TlvIterator::Iterate(NetworkDataTlv::Type aType, bool aStable) +{ + const NetworkDataTlv *tlv = NetworkDataTlv::Find(mStart, mEnd, aType, aStable); + + VerifyOrExit(tlv != nullptr); + mStart = tlv->GetNext(); + +exit: + return tlv; +} + +} // namespace NetworkData +} // namespace ot diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index a10cb583a..a7e4917b5 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -68,21 +68,11 @@ OT_TOOL_PACKED_BEGIN class NetworkDataTlv { public: - /** - * This method initializes TLV. - * - */ - void Init(void) - { - mType = 0; - mLength = 0; - } - /** * Thread Network Data Type values. * */ - enum Type + enum Type : uint8_t { kTypeHasRoute = 0, ///< Has Route TLV kTypePrefix = 1, ///< Prefix TLV @@ -93,6 +83,16 @@ public: kTypeServer = 6, ///< Server TLV }; + /** + * This method initializes the TLV. + * + */ + void Init(void) + { + mType = 0; + mLength = 0; + } + /** * This method returns the Type value. * @@ -209,6 +209,138 @@ public: */ void SetStable(void) { mType |= kStableMask; } + /** + * This static method searches in a given sequence of TLVs to find the first TLV with a given type. + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aType The TLV type to find. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + static NetworkDataTlv *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, Type aType) + { + return const_cast( + Find(const_cast(aStart), const_cast(aEnd), aType)); + } + + /** + * This static method searches in a given sequence of TLVs to find the first TLV with a given type. + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aType The TLV type to find. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + static const NetworkDataTlv *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, Type aType); + + /** + * This template static method searches in a given sequence of TLVs to find the first TLV with a given type. + * + * @tparam TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template static TlvType *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd) + { + return static_cast(Find(aStart, aEnd, TlvType::kType)); + } + + /** + * This template static method searches in a given sequence of TLVs to find the first TLV with a given type. + * + * @tparam TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template static const TlvType *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd) + { + return static_cast(Find(aStart, aEnd, TlvType::kType)); + } + + /** + * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and stable + * flag. + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aType The TLV type to find. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + static NetworkDataTlv *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, Type aType, bool aStable) + { + return const_cast( + Find(const_cast(aStart), const_cast(aEnd), aType, aStable)); + } + + /** + * This static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and stable + * flag. + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aType The TLV type to find. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + static const NetworkDataTlv *Find(const NetworkDataTlv *aStart, + const NetworkDataTlv *aEnd, + Type aType, + bool aStable); + + /** + * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and + * stable flag. + * + * @tparam TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template static TlvType *Find(NetworkDataTlv *aStart, NetworkDataTlv *aEnd, bool aStable) + { + return static_cast(Find(aStart, aEnd, TlvType::kType, aStable)); + } + + /** + * This template static method searches in a given sequence of TLVs to find the first TLV with a given TLV type and + * stable flag. + * + * @tparam TlvType The TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStart A pointer to the start of the sequence of TLVs to search within. + * @param[in] aEnd A pointer to the end of the sequence of TLVs. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template + static const TlvType *Find(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd, bool aStable) + { + return static_cast(Find(aStart, aEnd, TlvType::kType, aStable)); + } + private: enum { @@ -324,10 +456,7 @@ OT_TOOL_PACKED_BEGIN class HasRouteTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeHasRoute, ///< The TLV Type. - }; + static constexpr Type kType = kTypeHasRoute; ///< The TLV Type. /** * This method initializes the TLV. @@ -426,10 +555,7 @@ OT_TOOL_PACKED_BEGIN class PrefixTlv : public NetworkDataTlv { public: - enum - { - kType = kTypePrefix, ///< The TLV Type. - }; + static constexpr Type kType = kTypePrefix; ///< The TLV Type. /** * This method initializes the TLV. @@ -533,7 +659,7 @@ public: * @param[in] aPrefixLength The prefix length pointed to by @p aPrefix (in bits). * * @retval TRUE The TLV's Prefix is equal to @p aPrefix. - * @retval FALSE The TLV's Prefix is not euqal @p aPrefix. + * @retval FALSE The TLV's Prefix is not equal @p aPrefix. * */ bool IsEqual(const uint8_t *aPrefix, uint8_t aPrefixLength) const @@ -587,6 +713,110 @@ public: SetLength(sizeof(*this) - sizeof(NetworkDataTlv) + Ip6::Prefix::SizeForLength(mPrefixLength) + aLength); } + /** + * This template method searches in the sub-TLVs to find the first one matching a given TLV type. + * + * @tparam SubTlvType The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template SubTlvType *FindSubTlv(void) + { + return static_cast(FindSubTlv(SubTlvType::kType)); + } + + /** + * This template method searches in the sub-TLVs to find the first one matching a given TLV Type. + * + * @tparam SubTlvType The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template const SubTlvType *FindSubTlv(void) const + { + return static_cast(FindSubTlv(SubTlvType::kType)); + } + + /** + * This template method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag. + * + * @tparam SubTlvType The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template SubTlvType *FindSubTlv(bool aStable) + { + return static_cast(FindSubTlv(static_cast(SubTlvType::kType), aStable)); + } + + /** + * This template method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag. + * + * @tparam SubTlvType The sub-TLV type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + template const SubTlvType *FindSubTlv(bool aStable) const + { + return static_cast(FindSubTlv(static_cast(SubTlvType::kType), aStable)); + } + + /** + * This method searches in the sub-TLVs to find the first one matching a given TLV type. + * + * @param[in] aType The sub-TLV type to search for. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + NetworkDataTlv *FindSubTlv(Type aType) + { + return const_cast(const_cast(this)->FindSubTlv(aType)); + } + + /** + * This method searches in the sub-TLVs to find the first one matching a given TLV type. + * + * @param[in] aType The sub-TLV type to search for. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + const NetworkDataTlv *FindSubTlv(Type aType) const; + + /** + * This method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag. + * + * @param[in] aType The sub-TLV type to search for. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + NetworkDataTlv *FindSubTlv(Type aType, bool aStable) + { + return const_cast(const_cast(this)->FindSubTlv(aType, aStable)); + } + + /** + * This method searches in the sub-TLVs to find the first one matching a given TLV type and stable flag. + * + * @param[in] aType The sub-TLV type to search for. + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the TLV if found, or nullptr if not found. + * + */ + const NetworkDataTlv *FindSubTlv(Type aType, bool aStable) const; + /** * This static method calculates the total size (number of bytes) of a Prefix TLV with a given Prefix Length value. * @@ -789,10 +1019,7 @@ OT_TOOL_PACKED_BEGIN class BorderRouterTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeBorderRouter, ///< The TLV Type. - }; + static constexpr Type kType = kTypeBorderRouter; ///< The TLV Type. /** * This method initializes the TLV. @@ -894,10 +1121,7 @@ OT_TOOL_PACKED_BEGIN class ContextTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeContext, ///< The TLV Type. - }; + static constexpr Type kType = kTypeContext; ///< The TLV Type. /** * This method initializes the Context TLV. @@ -971,10 +1195,7 @@ OT_TOOL_PACKED_BEGIN class CommissioningDataTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeCommissioningData, ///< The TLV Type. - }; + static constexpr Type kType = kTypeCommissioningData; ///< The TLV Type. /** * This method initializes the TLV. @@ -996,10 +1217,7 @@ OT_TOOL_PACKED_BEGIN class ServiceTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeService, ///< The TLV Type. - }; + static constexpr Type kType = kTypeService; ///< The TLV Type. enum : uint32_t { @@ -1205,10 +1423,7 @@ OT_TOOL_PACKED_BEGIN class ServerTlv : public NetworkDataTlv { public: - enum - { - kType = kTypeServer, ///< The TLV Type. - }; + static constexpr Type kType = kTypeServer; ///< The TLV Type. /** * This method initializes the Server TLV. @@ -1298,6 +1513,97 @@ private: uint16_t mServer16; } OT_TOOL_PACKED_END; +/** + * This class represents a Network Data TLV iterator. + * + */ +class TlvIterator +{ +public: + /** + * This constructor initializes the `TlvIterator` to iterate over a given sequence of TLVs. + * + * @param[in] aStart A pointer to the start of the TLV sequence. + * @param[in] aEnd A pointer to the end of the TLV sequence. + * + */ + TlvIterator(const NetworkDataTlv *aStart, const NetworkDataTlv *aEnd) + : mStart(aStart) + , mEnd(aEnd) + { + } + + /** + * This constructor initializes the `TlvIterator` to iterate over TLVs from a given buffer. + * + * @param[in] aBuffer A pointer to a buffer containing the TLVs. + * @param[in] aLength The length (number of bytes) of @p aBuffer. + * + */ + TlvIterator(const uint8_t *aBuffer, uint8_t aLength) + : TlvIterator(reinterpret_cast(aBuffer), + reinterpret_cast(aBuffer + aLength)) + { + } + + /** + * This constructor initializes the `TlvIterator` to iterate over sub-TLVs of a given Prefix TLV. + * + * @param[in] aPrefixTlv A Prefix TLV to iterate over its sub-TLVs. + * + */ + explicit TlvIterator(const PrefixTlv &aPrefixTlv) + : TlvIterator(aPrefixTlv.GetSubTlvs(), aPrefixTlv.GetNext()) + { + } + + /** + * This constructor initializes the `TlvIterator` to iterate over sub-TLVs of a given Service TLV. + * + * @param[in] aServiceTlv A Service TLV to iterate over its sub-TLVs. + * + */ + explicit TlvIterator(const ServiceTlv &aServiceTlv) + : TlvIterator(aServiceTlv.GetSubTlvs(), aServiceTlv.GetNext()) + { + } + + /** + * This template method iterates to the next TLV with a given type. + * + * @tparam TlvType The TLV Type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @returns A pointer to the next TLV, or nullptr if it can not be found. + * + */ + template const TlvType *Iterate(void) + { + return static_cast(Iterate(TlvType::kType)); + } + + /** + * This template method iterates to the next TLV with a given type and stable flag. + * + * @tparam TlvType The TLV Type to search for (MUST be a sub-class of `NetworkDataTlv`). + * + * @param[in] aStable TRUE to find a stable TLV, FALSE to find a TLV not marked as stable. + * + * @returns A pointer to the next TLV, or nullptr if it can not be found. + * + */ + template const TlvType *Iterate(bool aStable) + { + return static_cast(Iterate(TlvType::kType, aStable)); + } + +private: + const NetworkDataTlv *Iterate(NetworkDataTlv::Type aType); + const NetworkDataTlv *Iterate(NetworkDataTlv::Type aType, bool aStable); + + const NetworkDataTlv *mStart; + const NetworkDataTlv *mEnd; +}; + /** * @} *