From 0823158ac8ede7328dff87a05914580903e4ecd1 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 10 Feb 2017 09:17:51 -0800 Subject: [PATCH] Handle message re-order for outbound indirect messages (#1298) This commit makes the following changes: - A new field is added in child table, `mIndirectSendMessage` which stores a pointer to the current outbound indirect message for the child. The current offset for the message (in case of 6lowpan fragmentation) is stored in `mFragmentOffset` (as before). - `GetIndirectTransmission()` is simplified to provide the next indirect message for a given child, and the preparation of the source/dest addresses for an indirect message is included in a new method `PrepareIndirectTransmission()`. - In preparation of source address, if `mAddSrcMatchEntryShort` is not set for a child, then the long/extended address is used. This commit addresses the issue where a re-ordering of messages in the queue (due to message priority) could cause an incorrect fragment offset to be applied to an outbound message. --- src/core/thread/mesh_forwarder.cpp | 101 ++++++++++++++++++++--------- src/core/thread/mesh_forwarder.hpp | 1 + src/core/thread/topology.hpp | 4 +- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index c97a10c9e..f48748bf8 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -243,32 +243,51 @@ void MeshForwarder::ScheduleTransmissionTask() for (int i = 0; i < numChildren; i++) { - if (children[i].mState == Child::kStateValid && - children[i].mDataRequest) - { - mSendMessage = GetIndirectTransmission(children[i]); + Child &child = children[i]; - if (mSendMessage != NULL) + if (child.mState != Child::kStateValid || !child.mDataRequest) + { + continue; + } + + mSendMessage = child.mIndirectSendMessage; + + if (mSendMessage == NULL) + { + mSendMessage = GetIndirectTransmission(child); + child.mIndirectSendMessage = mSendMessage; + child.mFragmentOffset = 0; + } + + if (mSendMessage != NULL) + { + mSendMessage->SetOffset(child.mFragmentOffset); + PrepareIndirectTransmission(*mSendMessage, child); + } + else + { + // A NULL `mSendMessage` triggers an empty frame to be sent to the child. + + if (child.mAddSrcMatchEntryShort) { - mSendMessage->SetOffset(children[i].mFragmentOffset); + mMacSource.mLength = sizeof(mMacSource.mShortAddress); + mMacSource.mShortAddress = mNetif.GetMac().GetShortAddress(); + + mMacDest.mLength = sizeof(mMacDest.mShortAddress); + mMacDest.mShortAddress = child.mValid.mRloc16; } else { - if (children[i].mAddSrcMatchEntryShort) - { - mMacDest.mLength = sizeof(mMacDest.mShortAddress); - mMacDest.mShortAddress = children[i].mValid.mRloc16; - } - else - { - mMacDest.mLength = sizeof(mMacDest.mExtAddress); - memcpy(mMacDest.mExtAddress.m8, children[i].mMacAddr.m8, sizeof(mMacDest.mExtAddress)); - } - } + mMacSource.mLength = sizeof(mMacSource.mExtAddress); + memcpy(mMacSource.mExtAddress.m8, mNetif.GetMac().GetExtAddress(), sizeof(mMacDest.mExtAddress)); - mNetif.GetMac().SendFrameRequest(mMacSender); - ExitNow(); + mMacDest.mLength = sizeof(mMacDest.mExtAddress); + memcpy(mMacDest.mExtAddress.m8, child.mMacAddr.m8, sizeof(mMacDest.mExtAddress)); + } } + + mNetif.GetMac().SendFrameRequest(mMacSender); + ExitNow(); } if ((mSendMessage = GetDirectTransmission()) != NULL) @@ -554,7 +573,6 @@ Message *MeshForwarder::GetIndirectTransmission(const Child &aChild) { Message *message = NULL; uint8_t childIndex = mNetif.GetMle().GetChildIndex(aChild); - Ip6::Header ip6Header; for (message = mSendQueue.GetHead(); message; message = message->GetNext()) { @@ -564,12 +582,18 @@ Message *MeshForwarder::GetIndirectTransmission(const Child &aChild) } } - VerifyOrExit(message != NULL, ;); + return message; +} - switch (message->GetType()) +void MeshForwarder::PrepareIndirectTransmission(const Message &aMessage, const Child &aChild) +{ + switch (aMessage.GetType()) { case Message::kTypeIp6: - message->Read(0, sizeof(ip6Header), &ip6Header); + { + Ip6::Header ip6Header; + + aMessage.Read(0, sizeof(ip6Header), &ip6Header); mAddMeshHeader = false; GetMacSourceAddress(ip6Header.GetSource(), mMacSource); @@ -580,17 +604,26 @@ Message *MeshForwarder::GetIndirectTransmission(const Child &aChild) } else { - mMacDest.mLength = sizeof(mMacDest.mShortAddress); - mMacDest.mShortAddress = aChild.mValid.mRloc16; + if (aChild.mAddSrcMatchEntryShort) + { + mMacDest.mLength = sizeof(mMacDest.mShortAddress); + mMacDest.mShortAddress = aChild.mValid.mRloc16; + } + else + { + mMacDest.mLength = sizeof(mMacDest.mExtAddress); + memcpy(mMacDest.mExtAddress.m8, aChild.mMacAddr.m8, sizeof(mMacDest.mExtAddress)); + } } break; + } case Message::kType6lowpan: { Lowpan::MeshHeader meshHeader; - IgnoreReturnValue(meshHeader.Init(*message)); + IgnoreReturnValue(meshHeader.Init(aMessage)); mAddMeshHeader = true; mMeshDest = meshHeader.GetDestination(); mMeshSource = meshHeader.GetSource(); @@ -605,12 +638,8 @@ Message *MeshForwarder::GetIndirectTransmission(const Child &aChild) assert(false); break; } - -exit: - return message; } - ThreadError MeshForwarder::UpdateMeshRoute(Message &aMessage) { ThreadError error = kThreadError_None; @@ -1548,11 +1577,19 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, ThreadError aError) if (mMessageNextOffset < mSendMessage->GetLength()) { - child->mFragmentOffset = mMessageNextOffset; + if (mSendMessage == child->mIndirectSendMessage) + { + child->mFragmentOffset = mMessageNextOffset; + } } else { - child->mFragmentOffset = 0; + if (mSendMessage == child->mIndirectSendMessage) + { + child->mFragmentOffset = 0; + child->mIndirectSendMessage = NULL; + } + mSendMessage->ClearChildMask(mNetif.GetMle().GetChildIndex(*child)); if ((child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 7ea2ede34..5507b4120 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -233,6 +233,7 @@ private: ThreadError GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr); Message *GetDirectTransmission(void); Message *GetIndirectTransmission(const Child &aChild); + void PrepareIndirectTransmission(const Message &aMessage, const Child &aChild); void HandleMesh(uint8_t *aFrame, uint8_t aPayloadLength, const Mac::Address &aMacSource, const ThreadMessageInfo &aMessageInfo); void HandleFragment(uint8_t *aFrame, uint8_t aPayloadLength, diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index 17a5416a2..77a95cd1e 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -39,6 +39,7 @@ #include #include #include +#include namespace Thread { @@ -107,7 +108,8 @@ public: }; Ip6::Address mIp6Address[kMaxIp6AddressPerChild]; ///< Registered IPv6 addresses uint32_t mTimeout; ///< Child timeout - uint16_t mFragmentOffset; ///< 6LoWPAN fragment offset + uint16_t mFragmentOffset; ///< 6LoWPAN fragment offset for the indirect message + Message *mIndirectSendMessage; ///< Current indirect message being sent. union { uint8_t mRequestTlvs[kMaxRequestTlvs]; ///< Requested MLE TLVs