[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`.
This commit is contained in:
Abtin Keshavarzian
2019-06-18 09:17:25 -07:00
committed by Jonathan Hui
parent 8a039efcf8
commit 936d4efe93
7 changed files with 199 additions and 154 deletions
+1 -2
View File
@@ -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
+124 -11
View File
@@ -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<Mle::MleRouter>().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<Mle::MleRouter>().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<DataPollManager>().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;
+14
View File
@@ -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;
+14 -19
View File
@@ -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<MeshForwarder>().GetSendQueue().GetHead(); message; message = message->GetNext())
{
VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = OT_ERROR_ALREADY);
}
message = Get<MessagePool>().New(Message::kTypeMacDataPoll, 0);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
error = Get<MeshForwarder>().SendMessage(*message);
if (error != OT_ERROR_NONE)
{
message->Free();
}
SuccessOrExit(error = Get<Mac::Mac>().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<MeshForwarder>().UpdateNeighborOnSentFrame(aFrame, aError, macDest);
if (Get<Mle::MleRouter>().GetParentCandidate()->GetState() == Neighbor::kStateInvalid)
{
StopPolling();
Get<Mle::MleRouter>().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:
+4 -3
View File
@@ -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
+36 -113
View File
@@ -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<Mle::MleRouter>().GetParentCandidate();
uint16_t shortAddress;
VerifyOrExit((parent != NULL) && parent->IsStateValidOrRestoring(), error = OT_ERROR_DROP);
shortAddress = Get<Mac::Mac>().GetShortAddress();
if ((shortAddress == Mac::kShortAddrInvalid) || (parent != Get<Mle::MleRouter>().GetParent()))
{
mMacSource.SetExtended(Get<Mac::Mac>().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<Mle::MleRouter>();
@@ -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<Mac::Mac>().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<Mle::MleRouter>().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<Mle::MleRouter>().RemoveNeighbor(*neighbor);
}
}
exit:
return neighbor;
}
void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError)
{
Mle::MleRouter &mle = Get<Mle::MleRouter>();
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())
+6 -6
View File
@@ -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);