From 6f909a1d6a9213cb137615af205aa29e1aca39b1 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 2 May 2023 23:15:33 -0700 Subject: [PATCH] [mle] request "Route TLV" after quick re-attach as FED (#8956) This commit allows an FED child to request Route TLV (in "TLV Request TLV") in an MLE Data Request message. Parent will include the Route TLV when requested by the child. After successfully performing a quick re-attach upon reset, an FED child requests Route TLV when sending MLE Data Request to its parent. This is tracked by a newly added boolean `mRequestRouteTlv`, which is set after quick re-attach and cleared when Route TLV is successfully processed. This commit also simplifies methods related to sending Data Request. --- src/core/thread/link_metrics.cpp | 4 +- src/core/thread/mle.cpp | 47 ++++++++++--- src/core/thread/mle.hpp | 75 +++++++++------------ src/core/thread/mle_router.cpp | 11 +-- tests/toranj/cli/test-012-reset-recovery.py | 20 +++++- 5 files changed, 95 insertions(+), 62 deletions(-) diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 2547f1bf3..a7ad64b0b 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -58,8 +58,6 @@ LinkMetrics::LinkMetrics(Instance &aInstance) Error LinkMetrics::Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics) { - static const uint8_t kTlvs[] = {Mle::Tlv::kLinkMetricsReport}; - Error error; Neighbor *neighbor; QueryInfo info; @@ -79,7 +77,7 @@ Error LinkMetrics::Query(const Ip6::Address &aDestination, uint8_t aSeriesId, co VerifyOrExit(info.mTypeIdCount == 0, error = kErrorInvalidArgs); } - error = Get().SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, info); + error = Get().SendDataRequestForLinkMetricsReport(aDestination, info); exit: return error; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 4fad3a71c..440f44d69 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -73,6 +73,7 @@ const otMeshLocalPrefix Mle::sMeshLocalPrefixInit = { Mle::Mle(Instance &aInstance) : InstanceLocator(aInstance) , mRetrieveNewNetworkData(false) + , mRequestRouteTlv(false) , mRole(kRoleDisabled) , mNeighborTable(aInstance) , mDeviceMode(DeviceMode::kModeRxOnWhenIdle) @@ -1841,7 +1842,30 @@ exit: return error; } +Error Mle::SendDataRequest(const Ip6::Address &aDestination) +{ + return SendDataRequestAfterDelay(aDestination, /* aDelay */ 0); +} + +Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) +{ + static const uint8_t kTlvs[] = {Tlv::kNetworkData, Tlv::kRoute}; + + // Based on `mRequestRouteTlv` include both Network Data and Route + // TLVs or only Network Data TLV. + + return SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1, aDelay); +} + #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE +Error Mle::SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination, + const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo) +{ + static const uint8_t kTlvs[] = {Tlv::kLinkMetricsReport}; + + return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, &aQueryInfo); +} + Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, @@ -1987,15 +2011,13 @@ void Mle::HandleMessageTransmissionTimer(void) case kChildUpdateRequestNone: if (mDataRequestState == kDataRequestActive) { - static const uint8_t kTlvs[] = {Tlv::kNetworkData}; - Ip6::Address destination; VerifyOrExit(mDataRequestAttempts < kMaxChildKeepAliveAttempts, IgnoreError(BecomeDetached())); destination.SetToLinkLocalAddress(mParent.GetExtAddress()); - if (SendDataRequest(destination, kTlvs) == kErrorNone) + if (SendDataRequest(destination) == kErrorNone) { mDataRequestAttempts++; } @@ -2741,8 +2763,6 @@ exit: void Mle::HandleAdvertisement(RxInfo &aRxInfo) { - static const uint8_t kTlvs[] = {Tlv::kNetworkData}; - Error error = kErrorNone; uint16_t sourceAddress; LeaderData leaderData; @@ -2796,7 +2816,7 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo) if (mRetrieveNewNetworkData || IsNetworkDataNewer(leaderData)) { delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay); - IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kTlvs, delay)); + IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay)); } aRxInfo.mClass = RxInfo::kPeerMessage; @@ -2826,6 +2846,10 @@ void Mle::HandleDataResponse(RxInfo &aRxInfo) } #endif +#if OPENTHREAD_FTD + SuccessOrExit(error = Get().ReadAndProcessRouteTlvOnFed(aRxInfo, mParent.GetRouterId())); +#endif + error = HandleLeaderData(aRxInfo); if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle()) @@ -2989,8 +3013,6 @@ exit: if (dataRequest) { - static const uint8_t kTlvs[] = {Tlv::kNetworkData}; - uint16_t delay; if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast()) @@ -3005,7 +3027,7 @@ exit: delay = 10; } - IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kTlvs, delay)); + IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay)); } else if (error == kErrorNone) { @@ -3584,6 +3606,13 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo) mRetrieveNewNetworkData = true; +#if OPENTHREAD_FTD + if (IsFullThreadDevice()) + { + mRequestRouteTlv = true; + } +#endif + OT_FALL_THROUGH; case kRoleChild: diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 517ab094b..163a4af95 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1525,49 +1525,32 @@ protected: */ Mac::ShortAddress GetNextHop(uint16_t aDestination) const; + /** + * This method generates an MLE Data Request message. + * + * @param[in] aDestination The IPv6 destination address. + * + * @retval kErrorNone Successfully generated an MLE Data Request message. + * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. + * + */ + Error SendDataRequest(const Ip6::Address &aDestination); + #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE /** - * This method generates an MLE Data Request message which includes a Link Metrics Query TLV. + * This method generates an MLE Data Request message which request Link Metrics Report TLV. * * @param[in] aDestination A reference to the IPv6 address of the destination. - * @param[in] aTlvs A pointer to requested TLV types. - * @param[in] aTlvsLength The number of TLV types in @p aTlvs. - * @param[in] aDelay Delay in milliseconds before the Data Request message is sent. * @param[in] aQueryInfo A Link Metrics query info. * * @retval kErrorNone Successfully generated an MLE Data Request message. * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. * */ - Error SendDataRequest(const Ip6::Address &aDestination, - const uint8_t *aTlvs, - uint8_t aTlvsLength, - uint16_t aDelay, - const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo) - { - return SendDataRequest(aDestination, aTlvs, aTlvsLength, aDelay, &aQueryInfo); - } + Error SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination, + const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo); #endif - /** - * This method generates an MLE Data Request message. - * - * @tparam kArrayLength The TLV array length. - * - * @param[in] aDestination A reference to the IPv6 address of the destination. - * @param[in] aTlvs An array of requested TLVs. - * @param[in] aDelay Delay in milliseconds before the Data Request message is sent. - * - * @retval kErrorNone Successfully generated an MLE Data Request message. - * @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message. - * - */ - template - Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t (&aTlvs)[kArrayLength], uint16_t aDelay = 0) - { - return SendDataRequest(aDestination, aTlvs, kArrayLength, aDelay); - } - /** * This method generates an MLE Child Update Request message. * @@ -1769,20 +1752,21 @@ protected: Ip6::Netif::UnicastAddress mLeaderAloc; ///< Leader anycast locator - LeaderData mLeaderData; ///< Last received Leader Data TLV. - bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set. - DeviceRole mRole; ///< Current Thread role. - Parent mParent; ///< Parent information. - NeighborTable mNeighborTable; ///< The neighbor table. - DeviceMode mDeviceMode; ///< Device mode setting. - AttachState mAttachState; ///< The attach state. - uint8_t mParentRequestCounter; ///< Number of parent requests while in `kAttachStateParentRequest`. - ReattachState mReattachState; ///< Reattach state - uint16_t mAttachCounter; ///< Attach attempt counter. - uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach. - AttachTimer mAttachTimer; ///< The timer for driving the attach process. - DelayTimer mDelayedResponseTimer; ///< The timer to delay MLE responses. - MsgTxTimer mMessageTransmissionTimer; ///< The timer for (re-)sending of MLE messages (e.g. Child Update). + LeaderData mLeaderData; ///< Last received Leader Data TLV. + bool mRetrieveNewNetworkData : 1; ///< Indicating new Network Data is needed if set. + bool mRequestRouteTlv : 1; ///< Request Route TLV when sending Data Request. + DeviceRole mRole; ///< Current Thread role. + Parent mParent; ///< Parent information. + NeighborTable mNeighborTable; ///< The neighbor table. + DeviceMode mDeviceMode; ///< Device mode setting. + AttachState mAttachState; ///< The attach state. + uint8_t mParentRequestCounter; ///< Number of parent requests while in `kAttachStateParentRequest`. + ReattachState mReattachState; ///< Reattach state + uint16_t mAttachCounter; ///< Attach attempt counter. + uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach. + AttachTimer mAttachTimer; ///< The timer for driving the attach process. + DelayTimer mDelayedResponseTimer; ///< The timer to delay MLE responses. + MsgTxTimer mMessageTransmissionTimer; ///< The timer for (re-)sending of MLE messages (e.g. Child Update). #if OPENTHREAD_FTD uint8_t mLinkRequestAttempts; ///< Number of remaining link requests to send after reset. bool mWasLeader; ///< Indicating if device was leader before reset. @@ -1990,6 +1974,7 @@ private: void HandleDetachGracefullyTimer(void); bool IsDetachingGracefully(void) { return mDetachGracefullyTimer.IsRunning(); } Error SendChildUpdateRequest(ChildUpdateRequestMode aMode); + Error SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay); #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE Error SendDataRequest(const Ip6::Address &aDestination, diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 30d6f76c1..052c93e53 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -808,8 +808,6 @@ void MleRouter::HandleLinkAcceptAndRequest(RxInfo &aRxInfo) Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) { - static const uint8_t kDataRequestTlvs[] = {Tlv::kNetworkData}; - Error error = kErrorNone; Router *router; Neighbor::State neighborState; @@ -916,7 +914,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) mLinkRequestAttempts = 0; // completed router sync after reset, no more link request to retransmit mRetrieveNewNetworkData = true; - IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kDataRequestTlvs)); + IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr())); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE Get().HandleTimeSyncMessage(aRxInfo.mMessage); @@ -939,7 +937,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) SerialNumber::IsGreater(leaderData.GetDataVersion(NetworkData::kFullSet), Get().GetVersion(NetworkData::kFullSet))) { - IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kDataRequestTlvs)); + IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr())); } // Route (optional) @@ -1085,6 +1083,7 @@ Error MleRouter::ReadAndProcessRouteTlvOnFed(RxInfo &aRxInfo, uint8_t aParentId) case kErrorNone: SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo)); mRouterTable.UpdateRoutesOnFed(routeTlv, aParentId); + mRequestRouteTlv = false; break; case kErrorNotFound: break; @@ -3159,6 +3158,10 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, SuccessOrExit(error = message->AppendPendingDatasetTlv()); break; + case Tlv::kRoute: + SuccessOrExit(error = message->AppendRouteTlv()); + break; + #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE case Tlv::kLinkMetricsReport: OT_ASSERT(aRequestMessage != nullptr); diff --git a/tests/toranj/cli/test-012-reset-recovery.py b/tests/toranj/cli/test-012-reset-recovery.py index 8af851441..ea92a434c 100755 --- a/tests/toranj/cli/test-012-reset-recovery.py +++ b/tests/toranj/cli/test-012-reset-recovery.py @@ -55,7 +55,7 @@ child2 = cli.Node() # Form topology leader.form('reset') -child1.join(leader, cli.JOIN_TYPE_END_DEVICE) +child1.join(leader, cli.JOIN_TYPE_REED) child2.join(leader, cli.JOIN_TYPE_END_DEVICE) verify(leader.get_state() == 'leader') @@ -135,6 +135,24 @@ def check_leader_neighbor_table(): verify_within(check_leader_neighbor_table, 10) +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# Reset `child` and make sure it re-attaches successfully. + +del child1 +child1 = cli.Node(index=3) +child1.set_router_eligible('disable') +child1.interface_up() +child1.thread_start() + + +def check_child1_state(): + verify(child1.get_state() == 'child') + table = child1.get_router_table() + verify(len(table) == 2) + + +verify_within(check_child1_state, 10) + # ----------------------------------------------------------------------------------------------------------------------- # Test finished