From 181405efc9bc789bd4f93315c01fde098568d1ac Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 14 May 2026 11:17:37 -0700 Subject: [PATCH] [mle] introduce `RouteTlv::Data` to represent parsed Route TLV (#13098) This commit introduces a new model for handling `RouteTlv` by adding the `RouteTlv::Data` and `RouteTlv::Data::Entry` classes. Previously, `RouteTlv` directly represented the packed on-wire format, which made it difficult to work with, especially when supporting different configurations such as `OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE`. The new `RouteTlv::Data` class decouples the on-wire serialization from the in-memory representation, providing a cleaner API for parsing the TLV from a `Message` and accessing its entries and their properties (Router ID, Route Cost, and Link Qualities). This change improves code clarity and maintainability by providing a structured way to handle route information. --- src/core/thread/mle.cpp | 13 +- src/core/thread/mle.hpp | 8 +- src/core/thread/mle_ftd.cpp | 107 ++++---- src/core/thread/mle_tlvs.cpp | 83 +++++- src/core/thread/mle_tlvs.hpp | 265 ++++++++++---------- src/core/thread/network_diagnostic.cpp | 33 ++- src/core/thread/network_diagnostic.hpp | 2 + src/core/thread/network_diagnostic_tlvs.cpp | 15 ++ src/core/thread/network_diagnostic_tlvs.hpp | 18 +- src/core/thread/router_table.cpp | 105 ++++---- src/core/thread/router_table.hpp | 31 ++- src/core/utils/mesh_diag.cpp | 16 +- 12 files changed, 381 insertions(+), 315 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 89a242a08..198517dec 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -4252,16 +4252,19 @@ exit: #endif #if OPENTHREAD_FTD -Error Mle::RxMessage::ReadRouteTlv(RouteTlv &aRouteTlv) const -{ - Error error; - SuccessOrExit(error = Tlv::FindTlv(*this, aRouteTlv)); - VerifyOrExit(aRouteTlv.IsValid(), error = kErrorParse); +Error Mle::RxMessage::ReadRouteTlv(RouteTlv::Data &aRouteTlvData) const +{ + Error error; + OffsetRange offsetRange; + + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(*this, RouteTlv::kType, offsetRange)); + error = aRouteTlvData.ParseFrom(*this, offsetRange); exit: return error; } + #endif //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 088cd2c1c..981ea194e 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1642,7 +1642,7 @@ private: Error ReadCslClockAccuracyTlv(Mac::CslAccuracy &aCslAccuracy) const; #endif #if OPENTHREAD_FTD - Error ReadRouteTlv(RouteTlv &aRouteTlv) const; + Error ReadRouteTlv(RouteTlv::Data &aRouteTlvData) const; #endif private: @@ -2243,7 +2243,7 @@ private: bool IsRouterCountBelowUpgradeThreshold(void) const; void HandleTimeTick(void); void DecideWhetherToUpgrade(void); - void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv); + void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData); #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE void SetCcmEnabled(bool aEnabled); void SetThreadVersionCheckEnabled(bool aEnabled); @@ -2251,7 +2251,7 @@ private: private: bool DetermineIfRouterRoleAllowed(void) const; - bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const; + bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData) const; bool mRouterEligible : 1; bool mRouterRoleAllowed : 1; @@ -2466,7 +2466,7 @@ private: void HandleNetworkDataUpdateRouter(void); void HandleDiscoveryRequest(RxInfo &aRxInfo); void EstablishRouterLinkOnFtdChild(Router &aRouter, RxInfo &aRxInfo, uint8_t aLinkMargin); - Error ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo); + Error ProcessRouteTlv(const RouteTlv::Data &aRouteTlvData, RxInfo &aRxInfo); Error ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId); void StopAdvertiseTrickleTimer(void); uint32_t DetermineAdvertiseIntervalMax(void) const; diff --git a/src/core/thread/mle_ftd.cpp b/src/core/thread/mle_ftd.cpp index 920f84941..b72d3e9de 100644 --- a/src/core/thread/mle_ftd.cpp +++ b/src/core/thread/mle_ftd.cpp @@ -899,7 +899,7 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType) uint32_t mleFrameCounter; uint8_t routerId; uint16_t address16; - RouteTlv routeTlv; + RouteTlv::Data routeTlvData; LeaderData leaderData; uint8_t linkMargin; bool shouldUpdateRoutes = false; @@ -969,8 +969,8 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType) SetLeaderData(leaderData); mRouterTable.Clear(); - SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv)); - SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); + SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlvData)); + SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo)); router = mRouterTable.FindRouterById(routerId); VerifyOrExit(router != nullptr); @@ -1010,14 +1010,14 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType) IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr())); } - switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData)) { case kErrorNone: - VerifyOrExit(routeTlv.IsRouterIdSet(routerId), error = kErrorParse); + VerifyOrExit(routeTlvData.IsAllocated(routerId), error = kErrorParse); - if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv)) + if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlvData)) { - SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); + SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo)); router = mRouterTable.FindRouterById(routerId); OT_ASSERT(router != nullptr); } @@ -1061,7 +1061,7 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType) if (shouldUpdateRoutes) { - mRouterTable.UpdateRoutes(routeTlv, routerId); + mRouterTable.UpdateRoutes(routeTlvData, routerId); } aRxInfo.mClass = RxInfo::kAuthoritativeMessage; @@ -1093,9 +1093,9 @@ exit: LogProcessError(aMessageType, error); } -Error Mle::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo) +Error Mle::ProcessRouteTlv(const RouteTlv::Data &aRouteTlvData, RxInfo &aRxInfo) { - // This method processes `aRouteTlv` read from an MLE message. + // This method processes `aRouteTlvData` read from an MLE message. // // During processing of Route TLV, the entries in the router table // may shuffle. This method ensures that the `aRxInfo.mNeighbor` @@ -1112,7 +1112,7 @@ Error Mle::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo) neighborRloc16 = aRxInfo.mNeighbor->GetRloc16(); } - mRouterTable.UpdateRouterIdMask(aRouteTlv.GetRouterIdMask()); + mRouterTable.UpdateRouterIdMask(aRouteTlvData); if (IsAttached() && !mRouterTable.IsAllocated(RouterIdFromRloc16(GetRloc16()))) { @@ -1141,16 +1141,16 @@ Error Mle::ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId) // It MUST be used only when device is acting as a child and // for a message received from device's current parent. - Error error = kErrorNone; - RouteTlv routeTlv; + Error error = kErrorNone; + RouteTlv::Data routeTlvData; VerifyOrExit(IsFullThreadDevice()); - switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData)) { case kErrorNone: - SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); - mRouterTable.UpdateRouterOnFtdChild(routeTlv, aParentId); + SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo)); + mRouterTable.UpdateRouterOnFtdChild(routeTlvData, aParentId); mRequestRouteTlv = false; break; case kErrorNotFound: @@ -1204,19 +1204,20 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co // - `aSourceAddress` is the read value from `SourceAddressTlv`. // - `aLeaderData` is the read value from `LeaderDataTlv`. - Error error = kErrorNone; - uint8_t linkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); - RouteTlv routeTlv; - Router *router; - uint8_t routerId; - uint32_t delay; + Error error = kErrorNone; + uint8_t linkMargin = Get().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss()); + RouteTlv::Data routeTlvData; + bool hasRouteTlv = false; + Router *router; + uint8_t routerId; + uint32_t delay; - switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlvData)) { case kErrorNone: + hasRouteTlv = true; break; case kErrorNotFound: - routeTlv.SetLength(0); // Mark that a Route TLV was not included. break; default: ExitNow(error = kErrorParse); @@ -1232,11 +1233,11 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co VerifyOrExit(linkMargin >= kPartitionMergeMinMargin, error = kErrorLinkMarginLow); - if (routeTlv.IsValid() && (mPreviousPartitionIdTimeout > 0) && - (aLeaderData.GetPartitionId() == mPreviousPartitionId)) + if (hasRouteTlv && (mPreviousPartitionIdTimeout > 0) && (aLeaderData.GetPartitionId() == mPreviousPartitionId)) { - VerifyOrExit(SerialNumber::IsGreater(routeTlv.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence), - error = kErrorDrop); + VerifyOrExit( + SerialNumber::IsGreater(routeTlvData.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence), + error = kErrorDrop); } if (IsChild() && (aRxInfo.mNeighbor == &mParent)) @@ -1244,7 +1245,8 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co ExitNow(); } - if (ComparePartitions(routeTlv.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0 + if (hasRouteTlv && + ComparePartitions(routeTlvData.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0 #if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED // Allow a better partition if it also enables time sync. && aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ @@ -1274,7 +1276,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co ExitNow(); } - VerifyOrExit(IsRouterRloc16(aSourceAddress) && routeTlv.IsValid()); + VerifyOrExit(IsRouterRloc16(aSourceAddress) && hasRouteTlv); routerId = RouterIdFromRloc16(aSourceAddress); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE @@ -1284,9 +1286,9 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Process `RouteTlv` - if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv)) + if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlvData)) { - SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); + SuccessOrExit(error = ProcessRouteTlv(routeTlvData, aRxInfo)); } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1305,7 +1307,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co ExitNow(error = kErrorDetached); } - mRouterTable.UpdateRouterOnFtdChild(routeTlv, routerId); + mRouterTable.UpdateRouterOnFtdChild(routeTlvData, routerId); mRoleTransitioner.DecideWhetherToUpgrade(); } @@ -1330,7 +1332,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Inform `RoleTransitioner` to decide whether we need to downgrade - mRoleTransitioner.DecideWhetherToDowngrade(routerId, routeTlv); + mRoleTransitioner.DecideWhetherToDowngrade(routerId, routeTlvData); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Update routers as a router or leader. @@ -1359,7 +1361,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co // unicast/multicast link request in progress if (!router->IsStateValid() && !router->IsStateLinkRequest() && (linkMargin >= kLinkRequestMinMargin) && - routeTlv.IsRouterIdSet(mRouterId)) + routeTlvData.IsAllocated(mRouterId)) { InitNeighbor(*router, aRxInfo); router->SetState(Neighbor::kStateLinkRequest); @@ -1371,7 +1373,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co router->SetLastHeard(TimerMilli::GetNow()); - mRouterTable.UpdateRoutes(routeTlv, routerId); + mRouterTable.UpdateRoutes(routeTlvData, routerId); exit: if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != aSourceAddress) @@ -3724,11 +3726,11 @@ void Mle::FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const aTlvValue.InitFrom(connectivity); } -void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) +void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv::Data &aRouteTlvData) { // Determine whether all conditions are satisfied for the router // to downgrade after receiving info for a neighboring router - // with Router ID `aNeighborId` along with its `aRouteTlv`. + // with Router ID `aNeighborId` along with its `aRouteTlvData`. uint8_t activeRouterCount = Get().GetActiveRouterCount(); uint8_t count; @@ -3773,7 +3775,7 @@ void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const // Check that the neighbor has as good or better-quality links to // same routers. - VerifyOrExit(NeighborHasComparableConnectivity(aNeighborId, aRouteTlv)); + VerifyOrExit(NeighborHasComparableConnectivity(aNeighborId, aRouteTlvData)); #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE // Check if we are eligible to be router due to being a BR. @@ -3787,21 +3789,22 @@ exit: return; } -bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const +bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborId, + const RouteTlv::Data &aRouteTlvData) const { // Check whether the neighboring router with Router ID `aNeighborId` - // (along with its `aRouteTlv`) has as good or better-quality links - // to all our neighboring routers which have a two-way link quality - // of two or better. + // (along with its `aRouteTlvData`) has as good or better-quality + // links to all our neighboring routers which have a two-way link + // quality of two or better. bool isComparable = true; - for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId; - index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++) + for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++) { - const Router *router; - LinkQuality localLinkQuality; - LinkQuality peerLinkQuality; + const Router *router; + LinkQuality localLinkQuality; + LinkQuality peerLinkQuality; + const RouteTlv::Data::Entry *entry; if ((routerId == Get().mRouterId) || (routerId == aNeighborId)) { @@ -3823,15 +3826,17 @@ bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborI } // `router` is our neighbor with two-way link quality of - // at least two. Check that `aRouteTlv` has as good or + // at least two. Check that `aRouteTlvData` has as good or // better-quality link to it as well. - if (!aRouteTlv.IsRouterIdSet(routerId)) + entry = aRouteTlvData.GetEntries().FindMatching(routerId); + + if (entry == nullptr) { ExitNow(isComparable = false); } - peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index)); + peerLinkQuality = Min(entry->GetLinkQualityIn(), entry->GetLinkQualityOut()); if (peerLinkQuality < localLinkQuality) { diff --git a/src/core/thread/mle_tlvs.cpp b/src/core/thread/mle_tlvs.cpp index 79e3bba1e..5b0699751 100644 --- a/src/core/thread/mle_tlvs.cpp +++ b/src/core/thread/mle_tlvs.cpp @@ -44,25 +44,82 @@ namespace Mle { //--------------------------------------------------------------------------------------------------------------------- // RouteTlv -void RouteTlv::Init(void) +Error RouteTlv::Data::ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange) { - SetType(kRoute); - SetLength(sizeof(*this) - sizeof(Tlv)); - mRouterIdMask.Clear(); - ClearAllBytes(mRouteData); -} + Error error; + RouterIdMask routerIdMask; + OffsetRange offsetRange = aOffsetRange; +#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + bool isEven = true; +#endif -bool RouteTlv::IsValid(void) const -{ - bool isValid = false; + SuccessOrExit(error = aMessage.Read(offsetRange, routerIdMask)); + offsetRange.AdvanceOffset(sizeof(routerIdMask)); - VerifyOrExit(GetLength() >= sizeof(mRouterIdMask)); + mIdSequence = routerIdMask.GetSequence(); - VerifyOrExit(mRouterIdMask.IsValid()); - isValid = (GetRouteDataEntryCount() >= mRouterIdMask.DetermineAllocatedCount()); + mEntries.Clear(); + + for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++) + { + Entry *entry; + + if (!routerIdMask.IsAllocated(routerId)) + { + continue; + } + + entry = mEntries.PushBack(); + + // If `mEntries` is full, it indicates that there are more than + // `kMaxRouters` allocated IDs in the mask, which makes it invalid. + + VerifyOrExit(entry != nullptr, error = kErrorParse); + + entry->mRouterId = routerId; + +#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + SuccessOrExit(error = aMessage.Read(offsetRange, entry->mRouteData)); + offsetRange.AdvanceOffset(sizeof(uint8_t)); +#else + { + EntryType value; + + SuccessOrExit(error = aMessage.Read(offsetRange, value)); + value = BigEndian::HostSwap16(value); + + if (isEven) + { + entry->mRouteData = ReadBits(value); + offsetRange.AdvanceOffset(sizeof(uint8_t)); + } + else + { + entry->mRouteData = ReadBits(value); + offsetRange.AdvanceOffset(sizeof(uint16_t)); + } + + isEven = !isEven; + } +#endif + } exit: - return isValid; + return error; +} + +bool RouteTlv::Data::IsAllocated(uint8_t aRouterId) const { return mEntries.FindMatching(aRouterId); } + +void RouteTlv::Data::DetermineRouterIdMask(RouterIdMask &aRouterIdMask) const +{ + aRouterIdMask.Clear(); + + aRouterIdMask.SetSequence(mIdSequence); + + for (const Entry &entry : mEntries) + { + aRouterIdMask.Add(entry.mRouterId); + } } Error RouteTlv::AppendRouteDataEntry(Message &aMessage, diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index f33558148..14f770f35 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -230,125 +230,142 @@ typedef UintTlvInfo CslTimeoutTlv; typedef UintTlvInfo XtalAccuracyTlv; /** - * Implements Route TLV generation and parsing. + * Defines Route TLV constants and types. */ -OT_TOOL_PACKED_BEGIN -class RouteTlv : public Tlv, public TlvInfo +class RouteTlv : public TlvInfo { +#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + typedef uint8_t EntryType; +#else + typedef uint16_t EntryType; +#endif + public: /** - * Initializes the TLV. + * Represents the parsed Route TLV data. */ - void Init(void); - - /** - * Indicates whether or not the TLV appears to be well-formed. - * - * @retval TRUE If the TLV appears to be well-formed. - * @retval FALSE If the TLV does not appear to be well-formed. - */ - bool IsValid(void) const; - - /** - * Returns the Router ID Sequence value. - * - * @returns The Router ID Sequence value. - */ - uint8_t GetRouterIdSequence(void) const { return mRouterIdMask.GetSequence(); } - - /** - * Gets the Router ID Mask. - * - * @returns The Router ID Mask. - */ - const RouterIdMask &GetRouterIdMask(void) const { return mRouterIdMask; } - - /** - * Gets the Router ID Mask. - * - * @returns The Router ID Mask. - */ - RouterIdMask &GetRouterIdMask(void) { return mRouterIdMask; } - - /** - * Indicates whether or not a Router ID bit is set. - * - * @param[in] aRouterId The Router ID. - * - * @retval TRUE If the Router ID bit is set. - * @retval FALSE If the Router ID bit is not set. - */ - bool IsRouterIdSet(uint8_t aRouterId) const { return mRouterIdMask.IsAllocated(aRouterId); } - - /** - * Indicates whether the `RouteTlv` is a singleton, i.e., only one router is allocated. - * - * @retval TRUE It is a singleton. - * @retval FALSE It is not a singleton. - */ - bool IsSingleton(void) const { return IsValid() && (mRouterIdMask.DetermineAllocatedCount() <= 1); } - - /** - * Returns the number of Route Data entries in the Route TLV. - * - * @returns The Route Data Entry Count. - */ - uint8_t GetRouteDataEntryCount(void) const + class Data { -#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE - return GetLength() - sizeof(mRouterIdMask); -#else - return (GetLength() - sizeof(mRouterIdMask)) * 2 / 3; -#endif - } + public: + /** + * Represents a single route entry. + */ + class Entry + { + friend class Data; - /** - * Returns the Route Cost value for a given Router index. - * - * @param[in] aRouterIndex The Router index. - * - * @returns The Route Cost value for a given Router index. - */ - uint8_t GetRouteCost(uint8_t aRouterIndex) const - { -#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE - return ReadBits(mRouteData[aRouterIndex]); -#else - return static_cast(ReadBits(ReadEntry(aRouterIndex))); -#endif - } + public: + /** + * Gets the Router ID. + * + * @returns The Router ID. + */ + uint8_t GetRouterId(void) const { return mRouterId; } - /** - * Returns the Link Quality In value for a given Router index. - * - * @param[in] aRouterIndex The Router index. - * - * @returns The Link Quality In value for a given Router index. - */ - LinkQuality GetLinkQualityIn(uint8_t aRouterIndex) const - { -#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE - return static_cast(ReadBits(mRouteData[aRouterIndex])); -#else - return static_cast(ReadBits(ReadEntry(aRouterIndex))); -#endif - } + /** + * Gets the Route Cost value. + * + * @returns The Route Cost value. + */ + uint8_t GetRouteCost(void) const + { + return static_cast(ReadBits(mRouteData)); + } - /** - * Returns the Link Quality Out value for a given Router index. - * - * @param[in] aRouterIndex The Router index. - * - * @returns The Link Quality Out value for a given Router index. - */ - LinkQuality GetLinkQualityOut(uint8_t aRouterIndex) const - { -#if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE - return static_cast(ReadBits(mRouteData[aRouterIndex])); -#else - return static_cast(ReadBits(ReadEntry(aRouterIndex))); -#endif - } + /** + * Gets the Link Quality Out value. + * + * @returns The Link Quality Out value. + */ + LinkQuality GetLinkQualityOut(void) const + { + return static_cast(ReadBits(mRouteData)); + } + + /** + * Gets the Link Quality In value. + * + * @returns The Link Quality In value. + */ + LinkQuality GetLinkQualityIn(void) const + { + return static_cast(ReadBits(mRouteData)); + } + + /** + * Indicates whether the entry matches a given Router ID. + * + * @param[in] aRouterId The Router ID to match against. + * + * @retval TRUE The entry matches @p aRouterId. + * @retval FALSE The entry does not match @p aRouterId. + */ + bool Matches(uint8_t aRouterId) const { return (mRouterId == aRouterId); } + + private: + uint8_t mRouterId; + EntryType mRouteData; + }; + + /** + * Represents an array of route entries. + */ + typedef Array EntryArray; + + /** + * Parses the Route TLV data from a given message and offset range. + * + * @param[in] aMessage The message to parse from. + * @param[in] aOffsetRange The offset range within the message to read from. + * + * @retval kErrorNone Successfully parsed the Route TLV data. + * @retval kErrorParse Failed to parse the Route TLV data. + */ + Error ParseFrom(const Message &aMessage, const OffsetRange &aOffsetRange); + + /** + * Gets the Router ID Sequence. + * + * @returns The Router ID Sequence. + */ + uint8_t GetRouterIdSequence(void) const { return mIdSequence; } + + /** + * Gets the array of route entries. + * + * @returns The array of route entries. + */ + const EntryArray &GetEntries(void) const { return mEntries; } + + /** + * Indicates whether a given Router ID is allocated in the route data. + * + * @param[in] aRouterId The Router ID to check. + * + * @retval TRUE The Router ID is allocated. + * @retval FALSE The Router ID is not allocated. + */ + bool IsAllocated(uint8_t aRouterId) const; + + /** + * Indicates whether the Route TLV data is a singleton (at most one router is allocated). + * + * @retval TRUE It is a singleton. + * @retval FALSE It is not a singleton. + */ + bool IsSingleton(void) const { return mEntries.GetLength() <= 1; } + + /** + * Determines the Router ID Mask from the route data. + * + * @param[out] aRouterIdMask A reference to a `RouterIdMask` to populate. + */ + void DetermineRouterIdMask(RouterIdMask &aRouterIdMask) const; + + private: + uint8_t mIdSequence; + EntryArray mEntries; + }; #if !OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE /** @@ -394,21 +411,16 @@ private: // | LQOut | LQIn | Route Cost | // +---+---+---+---+---+---+---+---+ - typedef uint8_t EntryType; - static constexpr uint8_t kLinkQualityOutMask = 0x03 << 6; static constexpr uint8_t kLinkQualityInMask = 0x03 << 4; static constexpr uint8_t kRouteCostMask = 0x0f << 0; - static constexpr uint16_t kMaxRouteDataSize = kMaxRouterId + 1; #else // Under `LOG_ROUTES` feature, Route Data is 12 bits per route // (1.5 bytes). The first 4 bits are link qualities (out/in), // remaining 8 bits are for the route cost. The even and odd // entries are staggered. - typedef uint16_t EntryType; - static constexpr uint16_t kEvenEntryMask = 0xfff << 4; static constexpr uint16_t kOddEntryMask = 0xfff << 0; @@ -416,29 +428,8 @@ private: static constexpr uint16_t kLinkQualityInMask = 0x03 << 8; static constexpr uint16_t kRouteCostMask = 0xff << 0; - static constexpr uint16_t kMaxRouteDataSize = kMaxRouterId + 1 + kMaxRouterId / 2 + 1; - - uint16_t ReadEntry(uint8_t aRouterIndex) const - { - uint16_t data; - uint16_t offset = (aRouterIndex + aRouterIndex / 2); - - if (aRouterIndex & 0x1) - { - data = ReadBits(BigEndian::ReadUint16(&mRouteData[offset])); - } - else - { - data = ReadBits(BigEndian::ReadUint16(&mRouteData[offset])); - } - - return data; - } #endif // OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE - - RouterIdMask mRouterIdMask; - uint8_t mRouteData[kMaxRouteDataSize]; -} OT_TOOL_PACKED_END; +}; /** * Represents Leader Data TLV value. diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 23ce55020..2156121e3 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -1010,24 +1010,22 @@ Error Client::SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_ return SendCommand(kUriDiagnosticReset, Message::kPriorityNormal, aDestination, aTlvTypes, aCount); } -static void ParseRoute(const RouteTlv &aRouteTlv, otNetworkDiagRoute &aNetworkDiagRoute) +void Client::GetRouteInfo(const RouteTlv::Data &aRouteTlvData, RouteInfo &aNetDiagRouteInfo) { uint8_t routeCount = 0; - for (uint8_t i = 0; i <= Mle::kMaxRouterId; ++i) + aNetDiagRouteInfo.mIdSequence = aRouteTlvData.GetRouterIdSequence(); + + for (const RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries()) { - if (!aRouteTlv.IsRouterIdSet(i)) - { - continue; - } - aNetworkDiagRoute.mRouteData[routeCount].mRouterId = i; - aNetworkDiagRoute.mRouteData[routeCount].mRouteCost = aRouteTlv.GetRouteCost(routeCount); - aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityIn = aRouteTlv.GetLinkQualityIn(routeCount); - aNetworkDiagRoute.mRouteData[routeCount].mLinkQualityOut = aRouteTlv.GetLinkQualityOut(routeCount); - ++routeCount; + aNetDiagRouteInfo.mRouteData[routeCount].mRouterId = entry.GetRouterId(); + aNetDiagRouteInfo.mRouteData[routeCount].mRouteCost = entry.GetRouteCost(); + aNetDiagRouteInfo.mRouteData[routeCount].mLinkQualityIn = entry.GetLinkQualityIn(); + aNetDiagRouteInfo.mRouteData[routeCount].mLinkQualityOut = entry.GetLinkQualityOut(); + routeCount++; } - aNetworkDiagRoute.mRouteCount = routeCount; - aNetworkDiagRoute.mIdSequence = aRouteTlv.GetRouterIdSequence(); + + aNetDiagRouteInfo.mRouteCount = routeCount; } static Error ParseEnhancedRoute(const Message &aMessage, uint16_t aOffset, otNetworkDiagEnhRoute &aNetworkDiagEnhRoute) @@ -1167,13 +1165,10 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, case Tlv::kRoute: { - RouteTlv routeTlv; - uint16_t bytesToRead = Min(tlvInfo.GetSize(), sizeof(routeTlv)); + RouteTlv::Data routeTlvData; - VerifyOrExit(!tlvInfo.IsExtended(), error = kErrorParse); - SuccessOrExit(error = aMessage.Read(offset, &routeTlv, bytesToRead)); - VerifyOrExit(routeTlv.IsValid(), error = kErrorParse); - ParseRoute(routeTlv, aDiagTlv.mData.mRoute); + SuccessOrExit(error = routeTlvData.ParseFrom(aMessage, tlvInfo.GetValueOffsetRange())); + GetRouteInfo(routeTlvData, aDiagTlv.mData.mRoute); break; } diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp index 6545ff8cc..da92c89bf 100644 --- a/src/core/thread/network_diagnostic.hpp +++ b/src/core/thread/network_diagnostic.hpp @@ -263,6 +263,7 @@ private: typedef otNetworkDiagData DiagData; typedef otNetworkDiagChildTable ChildTable; typedef otNetworkDiagIp6AddrList Ip6AddrList; + typedef otNetworkDiagRoute RouteInfo; Error SendCommand(Uri aUri, Message::Priority aPriority, @@ -285,6 +286,7 @@ private: static void ReadDiagData(DiagData &aDiagData, const Message &aMessage, const Tlv::Info &aTlvInfo); static Error ParseChildTable(ChildTable &aChildTable, const Message &aMessage, OffsetRange aOffsetRange); static void ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange); + static void GetRouteInfo(const RouteTlv::Data &aRouteTlvData, RouteInfo &aNetDiagRouteInfo); #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) static const char *UriToString(Uri aUri); diff --git a/src/core/thread/network_diagnostic_tlvs.cpp b/src/core/thread/network_diagnostic_tlvs.cpp index c05dab4cf..8a3104078 100644 --- a/src/core/thread/network_diagnostic_tlvs.cpp +++ b/src/core/thread/network_diagnostic_tlvs.cpp @@ -101,6 +101,21 @@ void ChildTableTlvEntry::Parse(ParseInfo &aParseInfo) const Mle::DeviceMode(mMode).Get(aParseInfo.mMode); } +//--------------------------------------------------------------------------------------------------------------------- +// RouteTlv + +Error RouteTlv::FindIn(const Message &aMessage, RouteTlv::Data &aData) +{ + Error error; + OffsetRange offsetRange; + + SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, kType, offsetRange)); + error = aData.ParseFrom(aMessage, offsetRange); + +exit: + return error; +} + //--------------------------------------------------------------------------------------------------------------------- // EnhancedRouteTlvEntry diff --git a/src/core/thread/network_diagnostic_tlvs.hpp b/src/core/thread/network_diagnostic_tlvs.hpp index 305881846..4affd0aa8 100644 --- a/src/core/thread/network_diagnostic_tlvs.hpp +++ b/src/core/thread/network_diagnostic_tlvs.hpp @@ -296,21 +296,23 @@ typedef TlvInfo ConnectivityTlv; /** * Implements Route TLV generation and parsing. */ -OT_TOOL_PACKED_BEGIN class RouteTlv : public Mle::RouteTlv { public: static constexpr uint8_t kType = ot::NetworkDiagnostic::Tlv::kRoute; ///< The TLV Type value. /** - * Initializes the TLV. + * Finds and parses a Route TLV in a given message. + * + * @param[in] aMessage The message to search within. + * @param[out] aData A reference to a `Data` to populate upon success. + * + * @retval kErrorNone Successfully found and parsed the Route TLV. + * @retval kErrorNotFound Could not find a Route TLV in @p aMessage. + * @retval kErrorParse Found the Route TLV but failed to parse it. */ - void Init(void) - { - Mle::RouteTlv::Init(); - ot::Tlv::SetType(kType); - } -} OT_TOOL_PACKED_END; + static Error FindIn(const Message &aMessage, Data &aData); +}; /** * Represents a Leader Data TLV value. diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 9bee48c2d..fac5dea9e 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -61,10 +61,10 @@ void RouterTable::Clear(void) SignalTableChanged(events); } -bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const +bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv::Data &aRouteTlvData) const { return (GetActiveRouterCount() == 0) || - SerialNumber::IsGreater(aRouteTlv.GetRouterIdSequence(), GetRouterIdSequence()); + SerialNumber::IsGreater(aRouteTlvData.GetRouterIdSequence(), GetRouterIdSequence()); } void RouterTable::ClearNeighbors(void) @@ -525,6 +525,14 @@ uint16_t RouterTable::GetNextHop(uint16_t aDestRloc16) const return nextHopRloc16; } +void RouterTable::UpdateRouterIdMask(const Mle::RouteTlv::Data &aRouteTlvData) +{ + Mle::RouterIdMask routerIdMask; + + aRouteTlvData.DetermineRouterIdMask(routerIdMask); + UpdateRouterIdMask(routerIdMask); +} + void RouterTable::UpdateRouterIdMask(const Mle::RouterIdMask &aRouterIdMask) { bool shouldAdd = false; @@ -575,11 +583,12 @@ exit: return; } -void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId) +void RouterTable::UpdateRoutes(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aNeighborId) { - Router *neighbor; - Mle::RouterIdMask finitePathCostIds; - uint8_t linkCostToNeighbor; + Router *neighbor; + Mle::RouterIdMask finitePathCostIds; + uint8_t linkCostToNeighbor; + const Mle::RouteTlv::Data::Entry *matchingEntry; neighbor = FindRouterById(aNeighborId); VerifyOrExit(neighbor != nullptr); @@ -600,66 +609,51 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor } // Find the entry corresponding to our Router ID in the received - // `aRouteTlv` to get the `LinkQualityIn` from the perspective of - // neighbor. We use this to update our `LinkQualityOut` to the + // `aRouteTlvData` to get the `LinkQualityIn` from the perspective + // of neighbor. We use this to update our `LinkQualityOut` to the // neighbor. - for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId; - index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++) + matchingEntry = aRouteTlvData.GetEntries().FindMatching(Mle::RouterIdFromRloc16(Get().GetRloc16())); + + if (matchingEntry != nullptr) { - if (!Get().MatchesRouterId(routerId)) + LinkQuality linkQuality = matchingEntry->GetLinkQualityIn(); + + if (neighbor->GetLinkQualityOut() != linkQuality) { - continue; + neighbor->SetLinkQualityOut(linkQuality); + SignalTableChanged(kEventLinkQualityOutChanged); } - if (aRouteTlv.IsRouterIdSet(routerId)) + // If the `aRouteTlvData` indicates that the neighboring + // router claims to have no link to us (by setting its + // `GetLinkQualityOut()` towards us as `kLinkQuality0`), + // and we have previously established a link with it, and + // our two-way link quality to this router is at least + // `kLinkQuality2`, we schedule a unicast Advertisement to + // be sent to this neighbor. This helps expedite recovery + // from any temporary router link quality mismatch. + // Otherwise, the neighboring router will continue to + // advertise that it has no link to us until our next + // trickle timer-triggered Advertisement transmission + // (which can be up to 32 seconds later). + + if (neighbor->IsStateValid() && (matchingEntry->GetLinkQualityOut() == kLinkQuality0) && + (neighbor->GetTwoWayLinkQuality() >= kLinkQuality2)) { - LinkQuality linkQuality = aRouteTlv.GetLinkQualityIn(index); - - if (neighbor->GetLinkQualityOut() != linkQuality) - { - neighbor->SetLinkQualityOut(linkQuality); - SignalTableChanged(kEventLinkQualityOutChanged); - } - - // If the `aRouteTlv` indicates that the neighboring - // router claims to have no link to us (by setting its - // `GetLinkQualityOut()` towards us as `kLinkQuality0`), - // and we have previously established a link with it, and - // our two-way link quality to this router is at least - // `kLinkQuality2`, we schedule a unicast Advertisement to - // be sent to this neighbor. This helps expedite recovery - // from any temporary router link quality mismatch. - // Otherwise, the neighboring router will continue to - // advertise that it has no link to us until our next - // trickle timer-triggered Advertisement transmission - // (which can be up to 32 seconds later). - - if (neighbor->IsStateValid() && (aRouteTlv.GetLinkQualityOut(index) == kLinkQuality0) && - (neighbor->GetTwoWayLinkQuality() >= kLinkQuality2)) - { - Get().ScheduleUnicastAdvertisementTo(*neighbor); - } + Get().ScheduleUnicastAdvertisementTo(*neighbor); } - - break; } linkCostToNeighbor = GetLinkCost(*neighbor); - for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId; - index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++) + for (const Mle::RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries()) { Router *router; Router *nextHop; uint8_t cost; - if (!aRouteTlv.IsRouterIdSet(routerId)) - { - continue; - } - - router = FindRouterById(routerId); + router = FindRouterById(entry.GetRouterId()); if (router == nullptr || Get().HasRloc16(router->GetRloc16()) || router == neighbor) { @@ -668,7 +662,7 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor nextHop = FindNextHopTowards(*router); - cost = aRouteTlv.GetRouteCost(index); + cost = entry.GetRouteCost(); cost = (cost == 0) ? Mle::kMaxRouteCost : cost; if ((nextHop == nullptr) || (nextHop == neighbor)) @@ -718,28 +712,27 @@ exit: return; } -void RouterTable::UpdateRouterOnFtdChild(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId) +void RouterTable::UpdateRouterOnFtdChild(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aParentId) { - for (uint8_t routerId = 0, index = 0; routerId <= Mle::kMaxRouterId; - index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++) + for (const Mle::RouteTlv::Data::Entry &entry : aRouteTlvData.GetEntries()) { Router *router; uint8_t cost; uint8_t nextHopId; - if (!aRouteTlv.IsRouterIdSet(routerId) || (routerId == aParentId)) + if (entry.GetRouterId() == aParentId) { continue; } - router = FindRouterById(routerId); + router = FindRouterById(entry.GetRouterId()); if (router == nullptr) { continue; } - cost = aRouteTlv.GetRouteCost(index); + cost = entry.GetRouteCost(); nextHopId = (cost == 0) ? Mle::kInvalidRouterId : aParentId; if (router->SetNextHopAndCost(nextHopId, cost)) diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 1bee0dfb9..502690108 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -312,12 +312,12 @@ public: * Determines whether the Router ID Sequence in a received Route TLV is more recent than the current * Router ID Sequence being used by `RouterTable`. * - * @param[in] aRouteTlv The Route TLV to compare. + * @param[in] aRouteTlvData The Route TLV Data to compare. * - * @retval TRUE The Router ID Sequence in @p aRouteTlv is more recent. - * @retval FALSE The Router ID Sequence in @p aRouteTlv is not more recent. + * @retval TRUE The Router ID Sequence in @p aRouteTlvData is more recent. + * @retval FALSE The Router ID Sequence in @p aRouteTlvData is not more recent. */ - bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const; + bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv::Data &aRouteTlvData) const; /** * Gets the number of router neighbors with `GetLinkQualityIn()` better than or equal to a given threshold. @@ -346,22 +346,29 @@ public: void UpdateRouterIdMask(const Mle::RouterIdMask &aRouterIdMask); /** - * Updates the routes based on a received `RouteTlv` from a neighboring router. + * Updates the allocated Router ID mask from a received `RouteTlv::Data`. * - * @param[in] aRouteTlv The received `RouteTlv` - * @param[in] aNeighborId The router ID of neighboring router from which @p aRouteTlv is received. + * @param[in] aRouteTlvData The received `RouteTlv::Data`. */ - void UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighborId); + void UpdateRouterIdMask(const Mle::RouteTlv::Data &aRouteTlvData); /** - * Updates the routes on an FTD child based on a received `RouteTlv` from the parent. + * Updates the routes based on a received `RouteTlv::Data` from a neighboring router. * - * MUST be called when device is an FTD child and @p aRouteTlv is received from its current parent. + * @param[in] aRouteTlvData The received `RouteTlv::Data` + * @param[in] aNeighborId The router ID of neighboring router from which @p aRouteTlvData is received. + */ + void UpdateRoutes(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aNeighborId); + + /** + * Updates the routes on an FTD child based on a received `RouteTlv::Data` from the parent. * - * @param[in] aRouteTlv The received `RouteTlv` from parent. + * MUST be called when device is an FTD child and @p aRouteTlvData is received from its current parent. + * + * @param[in] aRouteTlvData The received `RouteTlvData` from parent. * @param[in] aParentId The Router ID of parent. */ - void UpdateRouterOnFtdChild(const Mle::RouteTlv &aRouteTlv, uint8_t aParentId); + void UpdateRouterOnFtdChild(const Mle::RouteTlv::Data &aRouteTlvData, uint8_t aParentId); /** * Gets the allocated Router ID Mask. diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index fd50c26d6..3f6022ce6 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -467,15 +467,15 @@ void MeshDiag::HandleTimer(void) { Finalize(kErrorResponseTimeout); } Error MeshDiag::RouterInfo::ParseFrom(const Message &aMessage) { - Error error = kErrorNone; - Mle::Mle &mle = aMessage.Get(); - RouteTlv routeTlv; + Error error = kErrorNone; + Mle::Mle &mle = aMessage.Get(); + RouteTlv::Data routeTlvData; Clear(); SuccessOrExit(error = Tlv::Find(aMessage, mRloc16)); SuccessOrExit(error = Tlv::Find(aMessage, AsCoreType(&mExtAddress))); - SuccessOrExit(error = Tlv::FindTlv(aMessage, routeTlv)); + SuccessOrExit(error = RouteTlv::FindIn(aMessage, routeTlvData)); switch (error = Tlv::Find(aMessage, mVersion)) { @@ -495,13 +495,9 @@ Error MeshDiag::RouterInfo::ParseFrom(const Message &aMessage) mIsLeader = (mRouterId == mle.GetLeaderId()); mIsBorderRouter = aMessage.Get().ContainsBorderRouterWithRloc(mRloc16); - for (uint8_t id = 0, index = 0; id <= Mle::kMaxRouterId; id++) + for (const RouteTlv::Data::Entry &entry : routeTlvData.GetEntries()) { - if (routeTlv.IsRouterIdSet(id)) - { - mLinkQualities[id] = routeTlv.GetLinkQualityIn(index); - index++; - } + mLinkQualities[entry.GetRouterId()] = entry.GetLinkQualityIn(); } exit: