From 936d4efe9331d132c4d8abf75a27333a5a2f9b53 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 18 Jun 2019 09:17:25 -0700 Subject: [PATCH] [mac] move data poll tx into Mac and DataPollManager (#3915) This commit moves the implementation of data poll transmission related logic into `Mac` and `DataPollManagr` from `MeshForwarder`. --- src/core/common/message.hpp | 3 +- src/core/mac/mac.cpp | 135 +++++++++++++++++++++-- src/core/mac/mac.hpp | 14 +++ src/core/thread/data_poll_manager.cpp | 33 +++--- src/core/thread/data_poll_manager.hpp | 7 +- src/core/thread/mesh_forwarder.cpp | 149 +++++++------------------- src/core/thread/mesh_forwarder.hpp | 12 +-- 7 files changed, 199 insertions(+), 154 deletions(-) diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index befaac388..e1130a7c6 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -206,8 +206,7 @@ public: { kTypeIp6 = 0, ///< A full uncompressed IPv6 packet kType6lowpan = 1, ///< A 6lowpan frame - kTypeMacDataPoll = 2, ///< A MAC data poll message - kTypeSupervision = 3, ///< A child supervision frame. + kTypeSupervision = 2, ///< A child supervision frame. }; enum diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index fe2f77c4a..6704f15bf 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -73,8 +73,10 @@ Mac::Mac(Instance &aInstance) , mPendingEnergyScan(false) , mPendingTransmitBeacon(false) , mPendingTransmitData(false) + , mPendingTransmitPoll(false) , mPendingTransmitOobFrame(false) , mPendingWaitingForData(false) + , mShouldTxPollBeforeData(false) , mRxOnWhenIdle(false) , mBeaconsEnabled(false) #if OPENTHREAD_CONFIG_STAY_AWAKE_BETWEEN_FRAGMENTS @@ -174,8 +176,26 @@ void Mac::Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanD bool Mac::IsInTransmitState(void) const { - return (mOperation == kOperationTransmitData) || (mOperation == kOperationTransmitBeacon) || - (mOperation == kOperationTransmitOutOfBandFrame); + bool retval = false; + + switch (mOperation) + { + case kOperationTransmitData: + case kOperationTransmitBeacon: + case kOperationTransmitPoll: + case kOperationTransmitOutOfBandFrame: + retval = true; + break; + + case kOperationIdle: + case kOperationActiveScan: + case kOperationEnergyScan: + case kOperationWaitingForData: + retval = false; + break; + } + + return retval; } otError Mac::ConvertBeaconToActiveScanResult(Frame *aBeaconFrame, otActiveScanResult &aResult) @@ -488,6 +508,25 @@ exit: return error; } +otError Mac::RequestDataPollTransmission(void) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE); + VerifyOrExit(!mPendingTransmitPoll && (mOperation != kOperationTransmitPoll), error = OT_ERROR_ALREADY); + + // We ensure data frame and data poll tx requests are handled in the + // order they are requested. So if we have a pending data frame tx + // request, it should be sent before the poll frame. + + mShouldTxPollBeforeData = !mPendingTransmitData; + + StartOperation(kOperationTransmitPoll); + +exit: + return error; +} + void Mac::UpdateIdleMode(void) { bool shouldSleep = !mRxOnWhenIdle && !mPromiscuous; @@ -562,6 +601,10 @@ void Mac::StartOperation(Operation aOperation) mPendingTransmitData = true; break; + case kOperationTransmitPoll: + mPendingTransmitPoll = true; + break; + case kOperationWaitingForData: mPendingWaitingForData = true; break; @@ -594,6 +637,7 @@ void Mac::PerformNextOperation(void) mPendingEnergyScan = false; mPendingTransmitBeacon = false; mPendingTransmitData = false; + mPendingTransmitPoll = false; mTimer.Stop(); #if OPENTHREAD_CONFIG_STAY_AWAKE_BETWEEN_FRAGMENTS mDelayingSleep = false; @@ -630,6 +674,11 @@ void Mac::PerformNextOperation(void) mPendingTransmitBeacon = false; mOperation = kOperationTransmitBeacon; } + else if (mPendingTransmitPoll && (!mPendingTransmitData || mShouldTxPollBeforeData)) + { + mPendingTransmitPoll = false; + mOperation = kOperationTransmitPoll; + } else if (mPendingTransmitData) { mPendingTransmitData = false; @@ -657,6 +706,7 @@ void Mac::PerformNextOperation(void) case kOperationTransmitBeacon: case kOperationTransmitData: + case kOperationTransmitPoll: case kOperationTransmitOutOfBandFrame: BeginTransmit(); break; @@ -697,6 +747,49 @@ void Mac::GenerateNonce(const ExtAddress &aAddress, uint32_t aFrameCounter, uint aNonce[0] = aSecurityLevel; } +otError Mac::PrepareDataRequest(Frame &aFrame) +{ + otError error = OT_ERROR_NONE; + Neighbor *parent = Get().GetParentCandidate(); + uint16_t fcf; + bool useExtendedAddr; + + VerifyOrExit((parent != NULL) && parent->IsStateValidOrRestoring(), error = OT_ERROR_ABORT); + + fcf = Frame::kFcfFrameMacCmd | Frame::kFcfPanidCompression | Frame::kFcfFrameVersion2006 | Frame::kFcfAckRequest | + Frame::kFcfSecurityEnabled; + + useExtendedAddr = (GetShortAddress() == kShortAddrInvalid) || (parent != Get().GetParent()); + + if (useExtendedAddr) + { + fcf |= Frame::kFcfDstAddrExt | Frame::kFcfSrcAddrExt; + } + else + { + fcf |= Frame::kFcfDstAddrShort | Frame::kFcfSrcAddrShort; + } + + aFrame.InitMacHeader(fcf, Frame::kKeyIdMode1 | Frame::kSecEncMic32); + aFrame.SetDstPanId(GetPanId()); + + if (useExtendedAddr) + { + aFrame.SetSrcAddr(GetExtAddress()); + aFrame.SetDstAddr(parent->GetExtAddress()); + } + else + { + aFrame.SetSrcAddr(GetShortAddress()); + aFrame.SetDstAddr(parent->GetRloc16()); + } + + aFrame.SetCommandId(Frame::kMacCmdDataRequest); + +exit: + return error; +} + void Mac::PrepareBeaconRequest(Frame &aFrame) { uint16_t fcf = Frame::kFcfFrameMacCmd | Frame::kFcfDstAddrShort | Frame::kFcfSrcAddrNone; @@ -912,6 +1005,14 @@ void Mac::BeginTransmit(void) sendFrame.SetMaxFrameRetries(kMaxFrameRetriesDirect); break; + case kOperationTransmitPoll: + sendFrame.SetChannel(mRadioChannel); + SuccessOrExit(error = PrepareDataRequest(sendFrame)); + sendFrame.SetSequence(mDataSequence++); + sendFrame.SetMaxCsmaBackoffs(kMaxCsmaBackoffsDirect); + sendFrame.SetMaxFrameRetries(kMaxFrameRetriesDirect); + break; + case kOperationTransmitData: sendFrame.SetChannel(mRadioChannel); @@ -1141,23 +1242,31 @@ void Mac::HandleTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError) PerformNextOperation(); break; - case kOperationTransmitData: - if (aFrame.IsDataRequestCommand()) + case kOperationTransmitPoll: + assert(aFrame.GetAckRequest()); + + if ((aError == OT_ERROR_NONE) && (aAckFrame != NULL)) { - if (mEnabled && (aError == OT_ERROR_NONE) && aFrame.GetAckRequest() && (aAckFrame != NULL) && - aAckFrame->GetFramePending()) + bool framePending = aAckFrame->GetFramePending(); + + if (mEnabled && framePending) { mTimer.Start(kDataPollTimeout); StartOperation(kOperationWaitingForData); } - mCounters.mTxDataPoll++; - } - else - { - mCounters.mTxData++; + otLogInfoMac("Sent data poll, fp:%s", framePending ? "yes" : "no"); } + mCounters.mTxDataPoll++; + FinishOperation(); + Get().HandlePollSent(aFrame, aError); + PerformNextOperation(); + break; + + case kOperationTransmitData: + mCounters.mTxData++; + if (!aFrame.IsARetransmission()) { mDataSequence++; @@ -1759,6 +1868,10 @@ const char *Mac::OperationToString(Operation aOperation) retval = "TransmitData"; break; + case kOperationTransmitPoll: + retval = "TransmitPoll"; + break; + case kOperationWaitingForData: retval = "WaitingForData"; break; diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index efece73e9..95c9e8c57 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -232,6 +232,16 @@ public: */ otError RequestOutOfBandFrameTransmission(otRadioFrame *aOobFrame); + /** + * This method requests transmission of a data poll (MAC Data Request) frame. + * + * @retval OT_ERROR_NONE Data poll transmission request is scheduled successfully. + * @retval OT_ERROR_ALREADY MAC is busy sending earlier poll transmission request. + * @retval OT_ERROR_INVALID_STATE The MAC layer is not enabled. + * + */ + otError RequestDataPollTransmission(void); + /** * This method returns a reference to the IEEE 802.15.4 Extended Address. * @@ -591,6 +601,7 @@ private: kOperationEnergyScan, kOperationTransmitBeacon, kOperationTransmitData, + kOperationTransmitPoll, kOperationWaitingForData, kOperationTransmitOutOfBandFrame, }; @@ -618,6 +629,7 @@ private: void StartOperation(Operation aOperation); void FinishOperation(void); void PerformNextOperation(void); + otError PrepareDataRequest(Frame &aFrame); void PrepareBeaconRequest(Frame &aFrame); void PrepareBeacon(Frame &aFrame); bool ShouldSendBeacon(void) const; @@ -651,8 +663,10 @@ private: bool mPendingEnergyScan : 1; bool mPendingTransmitBeacon : 1; bool mPendingTransmitData : 1; + bool mPendingTransmitPoll : 1; bool mPendingTransmitOobFrame : 1; bool mPendingWaitingForData : 1; + bool mShouldTxPollBeforeData : 1; bool mRxOnWhenIdle : 1; bool mPromiscuous : 1; bool mBeaconsEnabled : 1; diff --git a/src/core/thread/data_poll_manager.cpp b/src/core/thread/data_poll_manager.cpp index 25c4927a1..f407766a4 100644 --- a/src/core/thread/data_poll_manager.cpp +++ b/src/core/thread/data_poll_manager.cpp @@ -93,7 +93,6 @@ void DataPollManager::StopPolling(void) otError DataPollManager::SendDataPoll(void) { otError error; - Message * message; Neighbor *parent; VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE); @@ -104,20 +103,7 @@ otError DataPollManager::SendDataPoll(void) mTimer.Stop(); - for (message = Get().GetSendQueue().GetHead(); message; message = message->GetNext()) - { - VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = OT_ERROR_ALREADY); - } - - message = Get().New(Message::kTypeMacDataPoll, 0); - VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); - - error = Get().SendMessage(*message); - - if (error != OT_ERROR_NONE) - { - message->Free(); - } + SuccessOrExit(error = Get().RequestDataPollTransmission()); exit: @@ -203,12 +189,23 @@ uint32_t DataPollManager::GetKeepAlivePollPeriod(void) const return period; } -void DataPollManager::HandlePollSent(otError aError) +void DataPollManager::HandlePollSent(Mac::Frame &aFrame, otError aError) { - bool shouldRecalculatePollPeriod = false; + Mac::Address macDest; + bool shouldRecalculatePollPeriod = false; VerifyOrExit(mEnabled); + aFrame.GetDstAddr(macDest); + Get().UpdateNeighborOnSentFrame(aFrame, aError, macDest); + + if (Get().GetParentCandidate()->GetState() == Neighbor::kStateInvalid) + { + StopPolling(); + Get().BecomeDetached(); + ExitNow(); + } + switch (aError) { case OT_ERROR_NONE: @@ -231,8 +228,6 @@ void DataPollManager::HandlePollSent(otError aError) shouldRecalculatePollPeriod = true; } - otLogInfoMac("Sent data poll"); - break; case OT_ERROR_CHANNEL_ACCESS_FAILURE: diff --git a/src/core/thread/data_poll_manager.hpp b/src/core/thread/data_poll_manager.hpp index e9ee82f5f..4d7745953 100644 --- a/src/core/thread/data_poll_manager.hpp +++ b/src/core/thread/data_poll_manager.hpp @@ -132,16 +132,17 @@ public: uint32_t GetExternalPollPeriod(void) const { return mExternalPollPeriod; } /** - * This method informs the data poll manager of success/error status of a previously requested poll message + * This method informs the data poll manager of success/error status of a previously requested poll frame * transmission. * * In case of transmit failure, the data poll manager may choose to send the next data poll more quickly (up to * some fixed number of attempts). * - * @param[in] aError Error status of a data poll message transmission. + * @param[in] aFrame The data poll frame. + * @param[in] aError Error status of a data poll message transmission. * */ - void HandlePollSent(otError aError); + void HandlePollSent(Mac::Frame &aFrame, otError aError); /** * This method informs the data poll manager that a data poll timeout happened, i.e., when the ack in response to diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 5be1c0fab..943efe122 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -247,10 +247,6 @@ Message *MeshForwarder::GetDirectTransmission(void) break; - case Message::kTypeMacDataPoll: - error = PrepareDataPoll(); - break; - #if OPENTHREAD_FTD case Message::kType6lowpan: @@ -295,31 +291,6 @@ exit: return curMessage; } -otError MeshForwarder::PrepareDataPoll(void) -{ - otError error = OT_ERROR_NONE; - Neighbor *parent = Get().GetParentCandidate(); - uint16_t shortAddress; - - VerifyOrExit((parent != NULL) && parent->IsStateValidOrRestoring(), error = OT_ERROR_DROP); - - shortAddress = Get().GetShortAddress(); - - if ((shortAddress == Mac::kShortAddrInvalid) || (parent != Get().GetParent())) - { - mMacSource.SetExtended(Get().GetExtAddress()); - mMacDest.SetExtended(parent->GetExtAddress()); - } - else - { - mMacSource.SetShort(shortAddress); - mMacDest.SetShort(parent->GetRloc16()); - } - -exit: - return error; -} - otError MeshForwarder::UpdateIp6Route(Message &aMessage) { Mle::MleRouter &mle = Get(); @@ -581,10 +552,6 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame) assert(aFrame.GetLength() != 7); break; - case Message::kTypeMacDataPoll: - SendPoll(*mSendMessage, aFrame); - break; - #if OPENTHREAD_FTD case Message::kType6lowpan: @@ -647,33 +614,6 @@ exit: return error; } -void MeshForwarder::SendPoll(Message &aMessage, Mac::Frame &aFrame) -{ - uint16_t fcf; - - // initialize MAC header - fcf = Mac::Frame::kFcfFrameMacCmd | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfFrameVersion2006; - - if (mMacSource.IsShort()) - { - fcf |= Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort; - } - else - { - fcf |= Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt; - } - - fcf |= Mac::Frame::kFcfAckRequest | Mac::Frame::kFcfSecurityEnabled; - - aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32); - aFrame.SetDstPanId(Get().GetPanId()); - aFrame.SetSrcAddr(mMacSource); - aFrame.SetDstAddr(mMacDest); - aFrame.SetCommandId(Mac::Frame::kMacCmdDataRequest); - - mMessageNextOffset = aMessage.GetLength(); -} - otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) { Mac::Address meshDest, meshSource; @@ -1000,52 +940,50 @@ void MeshForwarder::SendEmptyFrame(Mac::Frame &aFrame, bool aAckRequest) aFrame.SetFramePending(false); } +Neighbor *MeshForwarder::UpdateNeighborOnSentFrame(Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest) +{ + Neighbor *neighbor = NULL; + + VerifyOrExit(mEnabled); + + neighbor = Get().GetNeighbor(aMacDest); + VerifyOrExit(neighbor != NULL); + + VerifyOrExit(aFrame.GetAckRequest()); + + if (aError == OT_ERROR_NONE) + { + neighbor->ResetLinkFailures(); + } + else if (aError == OT_ERROR_NO_ACK) + { + neighbor->IncrementLinkFailures(); + VerifyOrExit(Mle::Mle::IsActiveRouter(neighbor->GetRloc16())); + + if (neighbor->GetLinkFailures() >= Mle::kFailedRouterTransmissions) + { + Get().RemoveNeighbor(*neighbor); + } + } + +exit: + return neighbor; +} + void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError) { - Mle::MleRouter &mle = Get(); - Mac::Address macDest; - Neighbor * neighbor; + Neighbor * neighbor = NULL; + Mac::Address macDest; + + assert((aError == OT_ERROR_NONE) || (aError == OT_ERROR_CHANNEL_ACCESS_FAILURE) || (aError == OT_ERROR_ABORT) || + (aError == OT_ERROR_NO_ACK)); mSendBusy = false; VerifyOrExit(mEnabled); aFrame.GetDstAddr(macDest); - - if ((neighbor = mle.GetNeighbor(macDest)) != NULL) - { - switch (aError) - { - case OT_ERROR_NONE: - if (aFrame.GetAckRequest()) - { - neighbor->ResetLinkFailures(); - } - - break; - - case OT_ERROR_CHANNEL_ACCESS_FAILURE: - case OT_ERROR_ABORT: - break; - - case OT_ERROR_NO_ACK: - neighbor->IncrementLinkFailures(); - - if (Mle::Mle::IsActiveRouter(neighbor->GetRloc16())) - { - if (neighbor->GetLinkFailures() >= Mle::kFailedRouterTransmissions) - { - mle.RemoveNeighbor(*neighbor); - } - } - - break; - - default: - assert(false); - break; - } - } + neighbor = UpdateNeighborOnSentFrame(aFrame, aError, macDest); #if OPENTHREAD_FTD HandleSentFrameToChild(aFrame, aError, macDest); @@ -1126,21 +1064,6 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError) } } - if (mSendMessage->GetType() == Message::kTypeMacDataPoll) - { - neighbor = mle.GetParentCandidate(); - - if (neighbor->GetState() == Neighbor::kStateInvalid) - { - mDataPollManager.StopPolling(); - mle.BecomeDetached(); - } - else - { - mDataPollManager.HandlePollSent(aError); - } - } - if (mSendMessage->GetDirectTransmission() == false && mSendMessage->IsChildPending() == false) { if (mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest && mSendMessage->IsLinkSecurityEnabled()) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 0fb88da52..00f5eb4b1 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -169,6 +169,7 @@ class MeshForwarder : public InstanceLocator { friend class Mac::Mac; friend class Instance; + friend class DataPollManager; public: /** @@ -383,7 +384,6 @@ private: Message *GetIndirectTransmission(Child &aChild); otError PrepareDiscoverRequest(void); void PrepareIndirectTransmission(Message &aMessage, const Child &aChild); - otError PrepareDataPoll(void); void HandleMesh(uint8_t * aFrame, uint8_t aFrameLength, const Mac::Address & aMacSource, @@ -404,7 +404,6 @@ private: uint8_t aFrameLength, Lowpan::FragmentHeader &aFragmentHeader); - void SendPoll(Message &aMessage, Mac::Frame &aFrame); void SendMesh(Message &aMessage, Mac::Frame &aFrame); otError SendFragment(Message &aMessage, Mac::Frame &aFrame); void SendEmptyFrame(Mac::Frame &aFrame, bool aAckRequest); @@ -423,10 +422,11 @@ private: void RemoveMessage(Message &aMessage); void HandleDiscoverComplete(void); - void HandleReceivedFrame(Mac::Frame &aFrame); - otError HandleFrameRequest(Mac::Frame &aFrame); - void HandleSentFrame(Mac::Frame &aFrame, otError aError); - void HandleSentFrameToChild(const Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest); + void HandleReceivedFrame(Mac::Frame &aFrame); + otError HandleFrameRequest(Mac::Frame &aFrame); + Neighbor *UpdateNeighborOnSentFrame(Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest); + void HandleSentFrame(Mac::Frame &aFrame, otError aError); + void HandleSentFrameToChild(const Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest); static void HandleDiscoverTimer(Timer &aTimer); void HandleDiscoverTimer(void);