From 6e62c9a12b07c05d8c7b4e0997568e8c3aa90260 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 17 Mar 2021 10:13:01 -0700 Subject: [PATCH] [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). --- src/core/thread/indirect_sender.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/core/thread/indirect_sender.cpp b/src/core/thread/indirect_sender.cpp index b5c1d6550..bea98179a 100644 --- a/src/core/thread/indirect_sender.cpp +++ b/src/core/thread/indirect_sender.cpp @@ -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().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().UpdateOnSend(aChild); break; case kErrorNoAck: