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