[indirect-sender] add FrameContext class (#4005)

This commit adds a `FrameContext` type (containing all info that need
to be saved along with a prepared frame for indirect transmission) and
its support in `IndirectSender` and `DataPollHandler`. While the
`FrameContext` is defined by the `IndirectSender`, the lower-layer
`DataPollHandler` is expected to provide the buffer/object for it to
be stored (when the frame is prepared). This model allows different
implementations of `DataPollHandler` to adopt different strategies on
how to store the context.
This commit is contained in:
Abtin Keshavarzian
2019-08-02 14:19:32 -07:00
committed by Jonathan Hui
parent 6d07a3eb31
commit 939ac82bf2
6 changed files with 150 additions and 26 deletions
+2 -1
View File
@@ -132,7 +132,7 @@ SOURCES_COMMON = \
api/sntp_api.cpp \
api/tasklet_api.cpp \
api/thread_api.cpp \
api/thread_ftd_api.cpp \
api/thread_ftd_api.cpp \
api/udp_api.cpp \
coap/coap.cpp \
coap/coap_message.cpp \
@@ -398,6 +398,7 @@ HEADERS_COMMON = \
thread/device_mode.hpp \
thread/energy_scan_server.hpp \
thread/indirect_sender.hpp \
thread/indirect_sender_frame_context.hpp \
thread/key_manager.hpp \
thread/link_quality.hpp \
thread/lowpan.hpp \
+9 -5
View File
@@ -47,16 +47,19 @@ DataPollHandler::Callbacks::Callbacks(Instance &aInstance)
{
}
inline otError DataPollHandler::Callbacks::PrepareFrameForChild(Mac::TxFrame &aFrame, Child &aChild)
inline otError DataPollHandler::Callbacks::PrepareFrameForChild(Mac::TxFrame &aFrame,
FrameContext &aContext,
Child & aChild)
{
return Get<IndirectSender>().PrepareFrameForChild(aFrame, aChild);
return Get<IndirectSender>().PrepareFrameForChild(aFrame, aContext, aChild);
}
inline void DataPollHandler::Callbacks::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
otError aError,
Child & aChild)
{
Get<IndirectSender>().HandleSentFrameToChild(aFrame, aError, aChild);
Get<IndirectSender>().HandleSentFrameToChild(aFrame, aContext, aError, aChild);
}
inline void DataPollHandler::Callbacks::HandleFrameChangeDone(Child &aChild)
@@ -69,6 +72,7 @@ inline void DataPollHandler::Callbacks::HandleFrameChangeDone(Child &aChild)
DataPollHandler::DataPollHandler(Instance &aInstance)
: InstanceLocator(aInstance)
, mIndirectTxChild(NULL)
, mFrameContext()
, mCallbacks(aInstance)
{
}
@@ -172,7 +176,7 @@ otError DataPollHandler::HandleFrameRequest(Mac::TxFrame &aFrame)
VerifyOrExit(mIndirectTxChild != NULL, error = OT_ERROR_ABORT);
SuccessOrExit(error = mCallbacks.PrepareFrameForChild(aFrame, *mIndirectTxChild));
SuccessOrExit(error = mCallbacks.PrepareFrameForChild(aFrame, mFrameContext, *mIndirectTxChild));
if (mIndirectTxChild->GetIndirectTxAttempts() > 0)
{
@@ -279,7 +283,7 @@ void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, otError aError
break;
}
mCallbacks.HandleSentFrameToChild(aFrame, aError, aChild);
mCallbacks.HandleSentFrameToChild(aFrame, mFrameContext, aError, aChild);
exit:
return;
+30 -6
View File
@@ -41,6 +41,7 @@
#include "common/timer.hpp"
#include "mac/mac.hpp"
#include "mac/mac_frame.hpp"
#include "thread/indirect_sender_frame_context.hpp"
namespace ot {
@@ -133,6 +134,17 @@ public:
friend class DataPollHandler;
private:
/**
* This type defines the frame context associated with a prepared frame.
*
* Data poll handler treats `FrameContext` as an opaque data type. Data poll handler provides the buffer/object
* for the context when a new frame is prepared (from the callback `PrepareFrameForChild()`). It ensures
* to save the context along with the prepared frame and provide the same context back in the callback
* `HandleSentFrameToChild()` when the indirect transmission of the frame is finished.
*
*/
typedef IndirectSenderBase::FrameContext FrameContext;
/**
* This constructor initializes the data poll handler object.
*
@@ -144,19 +156,21 @@ public:
/**
* This callback method requests a frame to be prepared for indirect transmission to a given sleepy child.
*
* @param[in] aFrame A reference to a MAC frame where the new frame would be placed.
* @param[in] aChild The child for which to prepare the frame.
* @param[out] aFrame A reference to a MAC frame where the new frame would be placed.
* @prarm[out] aContext A reference to a `FrameContext` where the context for the new frame would be placed.
* @param[in] aChild The child for which to prepare the frame.
*
* @retval OT_ERROR_NONE Frame was prepared successfully
* @retval OT_ERROR_ABORT Indirect transmission to child should be aborted (no frame for the child).
*
*/
otError PrepareFrameForChild(Mac::TxFrame &aFrame, Child &aChild);
otError PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
/**
* This callback method notifies the end of indirect frame transmission to a child.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aContext The context associated with the frame when it was prepared.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted successfully,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx failed due to activity on the channel,
@@ -164,7 +178,10 @@ public:
* @param[in] aChild The child to which the frame was transmitted.
*
*/
void HandleSentFrameToChild(const Mac::TxFrame &aFrame, otError aError, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
otError aError,
Child & aChild);
/**
* This callback method notifies that a requested frame change from `RequestFrameChange()` is processed.
@@ -249,8 +266,15 @@ private:
void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError, Child &aChild);
void ProcessPendingPolls(void);
Child * mIndirectTxChild;
Callbacks mCallbacks;
// In the current implementation of `DataPollHandler`, we can have a
// single indirect tx operation active at MAC layer at each point of
// time. `mIndirectTxChild` indicates the child being handled (NULL
// indicates no active indirect tx). `mFrameContext` tracks the
// context for the prepared frame for the current indirect tx.
Child * mIndirectTxChild;
Callbacks::FrameContext mFrameContext;
Callbacks mCallbacks;
};
/**
+13 -10
View File
@@ -65,7 +65,6 @@ IndirectSender::IndirectSender(Instance &aInstance)
, mEnabled(false)
, mSourceMatchController(aInstance)
, mDataPollHandler(aInstance)
, mMessageNextOffset(0)
{
}
@@ -320,7 +319,7 @@ void IndirectSender::UpdateIndirectMessage(Child &aChild)
}
}
otError IndirectSender::PrepareFrameForChild(Mac::TxFrame &aFrame, Child &aChild)
otError IndirectSender::PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild)
{
otError error = OT_ERROR_NONE;
Message *message = aChild.GetIndirectMessage();
@@ -336,12 +335,12 @@ otError IndirectSender::PrepareFrameForChild(Mac::TxFrame &aFrame, Child &aChild
switch (message->GetType())
{
case Message::kTypeIp6:
mMessageNextOffset = PrepareDataFrame(aFrame, aChild, *message);
aContext.mMessageNextOffset = PrepareDataFrame(aFrame, aChild, *message);
break;
case Message::kTypeSupervision:
PrepareEmptyFrame(aFrame, aChild, kSupervisionMsgAckRequest);
mMessageNextOffset = message->GetLength();
aContext.mMessageNextOffset = message->GetLength();
break;
default:
@@ -432,9 +431,13 @@ void IndirectSender::PrepareEmptyFrame(Mac::TxFrame &aFrame, Child &aChild, bool
aFrame.SetFramePending(false);
}
void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame, otError aError, Child &aChild)
void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
otError aError,
Child & aChild)
{
Message *message = aChild.GetIndirectMessage();
Message *message = aChild.GetIndirectMessage();
uint16_t nextOffset = aContext.mMessageNextOffset;
VerifyOrExit(mEnabled);
@@ -451,13 +454,13 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame, otError
aChild.SetIndirectTxSuccess(false);
#if OPENTHREAD_CONFIG_DROP_MESSAGE_ON_FRAGMENT_TX_FAILURE
// We set the NextOffset to end of message, since there is no need to
// We set the nextOffset to end of message, since there is no need to
// send any remaining fragments in the message to the child, if all tx
// attempts of current frame already failed.
if (message != NULL)
{
mMessageNextOffset = message->GetLength();
nextOffset = message->GetLength();
}
#endif
break;
@@ -467,9 +470,9 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame, otError
break;
}
if ((message != NULL) && (mMessageNextOffset < message->GetLength()))
if ((message != NULL) && (nextOffset < message->GetLength()))
{
aChild.SetIndirectFragmentOffset(mMessageNextOffset);
aChild.SetIndirectFragmentOffset(nextOffset);
mDataPollHandler.HandleNewFrame(aChild);
ExitNow();
}
+7 -4
View File
@@ -41,6 +41,7 @@
#include "mac/data_poll_handler.hpp"
#include "mac/mac_frame.hpp"
#include "thread/device_mode.hpp"
#include "thread/indirect_sender_frame_context.hpp"
#include "thread/src_match_controller.hpp"
namespace ot {
@@ -60,7 +61,7 @@ class Child;
* This class implements indirect transmission.
*
*/
class IndirectSender : public InstanceLocator
class IndirectSender : public InstanceLocator, public IndirectSenderBase
{
friend class Instance;
friend class DataPollHandler::Callbacks;
@@ -207,8 +208,11 @@ private:
};
// Callbacks from DataPollHandler
otError PrepareFrameForChild(Mac::TxFrame &aFrame, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame &aFrame, otError aError, Child &aChild);
otError PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
otError aError,
Child & aChild);
void HandleFrameChangeDone(Child &aChild);
void UpdateIndirectMessage(Child &aChild);
@@ -221,7 +225,6 @@ private:
bool mEnabled;
SourceMatchController mSourceMatchController;
DataPollHandler mDataPollHandler;
uint16_t mMessageNextOffset;
};
/**
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2019, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions of frame context used for indirect transmission.
*/
#ifndef INDIRECT_SENDER_FRAME_CONTETX_HPP_
#define INDIRECT_SENDER_FRAME_CONTETX_HPP_
#include "openthread-core-config.h"
#include "utils/wrap_stdint.h"
namespace ot {
/**
* @addtogroup core-mesh-forwarding
*
* @brief
* This module includes definitions frame context used by indirect sender.
*
* @{
*/
/**
* This class defines the `FrameContext` type.
*
* This is the base class for `IndirectSender`.
*
*/
class IndirectSenderBase
{
public:
/**
* This type defines the frame context used by `IndirectSender`.
*
* This type specifies all the info that `IndirectSender` requires to be saved along with a prepared frame for
* indirect transmission. `IndirectSender` is designed to contain the common code for handling of indirect
* transmission to sleepy children and be able to interface to different lower-layer implementation of
* `DataPollHandler`. While the `FrameContext` is defined by the `IndirectSender` itself, the lower-layer
* (`DataPollHandler`) is expected to provide the buffer/object for context to be stored (it is provided from the
* lower-layer callback asking for a frame to be prepared). This model allows different implementations of
* `DataPollHandler` to adopt different strategies on how to save the context.
*
*/
struct FrameContext
{
friend class IndirectSender;
private:
uint16_t mMessageNextOffset; ///< The next offset into the message associated with the prepared frame.
};
};
/**
* @}
*
*/
} // namespace ot
#endif // INDIRECT_SENDER_FRAME_CONTETX_HPP_