blob: 37532c49cf01aa424f6fc6024ac6cf8701347099 [file] [log] [blame]
/*
* 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 for handling of data polls and indirect frame transmission.
*/
#ifndef DATA_POLL_HANDLER_HPP_
#define DATA_POLL_HANDLER_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_FTD
#include "common/code_utils.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/timer.hpp"
#include "mac/mac.hpp"
#include "mac/mac_frame.hpp"
#include "thread/indirect_sender_frame_context.hpp"
namespace ot {
/**
* @addtogroup core-data-poll-handler
*
* @brief
* This module includes definitions for data poll handler.
*
* @{
*/
class Child;
/**
* This class implements the data poll (mac data request command) handler.
*
*/
class DataPollHandler : public InstanceLocator, private NonCopyable
{
friend class Mac::Mac;
public:
static constexpr uint8_t kMaxPollTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS;
/**
* This enumeration defines frame change request types used as input to `RequestFrameChange()`.
*
*/
enum FrameChange : uint8_t
{
kPurgeFrame, ///< Indicates that previous frame should be purged. Any ongoing indirect tx should be aborted.
kReplaceFrame, ///< Indicates that previous frame needs to be replaced with a new higher priority one.
};
/**
* This class defines all the child info required for handling of data polls and indirect frame transmissions.
*
* `Child` class publicly inherits from this class.
*
*/
class ChildInfo
{
friend class DataPollHandler;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
friend class CslTxScheduler;
#endif
private:
bool IsDataPollPending(void) const { return mDataPollPending; }
void SetDataPollPending(bool aPending) { mDataPollPending = aPending; }
uint32_t GetIndirectFrameCounter(void) const { return mIndirectFrameCounter; }
void SetIndirectFrameCounter(uint32_t aFrameCounter) { mIndirectFrameCounter = aFrameCounter; }
uint8_t GetIndirectKeyId(void) const { return mIndirectKeyId; }
void SetIndirectKeyId(uint8_t aKeyId) { mIndirectKeyId = aKeyId; }
uint8_t GetIndirectTxAttempts(void) const { return mIndirectTxAttempts; }
void ResetIndirectTxAttempts(void) { mIndirectTxAttempts = 0; }
void IncrementIndirectTxAttempts(void) { mIndirectTxAttempts++; }
uint8_t GetIndirectDataSequenceNumber(void) const { return mIndirectDsn; }
void SetIndirectDataSequenceNumber(uint8_t aDsn) { mIndirectDsn = aDsn; }
bool IsFramePurgePending(void) const { return mFramePurgePending; }
void SetFramePurgePending(bool aPurgePending) { mFramePurgePending = aPurgePending; }
bool IsFrameReplacePending(void) const { return mFrameReplacePending; }
void SetFrameReplacePending(bool aReplacePending) { mFrameReplacePending = aReplacePending; }
#if OPENTHREAD_CONFIG_MULTI_RADIO
Mac::RadioType GetLastPollRadioType(void) const { return mLastPollRadioType; }
void SetLastPollRadioType(Mac::RadioType aRadioType) { mLastPollRadioType = aRadioType; }
#endif
uint32_t mIndirectFrameCounter; // Frame counter for current indirect frame (used for retx).
uint8_t mIndirectKeyId; // Key Id for current indirect frame (used for retx).
uint8_t mIndirectDsn; // MAC level Data Sequence Number (DSN) for retx attempts.
uint8_t mIndirectTxAttempts : 5; // Number of data poll triggered tx attempts.
bool mDataPollPending : 1; // Indicates whether or not a Data Poll was received.
bool mFramePurgePending : 1; // Indicates a pending purge request for the current indirect frame.
bool mFrameReplacePending : 1; // Indicates a pending replace request for the current indirect frame.
#if OPENTHREAD_CONFIG_MULTI_RADIO
Mac::RadioType mLastPollRadioType; // The radio link last data poll frame was received on.
#endif
static_assert(kMaxPollTriggeredTxAttempts < (1 << 5), "mIndirectTxAttempts cannot fit max!");
};
/**
* This class defines the callbacks used by the `DataPollHandler`.
*
*/
class Callbacks : public InstanceLocator
{
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 callbacks object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit Callbacks(Instance &aInstance);
/**
* This callback method requests a frame to be prepared for indirect transmission to a given sleepy child.
*
* @param[out] aFrame A reference to a MAC frame where the new frame would be placed.
* @param[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 kErrorNone Frame was prepared successfully.
* @retval kErrorAbort Indirect transmission to child should be aborted (no frame for the child).
*
*/
Error 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 kErrorNone when the frame was transmitted successfully,
* kErrorNoAck when the frame was transmitted but no ACK was received,
* kErrorChannelAccessFailure tx failed due to activity on the channel,
* kErrorAbort when transmission was aborted for other reasons.
* @param[in] aChild The child to which the frame was transmitted.
*
*/
void HandleSentFrameToChild(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
Child & aChild);
/**
* This callback method notifies that a requested frame change from `RequestFrameChange()` is processed.
*
* This callback indicates to the next layer that the indirect frame/message for the child can be safely
* updated.
*
* @param[in] aChild The child to update.
*
*/
void HandleFrameChangeDone(Child &aChild);
};
/**
* This constructor initializes the data poll handler object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit DataPollHandler(Instance &aInstance);
/**
* This method clears any state/info saved per child for indirect frame transmission.
*
*/
void Clear(void);
/**
* This method informs data poll handler that there is a new frame for a given child.
*
* After this call, the data poll handler can use the `Callbacks::PrepareFrameForChild()` method to request the
* frame to be prepared. A subsequent call to `Callbacks::PrepareFrameForChild()` should ensure to prepare the same
* frame (this is used for retransmissions of frame by data poll handler). If/When the frame transmission is
* finished, the data poll handler will invoke the `Callbacks::HandleSentFrameToChild()` to indicate the status of
* the frame transmission.
*
* @param[in] aChild The child which has a new frame.
*
*/
void HandleNewFrame(Child &aChild);
/**
* This method requests a frame change for a given child.
*
* Two types of frame change requests are supported:
*
* 1) "Purge Frame" which indicates that the previous frame should be purged and any ongoing indirect tx aborted.
* 2) "Replace Frame" which indicates that the previous frame needs to be replaced with a new higher priority one.
*
* If there is no ongoing indirect frame transmission to the child, the request will be handled immediately and the
* callback `HandleFrameChangeDone()` is called directly from this method itself. This callback notifies the next
* layer that the indirect frame/message for the child can be safely updated.
*
* If there is an ongoing indirect frame transmission to this child, the request can not be handled immediately.
* The following options can happen based on the request type:
*
* 1) In case of "purge" request, the ongoing indirect transmission is aborted and upon completion of the abort the
* callback `HandleFrameChangeDone()` is invoked.
*
* 2) In case of "replace" request, the ongoing indirect transmission is allowed to finish (current tx attempt).
* 2.a) If the tx attempt is successful, the `Callbacks::HandleSentFrameToChild()` in invoked which indicates
* the "replace" could not happen (in this case the `HandleFrameChangeDone()` is no longer called).
* 2.b) If the ongoing tx attempt is unsuccessful, then callback `HandleFrameChangeDone()` is invoked to allow
* the next layer to update the frame/message for the child.
*
* If there is a pending request, a subsequent call to this method is ignored except for the case where pending
* request is for "replace frame" and new one is for "purge frame" where the "purge" overrides the "replace"
* request.
*
* @param[in] aChange The frame change type.
* @param[in] aChild The child to process its frame change.
*
*/
void RequestFrameChange(FrameChange aChange, Child &aChild);
private:
// Callbacks from MAC
void HandleDataPoll(Mac::RxFrame &aFrame);
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild);
void ProcessPendingPolls(void);
// 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 (`nullptr`
// 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;
};
/**
* @}
*
*/
} // namespace ot
#endif // OPENTHREAD_FTD
#endif // DATA_POLL_HANDLER_HPP_