1 /*
2  *  Copyright (c) 2019, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for handling of data polls and indirect frame transmission.
32  */
33 
34 #ifndef DATA_POLL_HANDLER_HPP_
35 #define DATA_POLL_HANDLER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_FTD
40 
41 #include "common/code_utils.hpp"
42 #include "common/locator.hpp"
43 #include "common/non_copyable.hpp"
44 #include "common/timer.hpp"
45 #include "mac/mac.hpp"
46 #include "mac/mac_frame.hpp"
47 #include "thread/indirect_sender_frame_context.hpp"
48 
49 namespace ot {
50 
51 /**
52  * @addtogroup core-data-poll-handler
53  *
54  * @brief
55  *   This module includes definitions for data poll handler.
56  *
57  * @{
58  */
59 
60 class Child;
61 
62 /**
63  * Implements the data poll (mac data request command) handler.
64  *
65  */
66 class DataPollHandler : public InstanceLocator, private NonCopyable
67 {
68     friend class Mac::Mac;
69 
70 public:
71     static constexpr uint8_t kMaxPollTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS;
72 
73     /**
74      * Defines frame change request types used as input to `RequestFrameChange()`.
75      *
76      */
77     enum FrameChange : uint8_t
78     {
79         kPurgeFrame,   ///< Indicates that previous frame should be purged. Any ongoing indirect tx should be aborted.
80         kReplaceFrame, ///< Indicates that previous frame needs to be replaced with a new higher priority one.
81     };
82 
83     /**
84      * Defines all the child info required for handling of data polls and indirect frame transmissions.
85      *
86      * `Child` class publicly inherits from this class.
87      *
88      */
89     class ChildInfo
90     {
91         friend class DataPollHandler;
92 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
93         friend class CslTxScheduler;
94 #endif
95 
96     private:
IsDataPollPending(void) const97         bool IsDataPollPending(void) const { return mDataPollPending; }
SetDataPollPending(bool aPending)98         void SetDataPollPending(bool aPending) { mDataPollPending = aPending; }
99 
GetIndirectFrameCounter(void) const100         uint32_t GetIndirectFrameCounter(void) const { return mIndirectFrameCounter; }
SetIndirectFrameCounter(uint32_t aFrameCounter)101         void     SetIndirectFrameCounter(uint32_t aFrameCounter) { mIndirectFrameCounter = aFrameCounter; }
102 
GetIndirectKeyId(void) const103         uint8_t GetIndirectKeyId(void) const { return mIndirectKeyId; }
SetIndirectKeyId(uint8_t aKeyId)104         void    SetIndirectKeyId(uint8_t aKeyId) { mIndirectKeyId = aKeyId; }
105 
GetIndirectTxAttempts(void) const106         uint8_t GetIndirectTxAttempts(void) const { return mIndirectTxAttempts; }
ResetIndirectTxAttempts(void)107         void    ResetIndirectTxAttempts(void) { mIndirectTxAttempts = 0; }
IncrementIndirectTxAttempts(void)108         void    IncrementIndirectTxAttempts(void) { mIndirectTxAttempts++; }
109 
GetIndirectDataSequenceNumber(void) const110         uint8_t GetIndirectDataSequenceNumber(void) const { return mIndirectDsn; }
SetIndirectDataSequenceNumber(uint8_t aDsn)111         void    SetIndirectDataSequenceNumber(uint8_t aDsn) { mIndirectDsn = aDsn; }
112 
IsFramePurgePending(void) const113         bool IsFramePurgePending(void) const { return mFramePurgePending; }
SetFramePurgePending(bool aPurgePending)114         void SetFramePurgePending(bool aPurgePending) { mFramePurgePending = aPurgePending; }
115 
IsFrameReplacePending(void) const116         bool IsFrameReplacePending(void) const { return mFrameReplacePending; }
SetFrameReplacePending(bool aReplacePending)117         void SetFrameReplacePending(bool aReplacePending) { mFrameReplacePending = aReplacePending; }
118 
119 #if OPENTHREAD_CONFIG_MULTI_RADIO
GetLastPollRadioType(void) const120         Mac::RadioType GetLastPollRadioType(void) const { return mLastPollRadioType; }
SetLastPollRadioType(Mac::RadioType aRadioType)121         void           SetLastPollRadioType(Mac::RadioType aRadioType) { mLastPollRadioType = aRadioType; }
122 #endif
123 
124         uint32_t mIndirectFrameCounter;    // Frame counter for current indirect frame (used for retx).
125         uint8_t  mIndirectKeyId;           // Key Id for current indirect frame (used for retx).
126         uint8_t  mIndirectDsn;             // MAC level Data Sequence Number (DSN) for retx attempts.
127         uint8_t  mIndirectTxAttempts : 5;  // Number of data poll triggered tx attempts.
128         bool     mDataPollPending : 1;     // Indicates whether or not a Data Poll was received.
129         bool     mFramePurgePending : 1;   // Indicates a pending purge request for the current indirect frame.
130         bool     mFrameReplacePending : 1; // Indicates a pending replace request for the current indirect frame.
131 #if OPENTHREAD_CONFIG_MULTI_RADIO
132         Mac::RadioType mLastPollRadioType; // The radio link last data poll frame was received on.
133 #endif
134 
135         static_assert(kMaxPollTriggeredTxAttempts < (1 << 5), "mIndirectTxAttempts cannot fit max!");
136     };
137 
138     /**
139      * Defines the callbacks used by the `DataPollHandler`.
140      *
141      */
142     class Callbacks : public InstanceLocator
143     {
144         friend class DataPollHandler;
145 
146     private:
147         /**
148          * Defines the frame context associated with a prepared frame.
149          *
150          * Data poll handler treats `FrameContext` as an opaque data type. Data poll handler provides the buffer/object
151          * for the context when a new frame is prepared (from the callback `PrepareFrameForChild()`). It ensures
152          * to save the context along with the prepared frame and provide the same context back in the callback
153          * `HandleSentFrameToChild()` when the indirect transmission of the frame is finished.
154          *
155          */
156         typedef IndirectSenderBase::FrameContext FrameContext;
157 
158         /**
159          * Initializes the callbacks object.
160          *
161          * @param[in]  aInstance   A reference to the OpenThread instance.
162          *
163          */
164         explicit Callbacks(Instance &aInstance);
165 
166         /**
167          * This callback method requests a frame to be prepared for indirect transmission to a given sleepy child.
168          *
169          * @param[out] aFrame    A reference to a MAC frame where the new frame would be placed.
170          * @param[out] aContext  A reference to a `FrameContext` where the context for the new frame would be placed.
171          * @param[in]  aChild    The child for which to prepare the frame.
172          *
173          * @retval kErrorNone   Frame was prepared successfully.
174          * @retval kErrorAbort  Indirect transmission to child should be aborted (no frame for the child).
175          *
176          */
177         Error PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
178 
179         /**
180          * This callback method notifies the end of indirect frame transmission to a child.
181          *
182          * @param[in]  aFrame     The transmitted frame.
183          * @param[in]  aContext   The context associated with the frame when it was prepared.
184          * @param[in]  aError     kErrorNone when the frame was transmitted successfully,
185          *                        kErrorNoAck when the frame was transmitted but no ACK was received,
186          *                        kErrorChannelAccessFailure tx failed due to activity on the channel,
187          *                        kErrorAbort when transmission was aborted for other reasons.
188          * @param[in]  aChild     The child to which the frame was transmitted.
189          *
190          */
191         void HandleSentFrameToChild(const Mac::TxFrame &aFrame,
192                                     const FrameContext &aContext,
193                                     Error               aError,
194                                     Child              &aChild);
195 
196         /**
197          * This callback method notifies that a requested frame change from `RequestFrameChange()` is processed.
198          *
199          * This callback indicates to the next layer that the indirect frame/message for the child can be safely
200          * updated.
201          *
202          * @param[in]  aChild     The child to update.
203          *
204          */
205         void HandleFrameChangeDone(Child &aChild);
206     };
207 
208     /**
209      * Initializes the data poll handler object.
210      *
211      * @param[in]  aInstance   A reference to the OpenThread instance.
212      *
213      */
214     explicit DataPollHandler(Instance &aInstance);
215 
216     /**
217      * Clears any state/info saved per child for indirect frame transmission.
218      *
219      */
220     void Clear(void);
221 
222     /**
223      * Informs data poll handler that there is a new frame for a given child.
224      *
225      * After this call, the data poll handler can use the `Callbacks::PrepareFrameForChild()` method to request the
226      * frame to be prepared. A subsequent call to `Callbacks::PrepareFrameForChild()` should ensure to prepare the same
227      * frame (this is used for retransmissions of frame by data poll handler). If/When the frame transmission is
228      * finished, the data poll handler will invoke the `Callbacks::HandleSentFrameToChild()` to indicate the status of
229      * the frame transmission.
230      *
231      * @param[in]  aChild     The child which has a new frame.
232      *
233      */
234     void HandleNewFrame(Child &aChild);
235 
236     /**
237      * Requests a frame change for a given child.
238      *
239      * Two types of frame change requests are supported:
240      *
241      * 1) "Purge Frame" which indicates that the previous frame should be purged and any ongoing indirect tx aborted.
242      * 2) "Replace Frame" which indicates that the previous frame needs to be replaced with a new higher priority one.
243      *
244      * If there is no ongoing indirect frame transmission to the child, the request will be handled immediately and the
245      * callback `HandleFrameChangeDone()` is called directly from this method itself. This callback notifies the next
246      * layer that the indirect frame/message for the child can be safely updated.
247      *
248      * If there is an ongoing indirect frame transmission to this child, the request can not be handled immediately.
249      * The following options can happen based on the request type:
250      *
251      * 1) In case of "purge" request, the ongoing indirect transmission is aborted and upon completion of the abort the
252      *    callback `HandleFrameChangeDone()` is invoked.
253      *
254      * 2) In case of "replace" request, the ongoing indirect transmission is allowed to finish (current tx attempt).
255      *    2.a) If the tx attempt is successful, the `Callbacks::HandleSentFrameToChild()` in invoked which indicates
256      *         the "replace" could not happen (in this case the `HandleFrameChangeDone()` is no longer called).
257      *    2.b) If the ongoing tx attempt is unsuccessful, then callback `HandleFrameChangeDone()` is invoked to allow
258      *         the next layer to update the frame/message for the child.
259      *
260      * If there is a pending request, a subsequent call to this method is ignored except for the case where pending
261      * request is for "replace frame" and new one is for "purge frame" where the "purge" overrides the "replace"
262      * request.
263      *
264      * @param[in]  aChange    The frame change type.
265      * @param[in]  aChild     The child to process its frame change.
266      *
267      */
268     void RequestFrameChange(FrameChange aChange, Child &aChild);
269 
270 private:
271     // Callbacks from MAC
272     void          HandleDataPoll(Mac::RxFrame &aFrame);
273     Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
274     void          HandleSentFrame(const Mac::TxFrame &aFrame, Error aError);
275 
276     void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild);
277     void ProcessPendingPolls(void);
278     void ResetTxAttempts(Child &aChild);
279 
280     // In the current implementation of `DataPollHandler`, we can have a
281     // single indirect tx operation active at MAC layer at each point of
282     // time. `mIndirectTxChild` indicates the child being handled (`nullptr`
283     // indicates no active indirect tx). `mFrameContext` tracks the
284     // context for the prepared frame for the current indirect tx.
285 
286     Child                  *mIndirectTxChild;
287     Callbacks::FrameContext mFrameContext;
288     Callbacks               mCallbacks;
289 };
290 
291 /**
292  * @}
293  *
294  */
295 
296 } // namespace ot
297 
298 #endif // OPENTHREAD_FTD
299 
300 #endif // DATA_POLL_HANDLER_HPP_
301