diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index b5c18d63c..3e5c3c0fd 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3153,12 +3153,13 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo) #if OPENTHREAD_FTD if (IsFullThreadDevice()) { - RouteTlv route; - - if ((Tlv::FindTlv(aRxInfo.mMessage, route) == kErrorNone) && route.IsValid()) + switch (Get().ProcessRouteTlv(aRxInfo)) { - // Overwrite Route Data - IgnoreError(Get().ProcessRouteTlv(route)); + case kErrorNone: + case kErrorNotFound: + break; + default: + ExitNow(error = kErrorParse); } } #endif @@ -3795,11 +3796,13 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) #if OPENTHREAD_FTD if (IsFullThreadDevice()) { - RouteTlv route; - - if (Tlv::FindTlv(aRxInfo.mMessage, route) == kErrorNone) + switch (Get().ProcessRouteTlv(aRxInfo)) { - SuccessOrExit(error = Get().ProcessRouteTlv(route)); + case kErrorNone: + case kErrorNotFound: + break; + default: + ExitNow(error = kErrorParse); } } #endif diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 1a90d47d6..42446ee46 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -837,7 +837,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) uint32_t mleFrameCounter; uint8_t routerId; uint16_t address16; - RouteTlv route; + RouteTlv routeTlv; LeaderData leaderData; uint8_t linkMargin; @@ -919,10 +919,8 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); // Route - SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, Tlv::kRoute, sizeof(route), route)); - VerifyOrExit(route.IsValid(), error = kErrorParse); mRouterTable.Clear(); - SuccessOrExit(error = ProcessRouteTlv(route)); + SuccessOrExit(error = ProcessRouteTlv(aRxInfo)); router = mRouterTable.GetRouter(routerId); VerifyOrExit(router != nullptr); @@ -964,14 +962,21 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) } // Route (optional) - if (Tlv::FindTlv(aRxInfo.mMessage, route) == kErrorNone) + switch (error = ProcessRouteTlv(aRxInfo, routeTlv)) { - VerifyOrExit(route.IsValid(), error = kErrorParse); - SuccessOrExit(error = ProcessRouteTlv(route)); - UpdateRoutes(route, routerId); - // need to update router after ProcessRouteTlv + case kErrorNone: + UpdateRoutes(routeTlv, routerId); + // Need to update router after ProcessRouteTlv router = mRouterTable.GetRouter(routerId); OT_ASSERT(router != nullptr); + break; + + case kErrorNotFound: + error = kErrorNone; + break; + + default: + ExitNow(); } // update routing table @@ -1084,18 +1089,54 @@ exit: return error; } -Error MleRouter::ProcessRouteTlv(const RouteTlv &aRoute) +Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo) { - Error error = kErrorNone; + RouteTlv routeTlv; - mRouterTable.UpdateRouterIdSet(aRoute.GetRouterIdSequence(), aRoute.GetRouterIdMask()); + return ProcessRouteTlv(aRxInfo, routeTlv); +} - if (IsRouter() && !mRouterTable.IsAllocated(mRouterId)) +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. + // + // During processing of Route TLV, the entries in the router table + // may shuffle. This method ensures that the `aRxInfo.mNeighbor` + // (which indicates the neighbor from which the MLE message was + // received) is correctly updated to point to the same neighbor + // (in case `mNeighbor` was pointing to a router entry from the + // `RouterTable`). + + Error error; + uint16_t neighborRloc16 = Mac::kShortAddrInvalid; + + if ((aRxInfo.mNeighbor != nullptr) && Get().Contains(*aRxInfo.mNeighbor)) + { + neighborRloc16 = aRxInfo.mNeighbor->GetRloc16(); + } + + SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, aRouteTlv)); + + VerifyOrExit(aRouteTlv.IsValid(), error = kErrorParse); + + Get().UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask()); + + if (IsRouter() && !Get().IsAllocated(mRouterId)) { IgnoreError(BecomeDetached()); error = kErrorNoRoute; } + if (neighborRloc16 != Mac::kShortAddrInvalid) + { + aRxInfo.mNeighbor = Get().GetNeighbor(neighborRloc16); + } + +exit: return error; } @@ -1289,11 +1330,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo) if (processRouteTlv) { - SuccessOrExit(error = ProcessRouteTlv(route)); - if (Get().Contains(*aRxInfo.mNeighbor)) - { - aRxInfo.mNeighbor = nullptr; // aRxInfo.mNeighbor is no longer valid after `ProcessRouteTlv` - } + SuccessOrExit(error = ProcessRouteTlv(aRxInfo)); } } diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 1a2df968e..6645498e6 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -603,7 +603,8 @@ private: void HandleTimeSync(RxInfo &aRxInfo); #endif - Error ProcessRouteTlv(const RouteTlv &aRoute); + Error ProcessRouteTlv(RxInfo &aRxInfo); + Error ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv); void StopAdvertiseTrickleTimer(void); Error SendAddressSolicit(ThreadStatusTlv::Status aStatus); void SendAddressRelease(void);