diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 74bc32362a4..bcc13430479 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -82,12 +82,12 @@ Mle::Mle(Instance &aInstance) #endif , mAlternateTimestamp(0) , mNeighborTable(aInstance) + , mDelayedSender(aInstance) , mSocket(aInstance, *this) #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE , mParentSearch(aInstance) #endif , mAttachTimer(aInstance) - , mDelayedResponseTimer(aInstance) , mMessageTransmissionTimer(aInstance) , mDetachGracefullyTimer(aInstance) { @@ -1563,88 +1563,6 @@ uint32_t Mle::Reattach(void) return delay; } -void Mle::HandleDelayedResponseTimer(void) -{ - NextFireTime nextSendTime; - - for (Message &message : mDelayedResponses) - { - DelayedResponseMetadata metadata; - - metadata.ReadFrom(message); - - if (nextSendTime.GetNow() < metadata.mSendTime) - { - nextSendTime.UpdateIfEarlier(metadata.mSendTime); - } - else - { - mDelayedResponses.Dequeue(message); - SendDelayedResponse(static_cast(message), metadata); - } - } - - mDelayedResponseTimer.FireAt(nextSendTime); -} - -void Mle::SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata &aMetadata) -{ - Error error = kErrorNone; - - aMetadata.RemoveFrom(aMessage); - - if (aMessage.GetSubType() == Message::kSubTypeMleDataRequest) - { - SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs()); - } - - SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination)); - - Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination); - - if (!IsRxOnWhenIdle()) - { - // Start fast poll mode, assuming enqueued msg is MLE Data Request. - // Note: Finer-grade check may be required when deciding whether or - // not to enter fast poll mode for other type of delayed message. - - Get().SendFastPolls(DataPollSender::kDefaultFastPolls); - } - -exit: - if (error != kErrorNone) - { - aMessage.Free(); - } -} - -void Mle::RemoveDelayedDataResponseMessage(void) -{ - RemoveDelayedMessage(Message::kSubTypeMleDataResponse, kTypeDataResponse, nullptr); -} - -void Mle::RemoveDelayedDataRequestMessage(const Ip6::Address &aDestination) -{ - RemoveDelayedMessage(Message::kSubTypeMleDataRequest, kTypeDataRequest, &aDestination); -} - -void Mle::RemoveDelayedMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination) -{ - for (Message &message : mDelayedResponses) - { - DelayedResponseMetadata metadata; - - metadata.ReadFrom(message); - - if ((message.GetSubType() == aSubType) && - ((aDestination == nullptr) || (metadata.mDestination == *aDestination))) - { - mDelayedResponses.DequeueAndFree(message); - Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination); - } - } -} - void Mle::SendParentRequest(ParentRequestType aType) { Error error = kErrorNone; @@ -1821,7 +1739,7 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlv Error error = kErrorNone; TxMessage *message; - RemoveDelayedDataRequestMessage(aDestination); + mDelayedSender.RemoveDataRequestMessage(aDestination); VerifyOrExit((message = NewMleMessage(kCommandDataRequest)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendTlvRequestTlv(aTlvs, aTlvsLength)); @@ -4386,9 +4304,116 @@ void Mle::TlvList::AddElementsFrom(const TlvList &aTlvList) } //--------------------------------------------------------------------------------------------------------------------- -// DelayedResponseMetadata +// DelayedSender -void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage) +Mle::DelayedSender::DelayedSender(Instance &aInstance) + : InstanceLocator(aInstance) + , mTimer(aInstance) +{ +} + +Error Mle::DelayedSender::SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay) +{ + Error error = kErrorNone; + Metadata metadata; + + metadata.mSendTime = TimerMilli::GetNow() + aDelay; + metadata.mDestination = aDestination; + + SuccessOrExit(error = metadata.AppendTo(aMessage)); + mQueue.Enqueue(aMessage); + + mTimer.FireAtIfEarlier(metadata.mSendTime); + +exit: + return error; +} + +void Mle::DelayedSender::HandleTimer(void) +{ + NextFireTime nextSendTime; + + for (Message &message : mQueue) + { + Metadata metadata; + + metadata.ReadFrom(message); + + if (nextSendTime.GetNow() < metadata.mSendTime) + { + nextSendTime.UpdateIfEarlier(metadata.mSendTime); + } + else + { + mQueue.Dequeue(message); + Send(static_cast(message), metadata); + } + } + + mTimer.FireAt(nextSendTime); +} + +void Mle::DelayedSender::Send(TxMessage &aMessage, const Metadata &aMetadata) +{ + Error error = kErrorNone; + + aMetadata.RemoveFrom(aMessage); + + if (aMessage.GetSubType() == Message::kSubTypeMleDataRequest) + { + SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs()); + } + + SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination)); + + Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination); + + if (!Get().IsRxOnWhenIdle()) + { + // Start fast poll mode, assuming enqueued msg is MLE Data Request. + // Note: Finer-grade check may be required when deciding whether or + // not to enter fast poll mode for other type of delayed message. + + Get().SendFastPolls(DataPollSender::kDefaultFastPolls); + } + +exit: + if (error != kErrorNone) + { + aMessage.Free(); + } +} + +void Mle::DelayedSender::RemoveDataResponseMessage(void) +{ + RemoveMessage(Message::kSubTypeMleDataResponse, kTypeDataResponse, nullptr); +} + +void Mle::DelayedSender::RemoveDataRequestMessage(const Ip6::Address &aDestination) +{ + RemoveMessage(Message::kSubTypeMleDataRequest, kTypeDataRequest, &aDestination); +} + +void Mle::DelayedSender::RemoveMessage(Message::SubType aSubType, + MessageType aMessageType, + const Ip6::Address *aDestination) +{ + for (Message &message : mQueue) + { + Metadata metadata; + + metadata.ReadFrom(message); + + if ((message.GetSubType() == aSubType) && + ((aDestination == nullptr) || (metadata.mDestination == *aDestination))) + { + mQueue.DequeueAndFree(message); + Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination); + } + } +} + +void Mle::DelayedSender::Metadata::ReadFrom(const Message &aMessage) { uint16_t length = aMessage.GetLength(); @@ -4396,7 +4421,7 @@ void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage) IgnoreError(aMessage.Read(length - sizeof(*this), *this)); } -void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const { aMessage.RemoveFooter(sizeof(*this)); } +void Mle::DelayedSender::Metadata::RemoveFrom(Message &aMessage) const { aMessage.RemoveFooter(sizeof(*this)); } //--------------------------------------------------------------------------------------------------------------------- // TxMessage @@ -4852,19 +4877,7 @@ Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination) Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay) { - Error error = kErrorNone; - DelayedResponseMetadata metadata; - - metadata.mSendTime = TimerMilli::GetNow() + aDelay; - metadata.mDestination = aDestination; - - SuccessOrExit(error = metadata.AppendTo(*this)); - Get().mDelayedResponses.Enqueue(*this); - - Get().mDelayedResponseTimer.FireAtIfEarlier(metadata.mSendTime); - -exit: - return error; + return Get().mDelayedSender.SendMessage(*this, aDestination, aDelay); } #if OPENTHREAD_FTD diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 20ca9cde9f9..7de278f2141 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -586,12 +586,7 @@ class Mle : public InstanceLocator, private NonCopyable * * @returns A reference to the send queue. */ - const MessageQueue &GetMessageQueue(void) const { return mDelayedResponses; } - - /** - * Frees multicast MLE Data Response from Delayed Message Queue if any. - */ - void RemoveDelayedDataResponseMessage(void); + const MessageQueue &GetMessageQueue(void) const { return mDelayedSender.GetQueue(); } /** * Gets the MLE counters. @@ -1093,14 +1088,38 @@ class Mle : public InstanceLocator, private NonCopyable //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct DelayedResponseMetadata + void HandleDelayedSenderTimer(void) { mDelayedSender.HandleTimer(); } + + class DelayedSender : public InstanceLocator { - Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); } - void ReadFrom(const Message &aMessage); - void RemoveFrom(Message &aMessage) const; + public: + explicit DelayedSender(Instance &aInstance); + + Error SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay); + void RemoveDataRequestMessage(const Ip6::Address &aDestination); + void RemoveDataResponseMessage(void); + void HandleTimer(void); + + const MessageQueue &GetQueue(void) const { return mQueue; } + + private: + struct Metadata + { + Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); } + void ReadFrom(const Message &aMessage); + void RemoveFrom(Message &aMessage) const; + + Ip6::Address mDestination; + TimeMilli mSendTime; + }; + + void Send(TxMessage &aMessage, const Metadata &aMetadata); + void RemoveMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination); + + using DelayTimer = TimerMilliIn; - Ip6::Address mDestination; // IPv6 address of the message destination. - TimeMilli mSendTime; // Time when the message shall be sent. + MessageQueue mQueue; + DelayTimer mTimer; }; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1223,7 +1242,6 @@ class Mle : public InstanceLocator, private NonCopyable void ClearParentCandidate(void) { mParentCandidate.Clear(); } Error SendDataRequest(const Ip6::Address &aDestination); void HandleNotifierEvents(Events aEvents); - void SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata &aMetadata); void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void ReestablishLinkWithNeighbor(Neighbor &aNeighbor); void HandleDetachGracefullyTimer(void); @@ -1243,7 +1261,6 @@ class Mle : public InstanceLocator, private NonCopyable bool IsAnnounceAttach(void) const { return mAlternatePanId != Mac::kPanIdBroadcast; } void ScheduleMessageTransmissionTimer(void); void HandleAttachTimer(void); - void HandleDelayedResponseTimer(void); void HandleMessageTransmissionTimer(void); void ProcessKeySequence(RxInfo &aRxInfo); void HandleAdvertisement(RxInfo &aRxInfo); @@ -1280,8 +1297,6 @@ class Mle : public InstanceLocator, private NonCopyable const Ip6::MessageInfo &aMessageInfo, uint16_t aCmdOffset, const SecurityHeader &aHeader); - void RemoveDelayedMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination); - void RemoveDelayedDataRequestMessage(const Ip6::Address &aDestination); #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH void InformPreviousParent(void); @@ -1352,7 +1367,6 @@ class Mle : public InstanceLocator, private NonCopyable using DetachGracefullyTimer = TimerMilliIn; using AttachTimer = TimerMilliIn; - using DelayTimer = TimerMilliIn; using MsgTxTimer = TimerMilliIn; using MleSocket = Ip6::Udp::SocketIn; @@ -1402,7 +1416,7 @@ class Mle : public InstanceLocator, private NonCopyable LeaderData mLeaderData; Parent mParent; NeighborTable mNeighborTable; - MessageQueue mDelayedResponses; + DelayedSender mDelayedSender; TxChallenge mParentRequestChallenge; ParentCandidate mParentCandidate; MleSocket mSocket; @@ -1418,7 +1432,6 @@ class Mle : public InstanceLocator, private NonCopyable Callback mParentResponseCallback; #endif AttachTimer mAttachTimer; - DelayTimer mDelayedResponseTimer; MsgTxTimer mMessageTransmissionTimer; DetachGracefullyTimer mDetachGracefullyTimer; Ip6::NetworkPrefix mMeshLocalPrefix; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 988fa184144..d1ae5682f59 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3116,7 +3116,7 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination, { Get().RemoveDataResponseMessages(); - RemoveDelayedDataResponseMessage(); + mDelayedSender.RemoveDataResponseMessage(); SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay)); Log(kMessageDelay, kTypeDataResponse, aDestination);