diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 6f1c34a6a..69c898124 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2772,21 +2772,7 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo) SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); #if OPENTHREAD_FTD - if (IsFullThreadDevice()) - { - RouteTlv routeTlv; - - switch (Get().ProcessRouteTlv(aRxInfo, routeTlv)) - { - case kErrorNone: - Get().UpdateRoutesOnFed(routeTlv, mParent.GetRouterId()); - break; - case kErrorNotFound: - break; - default: - ExitNow(error = kErrorParse); - } - } + SuccessOrExit(error = Get().ReadAndProcessRouteTlvOnFed(aRxInfo, mParent.GetRouterId())); #endif mRetrieveNewNetworkData = true; @@ -3395,21 +3381,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); #if OPENTHREAD_FTD - if (IsFullThreadDevice()) - { - RouteTlv routeTlv; - - switch (Get().ProcessRouteTlv(aRxInfo, routeTlv)) - { - case kErrorNone: - Get().UpdateRoutesOnFed(routeTlv, RouterIdFromRloc16(sourceAddress)); - break; - case kErrorNotFound: - break; - default: - ExitNow(error = kErrorParse); - } - } + SuccessOrExit(error = Get().ReadAndProcessRouteTlvOnFed(aRxInfo, RouterIdFromRloc16(sourceAddress))); #endif mParentCandidate.CopyTo(mParent); @@ -5047,6 +5019,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); + +exit: + return error; +} +#endif + //--------------------------------------------------------------------------------------------------------------------- // ParentCandidate diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index af157a28e..c73c4e8db 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1360,7 +1360,7 @@ protected: /** * This method reads CSL Clock Accuracy TLV from a message. * - * @param[out] A reference to output the CSL accuracy. + * @param[out] aCslAccuracy A reference to output the CSL accuracy. * * @retval kErrorNone Successfully read the TLV. * @retval kErrorNotFound TLV was not found in the message. @@ -1370,6 +1370,20 @@ protected: Error ReadCslClockAccuracyTlv(Mac::CslAccuracy &aCslAccuracy) const; #endif +#if OPENTHREAD_FTD + /** + * This method reads and validates Route TLV from a message. + * + * @param[out] aRouteTlv A reference to output the read Route TLV. + * + * @retval kErrorNone Successfully read and validated the Route TLV. + * @retval kErrorNotFound TLV was not found in the message. + * @retval kErrorParse TLV was found but could not be parsed or is not valid. + * + */ + Error ReadRouteTlv(RouteTlv &aRouteTlv) const; +#endif + private: Error ReadChallengeOrResponse(uint8_t aTlvType, Challenge &aBuffer) const; }; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 313e8273a..5a1206485 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -893,7 +893,8 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) // Route mRouterTable.Clear(); - SuccessOrExit(error = ProcessRouteTlv(aRxInfo)); + SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv)); + SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); router = mRouterTable.FindRouterById(routerId); VerifyOrExit(router != nullptr); @@ -935,24 +936,28 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) } // Route (optional) - switch (error = ProcessRouteTlv(aRxInfo, routeTlv)) + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) { case kErrorNone: + VerifyOrExit(routeTlv.IsRouterIdSet(routerId), error = kErrorParse); + + if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv)) + { + SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); + router = mRouterTable.FindRouterById(routerId); + OT_ASSERT(router != nullptr); + } + mRouterTable.UpdateRoutes(routeTlv, routerId); - // Need to update router after ProcessRouteTlv - router = mRouterTable.FindRouterById(routerId); - OT_ASSERT(router != nullptr); break; case kErrorNotFound: - error = kErrorNone; break; default: - ExitNow(); + ExitNow(error = kErrorParse); } - // update routing table if (routerId != mRouterId && !IsRouterIdValid(router->GetNextHop())) { ResetAdvertiseInterval(); @@ -1018,20 +1023,9 @@ exit: return error; } -Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo) +Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo) { - RouteTlv routeTlv; - - return ProcessRouteTlv(aRxInfo, routeTlv); -} - -Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv) -{ - // This method processes Route TLV in a received MLE message - // (from `RxInfo`). In case of success, `aRouteTlv` is updated - // to return the read/processed route TLV from the message. - // If the message contains no Route TLV, `kErrorNotFound` is - // returned. + // This method processes `aRouteTlv` 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` @@ -1040,7 +1034,7 @@ Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv) // (in case `mNeighbor` was pointing to a router entry from the // `RouterTable`). - Error error; + Error error = kErrorNone; uint16_t neighborRloc16 = Mac::kShortAddrInvalid; if ((aRxInfo.mNeighbor != nullptr) && Get().Contains(*aRxInfo.mNeighbor)) @@ -1048,13 +1042,9 @@ Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv) neighborRloc16 = aRxInfo.mNeighbor->GetRloc16(); } - SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, aRouteTlv)); + mRouterTable.UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask()); - VerifyOrExit(aRouteTlv.IsValid(), error = kErrorParse); - - Get().UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask()); - - if (IsRouter() && !Get().IsAllocated(mRouterId)) + if (IsRouter() && !mRouterTable.IsAllocated(mRouterId)) { IgnoreError(BecomeDetached()); error = kErrorNoRoute; @@ -1065,6 +1055,36 @@ Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv) aRxInfo.mNeighbor = Get().FindNeighbor(neighborRloc16); } + return error; +} + +Error MleRouter::ReadAndProcessRouteTlvOnFed(RxInfo &aRxInfo, uint8_t aParentId) +{ + // This method reads and processes Route TLV from message on an + // FED if message contains one. It returns `kErrorNone` when + // successfully processed or if there is no Route TLV in the + // message. + // + // 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; + + VerifyOrExit(IsFullThreadDevice()); + + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) + { + case kErrorNone: + SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); + mRouterTable.UpdateRoutesOnFed(routeTlv, aParentId); + break; + case kErrorNotFound: + break; + default: + ExitNow(error = kErrorParse); + } + exit: return error; } @@ -1116,13 +1136,15 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c Router *router; uint8_t routerId; - if (Tlv::FindTlv(aRxInfo.mMessage, routeTlv) == kErrorNone) + switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv)) { - VerifyOrExit(routeTlv.IsValid(), error = kErrorParse); - } - else - { - routeTlv.SetLength(0); // Mark that a Route TLV was not included + case kErrorNone: + break; + case kErrorNotFound: + routeTlv.SetLength(0); // Mark that a Route TLV was not included. + break; + default: + ExitNow(error = kErrorParse); } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1187,9 +1209,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Process `RouteTlv` - if (aRxInfo.IsNeighborStateValid() && - ((mRouterTable.GetActiveRouterCount() == 0) || - SerialNumber::IsGreater(routeTlv.GetRouterIdSequence(), mRouterTable.GetRouterIdSequence()))) + if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv)) { bool processRouteTlv = false; @@ -1216,7 +1236,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c if (processRouteTlv) { - SuccessOrExit(error = ProcessRouteTlv(aRxInfo)); + SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); } } diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 7ac7d2677..d1ac1ae2e 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -579,8 +579,9 @@ private: void HandleTimeSync(RxInfo &aRxInfo); #endif - Error ProcessRouteTlv(RxInfo &aRxInfo); - Error ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv); + Error ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo); + Error ReadAndProcessRouteTlvOnFed(RxInfo &aRxInfo, uint8_t aParentId); + void StopAdvertiseTrickleTimer(void); Error SendAddressSolicit(ThreadStatusTlv::Status aStatus); void SendAddressSolicitResponse(const Coap::Message &aRequest, diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index fb6feb5b5..8faced1ee 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -66,6 +66,12 @@ void RouterTable::Clear(void) SignalTableChanged(); } +bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const +{ + return (GetActiveRouterCount() == 0) || + SerialNumber::IsGreater(aRouteTlv.GetRouterIdSequence(), GetRouterIdSequence()); +} + void RouterTable::ClearNeighbors(void) { for (Router &router : mRouters) diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 02b6f2fc4..e87ed0dbc 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -39,6 +39,7 @@ #include "common/iterator_utils.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" +#include "common/serial_number.hpp" #include "common/tasklet.hpp" #include "mac/mac_types.hpp" #include "thread/mle_tlvs.hpp" @@ -315,6 +316,18 @@ public: */ TimeMilli GetRouterIdSequenceLastUpdated(void) const { return mRouterIdSequenceLastUpdated; } + /** + * This method 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. + * + * @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. + * + */ + bool IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const; + /** * This method returns the number of neighbor links. *