[mac] set tx frame as empty when tx aborted during frame preparation (#4265)

The TxDone callbacks can be invoked with `OT_ERROR_ABORT` from two
different paths: Either when OpenThread itself cannot prepare the tx
frame (e.g., message was removed while waiting for MAC to handle a tx
request and ask next layers to prepare the frame) or when the radio
platform itself need to abort the tx.

This commit changes the code such that in the first case, the frame
length is set to zero to mark it as empty. The empty frame helps
differentiate between the two cases and ensures that a previously tx
frame is not incorrectly used from the TxDone callbacks.

The TxDone callback handlers (in `MeshForwarder`, `DataPollHanlder`,
`IndirectSender` and `DataPollHandler` are updated to check for frame
not being empty when processing the frame.
This commit is contained in:
Abtin Keshavarzian
2019-10-24 08:46:54 -07:00
committed by Jonathan Hui
parent aaafa1a480
commit ed8c9f18df
6 changed files with 51 additions and 21 deletions
+1 -1
View File
@@ -250,7 +250,7 @@ void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, otError aError
ExitNow();
}
if (aChild.GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts)
if ((aChild.GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts) && !aFrame.IsEmpty())
{
// We save the frame counter, key id, and data sequence number of
// current frame so we use the same values for the retransmission
+5 -2
View File
@@ -199,8 +199,11 @@ void DataPollSender::HandlePollSent(Mac::TxFrame &aFrame, otError aError)
VerifyOrExit(mEnabled);
aFrame.GetDstAddr(macDest);
Get<MeshForwarder>().UpdateNeighborOnSentFrame(aFrame, aError, macDest);
if (!aFrame.IsEmpty())
{
aFrame.GetDstAddr(macDest);
Get<MeshForwarder>().UpdateNeighborOnSentFrame(aFrame, aError, macDest);
}
if (Get<Mle::MleRouter>().GetParentCandidate()->GetState() == Neighbor::kStateInvalid)
{
+26 -14
View File
@@ -1114,6 +1114,13 @@ exit:
if (error != OT_ERROR_NONE)
{
// If the sendFrame could not be prepared and the tx is being
// aborted, we set the frame length to zero to mark it as empty.
// The empty frame helps differentiate between an aborted tx due
// to OpenThread itself not being able to prepare the frame, versus
// the radio platform aborting the tx operation.
sendFrame.SetLength(0);
HandleTransmitDone(sendFrame, NULL, OT_ERROR_ABORT);
}
}
@@ -1149,6 +1156,8 @@ void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame,
Address dstAddr;
Neighbor *neighbor;
VerifyOrExit(!aFrame.IsEmpty());
aFrame.GetDstAddr(dstAddr);
neighbor = Get<Mle::MleRouter>().GetNeighbor(dstAddr);
@@ -1251,23 +1260,26 @@ exit:
void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError)
{
Address dstAddr;
// Determine whether to re-transmit a broadcast frame.
aFrame.GetDstAddr(dstAddr);
if (dstAddr.IsBroadcast())
if (!aFrame.IsEmpty())
{
mBroadcastTransmitCount++;
Address dstAddr;
if (mBroadcastTransmitCount < kTxNumBcast)
// Determine whether to re-transmit a broadcast frame.
aFrame.GetDstAddr(dstAddr);
if (dstAddr.IsBroadcast())
{
mSubMac.Send();
ExitNow();
}
mBroadcastTransmitCount++;
mBroadcastTransmitCount = 0;
if (mBroadcastTransmitCount < kTxNumBcast)
{
mSubMac.Send();
ExitNow();
}
mBroadcastTransmitCount = 0;
}
}
// Determine next action based on current operation.
@@ -1286,7 +1298,7 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, otError aError
break;
case kOperationTransmitPoll:
assert(aFrame.GetAckRequest());
assert(aFrame.IsEmpty() || aFrame.GetAckRequest());
if ((aError == OT_ERROR_NONE) && (aAckFrame != NULL))
{
+9
View File
@@ -851,6 +851,15 @@ public:
*/
typedef String<kInfoStringSize> InfoString;
/**
* This method indicates whether the frame is empty (no payload).
*
* @retval TRUE The frame is empty (no PSDU payload).
* @retval FALSE The frame is not empty.
*
*/
bool IsEmpty(void) const { return (mLength == 0); }
/**
* This method initializes the MAC header.
*
+5 -2
View File
@@ -515,8 +515,11 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
}
#endif
aFrame.GetDstAddr(macDest);
Get<MeshForwarder>().LogMessage(MeshForwarder::kMessageTransmit, *message, &macDest, txError);
if (!aFrame.IsEmpty())
{
aFrame.GetDstAddr(macDest);
Get<MeshForwarder>().LogMessage(MeshForwarder::kMessageTransmit, *message, &macDest, txError);
}
if (message->GetType() == Message::kTypeIp6)
{
+5 -2
View File
@@ -897,8 +897,11 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, otError aError)
VerifyOrExit(mEnabled);
aFrame.GetDstAddr(macDest);
neighbor = UpdateNeighborOnSentFrame(aFrame, aError, macDest);
if (!aFrame.IsEmpty())
{
aFrame.GetDstAddr(macDest);
neighbor = UpdateNeighborOnSentFrame(aFrame, aError, macDest);
}
VerifyOrExit(mSendMessage != NULL);
assert(mSendMessage->GetDirectTransmission());