@@ -217,6 +217,7 @@ void Mle::Stop(StopMode aMode)
217217
218218 VerifyOrExit (!IsDisabled ());
219219
220+ mDelayedSender .Stop ();
220221 Get<KeyManager>().Stop ();
221222 SetStateDetached ();
222223 Get<ThreadNetif>().UnsubscribeMulticast (mRealmLocalAllThreadNodes );
@@ -1737,22 +1738,17 @@ Error Mle::SendChildIdRequest(void)
17371738}
17381739
17391740Error Mle::SendDataRequest (const Ip6::Address &aDestination)
1740- {
1741- return SendDataRequestAfterDelay (aDestination, /* aDelay */ 0 );
1742- }
1743-
1744- Error Mle::SendDataRequestAfterDelay (const Ip6::Address &aDestination, uint16_t aDelay)
17451741{
17461742 static const uint8_t kTlvs [] = {Tlv::kNetworkData , Tlv::kRoute };
17471743
1748- Error error;
1744+ Error error = kErrorNone ;
17491745
1750- mDelayedSender . RemoveDataRequestMessage (aDestination );
1746+ VerifyOrExit ( IsAttached () );
17511747
17521748 // Based on `mRequestRouteTlv` include both Network Data and Route
17531749 // TLVs or only Network Data TLV.
17541750
1755- error = SendDataRequest (aDestination, kTlvs , mRequestRouteTlv ? 2 : 1 , aDelay );
1751+ error = SendDataRequest (aDestination, kTlvs , mRequestRouteTlv ? 2 : 1 );
17561752
17571753 if (IsChild () && !IsRxOnWhenIdle ())
17581754 {
@@ -1764,6 +1760,7 @@ Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t
17641760 }
17651761 }
17661762
1763+ exit:
17671764 return error;
17681765}
17691766
@@ -1773,16 +1770,15 @@ Error Mle::SendDataRequestForLinkMetricsReport(const Ip6::Address
17731770{
17741771 static const uint8_t kTlvs [] = {Tlv::kLinkMetricsReport };
17751772
1776- return SendDataRequest (aDestination, kTlvs , sizeof (kTlvs ), /* aDelay */ 0 , &aQueryInfo);
1773+ return SendDataRequest (aDestination, kTlvs , sizeof (kTlvs ), &aQueryInfo);
17771774}
17781775
17791776Error Mle::SendDataRequest (const Ip6::Address &aDestination,
17801777 const uint8_t *aTlvs,
17811778 uint8_t aTlvsLength,
1782- uint16_t aDelay,
17831779 const LinkMetrics::Initiator::QueryInfo *aQueryInfo)
17841780#else
1785- Error Mle::SendDataRequest (const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay )
1781+ Error Mle::SendDataRequest (const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength)
17861782#endif
17871783{
17881784 Error error = kErrorNone ;
@@ -1798,22 +1794,14 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlv
17981794 }
17991795#endif
18001796
1801- if (aDelay)
1802- {
1803- SuccessOrExit (error = message->SendAfterDelay (aDestination, aDelay));
1804- Log (kMessageDelay , kTypeDataRequest , aDestination);
1805- }
1806- else
1807- {
1808- SuccessOrExit (error = message->AppendActiveAndPendingTimestampTlvs ());
1797+ SuccessOrExit (error = message->AppendActiveAndPendingTimestampTlvs ());
18091798
1810- SuccessOrExit (error = message->SendTo (aDestination));
1811- Log (kMessageSend , kTypeDataRequest , aDestination);
1799+ SuccessOrExit (error = message->SendTo (aDestination));
1800+ Log (kMessageSend , kTypeDataRequest , aDestination);
18121801
1813- if (!IsRxOnWhenIdle ())
1814- {
1815- Get<DataPollSender>().SendFastPolls (DataPollSender::kDefaultFastPolls );
1816- }
1802+ if (!IsRxOnWhenIdle ())
1803+ {
1804+ Get<DataPollSender>().SendFastPolls (DataPollSender::kDefaultFastPolls );
18171805 }
18181806
18191807exit:
@@ -2719,8 +2707,8 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo)
27192707
27202708 if (mRetrieveNewNetworkData || IsNetworkDataNewer (leaderData))
27212709 {
2722- delay = Random::NonCrypto::GetUint16InRange (0 , kMleMaxResponseDelay );
2723- IgnoreError ( SendDataRequestAfterDelay ( aRxInfo.mMessageInfo .GetPeerAddr (), delay) );
2710+ delay = 1 + Random::NonCrypto::GetUint16InRange (0 , kMleMaxResponseDelay );
2711+ mDelayedSender . ScheduleDataRequest ( aRxInfo.mMessageInfo .GetPeerAddr (), delay);
27242712 }
27252713
27262714 aRxInfo.mClass = RxInfo::kPeerMessage ;
@@ -2901,7 +2889,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
29012889
29022890 if (aRxInfo.mMessageInfo .GetSockAddr ().IsMulticast ())
29032891 {
2904- delay = Random::NonCrypto::GetUint16InRange (0 , kMleMaxResponseDelay );
2892+ delay = 1 + Random::NonCrypto::GetUint16InRange (0 , kMleMaxResponseDelay );
29052893 }
29062894 else
29072895 {
@@ -2911,7 +2899,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
29112899 delay = 10 ;
29122900 }
29132901
2914- IgnoreError ( SendDataRequestAfterDelay ( aRxInfo.mMessageInfo .GetPeerAddr (), delay) );
2902+ mDelayedSender . ScheduleDataRequest ( aRxInfo.mMessageInfo .GetPeerAddr (), delay);
29152903 }
29162904 else if (error == kErrorNone )
29172905 {
@@ -4328,100 +4316,210 @@ Mle::DelayedSender::DelayedSender(Instance &aInstance)
43284316{
43294317}
43304318
4331- Error Mle::DelayedSender::SendMessage (TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay)
4319+ void Mle::DelayedSender::Stop (void )
4320+ {
4321+ mTimer .Stop ();
4322+ mSchedules .DequeueAndFreeAll ();
4323+ }
4324+
4325+ void Mle::DelayedSender::ScheduleDataRequest (const Ip6::Address &aDestination, uint16_t aDelay)
4326+ {
4327+ VerifyOrExit (!HasMatchingSchedule (kTypeDataRequest , aDestination));
4328+ AddSchedule (kTypeDataRequest , aDestination, aDelay, nullptr , 0 );
4329+
4330+ exit:
4331+ return ;
4332+ }
4333+
4334+ #if OPENTHREAD_FTD
4335+
4336+ void Mle::DelayedSender::ScheduleParentResponse (const ParentResponseInfo &aInfo, uint16_t aDelay)
4337+ {
4338+ Ip6::Address destination;
4339+
4340+ destination.SetToLinkLocalAddress (aInfo.mChildExtAddress );
4341+
4342+ RemoveMatchingSchedules (kTypeParentResponse , destination);
4343+ AddSchedule (kTypeParentResponse , destination, aDelay, &aInfo, sizeof (aInfo));
4344+ }
4345+
4346+ void Mle::DelayedSender::ScheduleMulticastDataResponse (uint16_t aDelay)
4347+ {
4348+ Ip6::Address destination;
4349+
4350+ destination.SetToLinkLocalAllNodesMulticast ();
4351+
4352+ Get<MeshForwarder>().RemoveDataResponseMessages ();
4353+ RemoveMatchingSchedules (kTypeDataResponse , destination);
4354+ AddSchedule (kTypeDataResponse , destination, aDelay, nullptr , 0 );
4355+ }
4356+
4357+ void Mle::DelayedSender::ScheduleLinkAccept (const LinkAcceptInfo &aInfo, uint16_t aDelay)
4358+ {
4359+ Ip6::Address destination;
4360+
4361+ destination.SetToLinkLocalAddress (aInfo.mExtAddress );
4362+
4363+ RemoveMatchingSchedules (kTypeLinkAccept , destination);
4364+ AddSchedule (kTypeLinkAccept , destination, aDelay, &aInfo, sizeof (aInfo));
4365+ }
4366+
4367+ void Mle::DelayedSender::ScheduleDiscoveryResponse (const Ip6::Address &aDestination,
4368+ const DiscoveryResponseInfo &aInfo,
4369+ uint16_t aDelay)
4370+ {
4371+ AddSchedule (kTypeDiscoveryResponse , aDestination, aDelay, &aInfo, sizeof (aInfo));
4372+ }
4373+
4374+ #endif // OPENTHREAD_FTD
4375+
4376+ void Mle::DelayedSender::AddSchedule (MessageType aMessageType,
4377+ const Ip6::Address &aDestination,
4378+ uint16_t aDelay,
4379+ const void *aInfo,
4380+ uint16_t aInfoSize)
43324381{
4333- Error error = kErrorNone ;
4334- Metadata metadata ;
4382+ Schedule *schedule = Get<MessagePool>(). Allocate (Message:: kTypeOther ) ;
4383+ Header header ;
43354384
4336- metadata.mSendTime = TimerMilli::GetNow () + aDelay;
4337- metadata.mDestination = aDestination;
4385+ VerifyOrExit (schedule != nullptr );
43384386
4339- SuccessOrExit (error = metadata.AppendTo (aMessage));
4340- mQueue .Enqueue (aMessage);
4387+ header.mSendTime = TimerMilli::GetNow () + aDelay;
4388+ header.mDestination = aDestination;
4389+ header.mMessageType = aMessageType;
4390+ SuccessOrExit (schedule->Append (header));
43414391
4342- mTimer .FireAtIfEarlier (metadata.mSendTime );
4392+ if (aInfo != nullptr )
4393+ {
4394+ SuccessOrExit (schedule->AppendBytes (aInfo, aInfoSize));
4395+ }
4396+
4397+ mTimer .FireAtIfEarlier (header.mSendTime );
4398+
4399+ mSchedules .Enqueue (*schedule);
4400+ schedule = nullptr ;
4401+
4402+ Log (kMessageDelay , aMessageType, aDestination);
43434403
43444404exit:
4345- return error ;
4405+ FreeMessage (schedule) ;
43464406}
43474407
43484408void Mle::DelayedSender::HandleTimer (void )
43494409{
43504410 NextFireTime nextSendTime;
4411+ MessageQueue schedulesToExecute;
43514412
4352- for (Message &message : mQueue )
4413+ for (Schedule &schedule : mSchedules )
43534414 {
4354- Metadata metadata ;
4415+ Header header ;
43554416
4356- metadata .ReadFrom (message );
4417+ header .ReadFrom (schedule );
43574418
4358- if (nextSendTime.GetNow () < metadata .mSendTime )
4419+ if (nextSendTime.GetNow () < header .mSendTime )
43594420 {
4360- nextSendTime.UpdateIfEarlier (metadata .mSendTime );
4421+ nextSendTime.UpdateIfEarlier (header .mSendTime );
43614422 }
43624423 else
43634424 {
4364- mQueue .Dequeue (message );
4365- Send ( static_cast <TxMessage &>(message), metadata );
4425+ mSchedules .Dequeue (schedule );
4426+ schedulesToExecute. Enqueue (schedule );
43664427 }
43674428 }
43684429
43694430 mTimer .FireAt (nextSendTime);
4431+
4432+ for (Schedule &schedule : schedulesToExecute)
4433+ {
4434+ Execute (schedule);
4435+ }
4436+
4437+ schedulesToExecute.DequeueAndFreeAll ();
43704438}
43714439
4372- void Mle::DelayedSender::Send (TxMessage &aMessage, const Metadata &aMetadata )
4440+ void Mle::DelayedSender::Execute ( const Schedule &aSchedule )
43734441{
4374- Error error = kErrorNone ;
4442+ Header header ;
43754443
4376- aMetadata. RemoveFrom (aMessage );
4444+ header. ReadFrom (aSchedule );
43774445
4378- if (aMessage. IsMleCommand ( kCommandDataRequest ) )
4446+ switch (header. mMessageType )
43794447 {
4380- SuccessOrExit (error = aMessage.AppendActiveAndPendingTimestampTlvs ());
4381- }
4448+ case kTypeDataRequest :
4449+ IgnoreError (Get<Mle>().SendDataRequest (header.mDestination ));
4450+ break ;
4451+
4452+ #if OPENTHREAD_FTD
4453+ case kTypeParentResponse :
4454+ {
4455+ ParentResponseInfo info;
43824456
4383- SuccessOrExit (error = aMessage.SendTo (aMetadata.mDestination ));
4457+ IgnoreError (aSchedule.Read (sizeof (Header), info));
4458+ Get<MleRouter>().SendParentResponse (info);
4459+ break ;
4460+ }
43844461
4385- Log (kMessageSend , kTypeGenericDelayed , aMetadata.mDestination );
4462+ case kTypeDataResponse :
4463+ Get<MleRouter>().SendMulticastDataResponse ();
4464+ break ;
43864465
4387- if (!Get<Mle>(). IsRxOnWhenIdle ())
4466+ case kTypeLinkAccept :
43884467 {
4389- // Start fast poll mode, assuming enqueued msg is MLE Data Request.
4390- // Note: Finer-grade check may be required when deciding whether or
4391- // not to enter fast poll mode for other type of delayed message.
4468+ LinkAcceptInfo info;
43924469
4393- Get<DataPollSender>().SendFastPolls (DataPollSender::kDefaultFastPolls );
4470+ IgnoreError (aSchedule.Read (sizeof (Header), info));
4471+ IgnoreError (Get<MleRouter>().SendLinkAccept (info));
4472+ break ;
43944473 }
43954474
4396- exit:
4397- if (error != kErrorNone )
4475+ case kTypeDiscoveryResponse :
43984476 {
4399- aMessage.Free ();
4477+ DiscoveryResponseInfo info;
4478+
4479+ IgnoreError (aSchedule.Read (sizeof (Header), info));
4480+ IgnoreError (Get<MleRouter>().SendDiscoveryResponse (header.mDestination , info));
4481+ break ;
44004482 }
4401- }
4483+ # endif // OPENTHREAD_FTD
44024484
4403- void Mle::DelayedSender::RemoveDataResponseMessage ( void )
4404- {
4405- RemoveMessage ( kCommandDataResponse , kTypeDataResponse , nullptr );
4485+ default :
4486+ break ;
4487+ }
44064488}
44074489
4408- void Mle::DelayedSender::RemoveDataRequestMessage ( const Ip6::Address &aDestination)
4490+ bool Mle::DelayedSender::Match ( const Schedule &aSchedule, MessageType aMessageType, const Ip6::Address &aDestination)
44094491{
4410- RemoveMessage (kCommandDataRequest , kTypeDataRequest , &aDestination);
4492+ Header header;
4493+
4494+ header.ReadFrom (aSchedule);
4495+
4496+ return (header.mMessageType == aMessageType) && (header.mDestination == aDestination);
44114497}
44124498
4413- void Mle::DelayedSender::RemoveMessage (Command aCommand, MessageType aMessageType, const Ip6::Address * aDestination)
4499+ bool Mle::DelayedSender::HasMatchingSchedule ( MessageType aMessageType, const Ip6::Address & aDestination) const
44144500{
4415- for (Message &message : mQueue )
4501+ bool hasMatching = false ;
4502+
4503+ for (const Schedule &schedule : mSchedules )
44164504 {
4417- Metadata metadata;
4505+ if (Match (schedule, aMessageType, aDestination))
4506+ {
4507+ hasMatching = true ;
4508+ break ;
4509+ }
4510+ }
44184511
4419- metadata.ReadFrom (message);
4512+ return hasMatching;
4513+ }
44204514
4421- if (message.IsMleCommand (aCommand) && ((aDestination == nullptr ) || (metadata.mDestination == *aDestination)))
4515+ void Mle::DelayedSender::RemoveMatchingSchedules (MessageType aMessageType, const Ip6::Address &aDestination)
4516+ {
4517+ for (Schedule &schedule : mSchedules )
4518+ {
4519+ if (Match (schedule, aMessageType, aDestination))
44224520 {
4423- mQueue .DequeueAndFree (message );
4424- Log (kMessageRemoveDelayed , aMessageType, metadata. mDestination );
4521+ mSchedules .DequeueAndFree (schedule );
4522+ Log (kMessageRemoveDelayed , aMessageType, aDestination );
44254523 }
44264524 }
44274525}
@@ -4846,11 +4944,6 @@ Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination)
48464944 return error;
48474945}
48484946
4849- Error Mle::TxMessage::SendAfterDelay (const Ip6::Address &aDestination, uint16_t aDelay)
4850- {
4851- return Get<Mle>().mDelayedSender .SendMessage (*this , aDestination, aDelay);
4852- }
4853-
48544947#if OPENTHREAD_FTD
48554948
48564949Error Mle::TxMessage::AppendConnectivityTlv (void )
0 commit comments