diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index ba6520128..480852471 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -366,6 +366,7 @@ bool Message::IsSubTypeMle(void) const mBuffer.mHead.mInfo.mSubType == kSubTypeMleDiscoverRequest || mBuffer.mHead.mInfo.mSubType == kSubTypeMleDiscoverResponse || mBuffer.mHead.mInfo.mSubType == kSubTypeMleChildUpdateRequest || + mBuffer.mHead.mInfo.mSubType == kSubTypeMleDataResponse || mBuffer.mHead.mInfo.mSubType == kSubTypeMleGeneral) { rval = true; diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index c3458edc3..2007a4713 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -218,6 +218,7 @@ public: kSubTypeMleGeneral = 6, ///< General MLE kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request + kSubTypeMleDataResponse = 9, ///< MLE Data Response }; enum diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index a6810fa02..5959d0130 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -174,6 +174,12 @@ public: */ void RemoveMessages(Child &aChild, uint8_t aSubType); + /** + * This method frees unicast/multicast MLE Data Responses from Send Message Queue if any. + * + */ + void RemoveDataResponseMessages(void); + /** * This method evicts the first indirect message in the indirect send queue. * diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index 1bd0fa140..a9e74c56f 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -314,6 +314,43 @@ void MeshForwarder::RemoveMessages(Child &aChild, uint8_t aSubType) } } +void MeshForwarder::RemoveDataResponseMessages(void) +{ + Ip6::Header ip6Header; + + for (Message *message = mSendQueue.GetHead(); message; message = message->GetNext()) + { + if (message->GetSubType() != Message::kSubTypeMleDataResponse) + { + continue; + } + + message->Read(0, sizeof(ip6Header), &ip6Header); + + if (!(ip6Header.GetDestination().IsMulticast())) + { + Child *children; + uint8_t numChildren; + + children = GetNetif().GetMle().GetChildren(&numChildren); + + for (uint8_t i = 0; i < numChildren; i++) + { + IgnoreReturnValue(RemoveMessageFromSleepyChild(*message, children[i])); + } + } + + if (mSendMessage == message) + { + mSendMessage = NULL; + } + + mSendQueue.Dequeue(*message); + LogIp6Message(kMessageDrop, *message, NULL, OT_ERROR_NONE); + message->Free(); + } +} + otError MeshForwarder::GetIndirectTransmission(void) { otError error = OT_ERROR_NOT_FOUND; diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 7c85d678d..957143432 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1565,6 +1565,29 @@ void Mle::HandleDelayedResponseTimer(void) } } +void Mle::RemoveDelayedDataResponseMessage(void) +{ + Message *message = mDelayedResponses.GetHead(); + DelayedResponseHeader delayedResponse; + + while (message != NULL) + { + delayedResponse.ReadFrom(*message); + + if (message->GetSubType() == Message::kSubTypeMleDataResponse) + { + mDelayedResponses.Dequeue(*message); + message->Free(); + LogMleMessage("Remove Delayed Data Response", delayedResponse.GetDestination()); + + // no more than one multicast MLE Data Response in Delayed Message Queue. + break; + } + + message = message->GetNext(); + } +} + otError Mle::SendParentRequest(void) { otError error = OT_ERROR_NONE; diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index f4f384982..656fe47b5 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -937,6 +937,12 @@ public: */ const MessageQueue &GetMessageQueue(void) const { return mDelayedResponses; } + /** + * This method frees multicast MLE Data Response from Delayed Message Queue if any. + * + */ + void RemoveDelayedDataResponseMessage(void); + protected: enum { diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index cd85766f2..673bd685c 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2198,6 +2198,7 @@ otError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::Mess // Remove existing MLE messages netif.GetMeshForwarder().RemoveMessages(*child, Message::kSubTypeMleGeneral); netif.GetMeshForwarder().RemoveMessages(*child, Message::kSubTypeMleChildUpdateRequest); + netif.GetMeshForwarder().RemoveMessages(*child, Message::kSubTypeMleDataResponse); // Link-Layer Frame Counter SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLinkFrameCounter, sizeof(linkFrameCounter), @@ -3131,6 +3132,7 @@ otError MleRouter::SendDataResponse(const Ip6::Address &aDestination, const uint } VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); + message->SetSubType(Message::kSubTypeMleDataResponse); SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataResponse)); SuccessOrExit(error = AppendSourceAddress(*message)); SuccessOrExit(error = AppendLeaderData(*message)); @@ -3159,6 +3161,12 @@ otError MleRouter::SendDataResponse(const Ip6::Address &aDestination, const uint if (aDelay) { + // Remove MLE Data Responses from Send Message Queue. + GetNetif().GetMeshForwarder().RemoveDataResponseMessages(); + + // Remove multicast MLE Data Response from Delayed Message Queue. + RemoveDelayedDataResponseMessage(); + SuccessOrExit(error = AddDelayedResponse(*message, aDestination, aDelay)); LogMleMessage("Delay Data Response", aDestination); }