diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 70c871420..76a52e988 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -725,7 +725,7 @@ otError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, switch (aRequestedTlvs.mTlvs[i]) { case Tlv::kRoute: - SuccessOrExit(error = AppendRoute(*message)); + SuccessOrExit(error = AppendRoute(*message, aNeighbor)); break; case Tlv::kAddress16: @@ -4139,15 +4139,62 @@ exit: return error; } -void MleRouter::FillRouteTlv(RouteTlv &aTlv) +void MleRouter::FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor) { - uint8_t routerCount = 0; + uint8_t routerIdSequence = mRouterTable.GetRouterIdSequence(); + RouterIdSet routerIdSet = mRouterTable.GetRouterIdSet(); + uint8_t routerCount; - aTlv.SetRouterIdSequence(mRouterTable.GetRouterIdSequence()); - aTlv.SetRouterIdMask(mRouterTable.GetRouterIdSet()); + if (aNeighbor && IsActiveRouter(aNeighbor->GetRloc16())) + { + // Sending a Link Accept message that may require truncation + // of Route64 TLV + + routerCount = mRouterTable.GetActiveRouterCount(); + + if (routerCount > RouteTlv::kLinkAcceptMaxRouters) + { + for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++) + { + if (routerCount <= RouteTlv::kLinkAcceptMaxRouters) + { + break; + } + + if ((routerId == RouterIdFromRloc16(GetRloc16())) || (routerId == aNeighbor->GetRouterId()) || + (routerId == GetLeaderId())) + { + // Route64 TLV must contain this device and the + // neighboring router to ensure that at least this + // link can be established. + continue; + } + + if (routerIdSet.Contains(routerId)) + { + routerIdSet.Remove(routerId); + routerCount--; + } + } + + // Ensure that the neighbor will process the current + // Route64 TLV in a subsequent message exchange + routerIdSequence -= RouteTlv::kLinkAcceptSequenceRollback; + } + } + + aTlv.SetRouterIdSequence(routerIdSequence); + aTlv.SetRouterIdMask(routerIdSet); + + routerCount = 0; for (Router &router : Get().Iterate()) { + if (!routerIdSet.Contains(router.GetRouterId())) + { + continue; + } + if (router.GetRloc16() == GetRloc16()) { aTlv.SetLinkQualityIn(routerCount, 0); @@ -4193,12 +4240,12 @@ void MleRouter::FillRouteTlv(RouteTlv &aTlv) aTlv.SetRouteDataLength(routerCount); } -otError MleRouter::AppendRoute(Message &aMessage) +otError MleRouter::AppendRoute(Message &aMessage, Neighbor *aNeighbor) { RouteTlv tlv; tlv.Init(); - FillRouteTlv(tlv); + FillRouteTlv(tlv, aNeighbor); return tlv.AppendTo(aMessage); } diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index ec1632477..4518617bd 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -419,7 +419,7 @@ public: * @param[out] aTlv A reference to the tlv to be filled. * */ - void FillRouteTlv(RouteTlv &aTlv); + void FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor = nullptr); /** * This method generates an MLE Child Update Request message to be sent to the parent. @@ -582,7 +582,7 @@ private: otError AppendConnectivity(Message &aMessage); otError AppendChildAddresses(Message &aMessage, Child &aChild); - otError AppendRoute(Message &aMessage); + otError AppendRoute(Message &aMessage, Neighbor *aNeighbor = nullptr); otError AppendActiveDataset(Message &aMessage); otError AppendPendingDataset(Message &aMessage); void HandleDetachStart(void); diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index bae885d07..7285a0c17 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -142,6 +142,16 @@ OT_TOOL_PACKED_BEGIN class RouteTlv : public Tlv { public: + enum + { +#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE + kLinkAcceptMaxRouters = 3, +#else + kLinkAcceptMaxRouters = 20, +#endif + kLinkAcceptSequenceRollback = 64, + }; + /** * This method initializes the TLV. *