[indirect-sender] skip over HandleSentFrameToChild() for an empty frame (#6293)

This commit updates `IndirectSender` to check exit quickly from the
`HandleSentFrameToChild()` callback if the sent frame is an empty
frame. `PrepareFrameForChild()` prepares an empty frame when there is
no indirect message in the send queue for the child. This can happen
in the (not common) situation where the radio platform does not
support the "source address match" feature and always include "frame
pending" flag in acks to data poll frames. The change in this commit
address a potential issue in this situation and ensures that the "send
done" is not incorrectly processed for any newly added indirect
message after preparing the empty frame (which would cause the message
to be assumed sent and removed without actual tx).
This commit is contained in:
Abtin Keshavarzian
2021-03-17 10:13:01 -07:00
committed by GitHub
parent 12d5f793e7
commit 6e62c9a12b
+20 -1
View File
@@ -338,6 +338,7 @@ Error IndirectSender::PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &a
if (message == nullptr)
{
PrepareEmptyFrame(aFrame, aChild, /* aAckRequest */ true);
aContext.mMessageNextOffset = 0;
ExitNow();
}
@@ -422,10 +423,28 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
VerifyOrExit(mEnabled);
if (aError == kErrorNone)
{
Get<Utils::ChildSupervisor>().UpdateOnSend(aChild);
}
// A zero `nextOffset` indicates that the sent frame is an empty
// frame generated by `PrepareFrameForChild()` when there was no
// indirect message in the send queue for the child. This can happen
// in the (not common) case where the radio platform does not
// support the "source address match" feature and always includes
// "frame pending" flag in acks to data poll frames. In such a case,
// `IndirectSender` prepares and sends an empty frame to the child
// after it sends a data poll. Here in `HandleSentFrameToChild()` we
// exit quickly if we detect the "send done" is for the empty frame
// to ensure we do not update any newly added indirect message after
// preparing the empty frame.
VerifyOrExit(nextOffset != 0);
switch (aError)
{
case kErrorNone:
Get<Utils::ChildSupervisor>().UpdateOnSend(aChild);
break;
case kErrorNoAck: