| /* |
| * 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" |
| |
| #include "common/code_utils.hpp" |
| #include "common/locator.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 |
| { |
| friend class Mac::Mac; |
| |
| public: |
| enum |
| { |
| kMaxPollTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS, |
| }; |
| |
| /** |
| * This enumeration defines frame change request types used as input to `RequestFrameChange()`. |
| * |
| */ |
| enum FrameChange |
| { |
| 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; |
| |
| 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 SetIndirectTxAttemptsToMax(void) { mIndirectTxAttempts = kMaxPollTriggeredTxAttempts; } |
| 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; } |
| |
| 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. |
| |
| OT_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 data poll handler 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. |
| * @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, 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, |
| * OT_ERROR_ABORT 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, |
| otError 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); |
| otError HandleFrameRequest(Mac::TxFrame &aFrame); |
| void HandleSentFrame(const Mac::TxFrame &aFrame, otError aError); |
| |
| void HandleSentFrame(const Mac::TxFrame &aFrame, otError 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 (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; |
| }; |
| |
| /** |
| * @} |
| * |
| */ |
| |
| } // namespace ot |
| |
| #endif // DATA_POLL_HANDLER_HPP_ |