1 /*
2  *  Copyright (c) 2017, 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 data poll (mac data request command) sender.
32  */
33 
34 #ifndef DATA_POLL_MANAGER_HPP_
35 #define DATA_POLL_MANAGER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include "common/code_utils.hpp"
40 #include "common/locator.hpp"
41 #include "common/non_copyable.hpp"
42 #include "common/timer.hpp"
43 #include "mac/mac.hpp"
44 #include "mac/mac_frame.hpp"
45 #include "thread/topology.hpp"
46 
47 namespace ot {
48 
49 /**
50  * @addtogroup core-data-poll-sender
51  *
52  * @brief
53  *   This module includes definitions for data poll sender.
54  *
55  * @{
56  */
57 
58 /**
59  * This class implements the data poll (mac data request command) sender.
60  *
61  */
62 
63 class DataPollSender : public InstanceLocator, private NonCopyable
64 {
65 public:
66     static constexpr uint8_t kDefaultFastPolls  = 8;  ///< Default number of fast poll tx (@sa StartFastPolls).
67     static constexpr uint8_t kMaxFastPolls      = 15; ///< Maximum number of fast poll tx allowed.
68     static constexpr uint8_t kMaxFastPollsUsers = 63; ///< Maximum number of the users of fast poll tx allowed.
69 
70     /**
71      * This constructor initializes the data poll sender object.
72      *
73      * @param[in]  aInstance   A reference to the OpenThread instance.
74      *
75      */
76     explicit DataPollSender(Instance &aInstance);
77 
78     /**
79      * This method instructs the data poll sender to start sending periodic data polls.
80      *
81      */
82     void StartPolling(void);
83 
84     /**
85      * This method instructs the data poll sender to stop sending periodic data polls.
86      *
87      */
88     void StopPolling(void);
89 
90     /**
91      * This method enqueues a data poll (an IEEE 802.15.4 Data Request) message.
92      *
93      * @retval kErrorNone          Successfully enqueued a data poll message
94      * @retval kErrorAlready       A data poll message is already enqueued.
95      * @retval kErrorInvalidState  Device is not in rx-off-when-idle mode.
96      * @retval kErrorNoBufs        Insufficient message buffers available.
97      *
98      */
99     Error SendDataPoll(void);
100 
101     /**
102      * This method sets/clears a user-specified/external data poll period.
103      *
104      * Value of zero for `aPeriod` clears the user-specified poll period.
105      *
106      * If the user provides a non-zero poll period, the user value specifies the maximum period between data
107      * request transmissions. Note that OpenThread may send data request transmissions more frequently when expecting
108      * a control-message from a parent or in case of data poll transmission failures or timeouts, or when the specified
109      * value is larger than the child timeout.
110      *
111      * A non-zero `aPeriod` should be larger than or equal to `OPENTHREAD_CONFIG_MAC_MINIMUM_POLL_PERIOD` (10ms) or
112      * this method returns `kErrorInvalidArgs`. If a non-zero `aPeriod` is larger than maximum value of
113      * `0x3FFFFFF ((1 << 26) - 1)`, it would be clipped to this value.
114      *
115      * @param[in]  aPeriod  The data poll period in milliseconds.
116      *
117      * @retval kErrorNone           Successfully set/cleared user-specified poll period.
118      * @retval kErrorInvalidArgs    If aPeriod is invalid.
119      *
120      */
121     Error SetExternalPollPeriod(uint32_t aPeriod);
122 
123     /**
124      * This method gets the current user-specified/external data poll period.
125      *
126      * @returns  The data poll period in milliseconds.
127      *
128      */
GetExternalPollPeriod(void) const129     uint32_t GetExternalPollPeriod(void) const { return mExternalPollPeriod; }
130 
131     /**
132      * This method informs the data poll sender of success/error status of a previously requested poll frame
133      * transmission.
134      *
135      * In case of transmit failure, the data poll sender may choose to send the next data poll more quickly (up to
136      * some fixed number of attempts).
137      *
138      * @param[in] aFrame     The data poll frame.
139      * @param[in] aError     Error status of a data poll message transmission.
140      *
141      */
142     void HandlePollSent(Mac::TxFrame &aFrame, Error aError);
143 
144     /**
145      * This method informs the data poll sender that a data poll timeout happened, i.e., when the ack in response to
146      * a data request command indicated that a frame was pending, but no frame was received after timeout interval.
147      *
148      * Data poll sender may choose to transmit another data poll immediately (up to some fixed number of attempts).
149      *
150      */
151     void HandlePollTimeout(void);
152 
153     /**
154      * This method informs the data poll sender to process a received MAC frame.
155      *
156      * @param[in] aFrame     A reference to the received frame to process.
157      *
158      */
159     void ProcessRxFrame(const Mac::RxFrame &aFrame);
160 
161 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
162     /**
163      * This method informs the data poll sender to process a transmitted MAC frame.
164      *
165      * @param[in]  aFrame      A reference to the frame that was transmitted.
166      * @param[in]  aAckFrame   A pointer to the ACK frame, nullptr if no ACK was received.
167      * @param[in]  aError      kErrorNone when the frame was transmitted successfully,
168      *                         kErrorNoAck when the frame was transmitted but no ACK was received,
169      *                         kErrorChannelAccessFailure when the tx failed due to activity on the channel,
170      *                         kErrorAbort when transmission was aborted for other reasons.
171      *
172      */
173     void ProcessTxDone(const Mac::TxFrame &aFrame, const Mac::RxFrame *aAckFrame, Error aError);
174 #endif
175 
176     /**
177      * This method asks the data poll sender to recalculate the poll period.
178      *
179      * This is mainly used to inform the poll sender that a parameter impacting the poll period (e.g., the child's
180      * timeout value which is used to determine the default data poll period) is modified.
181      *
182      */
183     void RecalculatePollPeriod(void);
184 
185     /**
186      * This method sets/clears the attach mode on data poll sender.
187      *
188      * When attach mode is enabled, the data poll sender will send data polls at a faster rate determined by
189      * poll period configuration option `OPENTHREAD_CONFIG_MAC_ATTACH_DATA_POLL_PERIOD`.
190      *
191      * @param[in]  aMode  The mode value.
192      *
193      */
194     void SetAttachMode(bool aMode);
195 
196     /**
197      * This method asks data poll sender to send the next given number of polls at a faster rate (poll period defined
198      * by `kFastPollPeriod`). This is used by OpenThread stack when it expects a response from the parent/sender.
199      *
200      * If @p aNumFastPolls is zero the default value specified by `kDefaultFastPolls` is used instead. The number of
201      * fast polls is clipped by maximum value specified by `kMaxFastPolls`.
202      *
203      * Note that per `SendFastPolls()` would increase the internal reference count until up to the allowed maximum
204      * value. If there are retransmission mechanism in the caller component, it should be responsible to call
205      * `StopFastPolls()` the same times as `SendFastPolls()` it triggered to decrease the reference count properly,
206      * guaranteeing to exit fast poll mode gracefully. Otherwise, fast poll would continue until all data polls are sent
207      * out.
208      *
209      * @param[in] aNumFastPolls  If non-zero, number of fast polls to send, if zero, default value is used instead.
210      *
211      */
212     void SendFastPolls(uint8_t aNumFastPolls = 0);
213 
214     /**
215      * This method asks data poll sender to stop fast polls when the expecting response is received.
216      *
217      */
218     void StopFastPolls(void);
219 
220     /**
221      * This method gets the maximum data polling period in use.
222      *
223      * The maximum data poll period is determined based as the minimum of the user-specified poll interval and the
224      * default poll interval.
225      *
226      * @returns The maximum data polling period in use.
227      *
228      */
229     uint32_t GetKeepAlivePollPeriod(void) const;
230 
231     /**
232      * This method resets the timer for sending keep-alive messages.
233      *
234      */
235     void ResetKeepAliveTimer(void);
236 
237     /**
238      * This method returns the default maximum poll period.
239      *
240      * The default poll period is determined based on the child timeout interval, ensuing the child would send data poll
241      * within the child's timeout.
242      *
243      * @returns The maximum default data polling interval (in msec).
244      *
245      */
246     uint32_t GetDefaultPollPeriod(void) const;
247 
248     /**
249      * This method prepares and returns a data request command frame.
250      *
251      * @param[in] aTxFrames  The set of TxFrames for all radio links.
252      *
253      * @returns The data poll frame.
254      *
255      */
256     Mac::TxFrame *PrepareDataRequest(Mac::TxFrames &aTxFrames);
257 
258 private:
259     static constexpr uint8_t kQuickPollsAfterTimeout = 5; // Quick data poll tx in case of back-to-back poll timeouts.
260     static constexpr uint8_t kMaxPollRetxAttempts    = OPENTHREAD_CONFIG_FAILED_CHILD_TRANSMISSIONS;
261     static constexpr uint8_t kMaxCslPollRetxAttempts = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT;
262 
263     enum PollPeriodSelector : uint8_t
264     {
265         kUsePreviousPollPeriod,
266         kRecalculatePollPeriod,
267     };
268 
269     // Poll period under different conditions (in milliseconds).
270     static constexpr uint32_t kAttachDataPollPeriod = OPENTHREAD_CONFIG_MAC_ATTACH_DATA_POLL_PERIOD;
271     static constexpr uint32_t kRetxPollPeriod       = OPENTHREAD_CONFIG_MAC_RETX_POLL_PERIOD;
272     static constexpr uint32_t kFastPollPeriod       = 188;
273     static constexpr uint32_t kMinPollPeriod        = OPENTHREAD_CONFIG_MAC_MINIMUM_POLL_PERIOD;
274     static constexpr uint32_t kMaxExternalPeriod    = ((1 << 26) - 1); //< ~18.6 hours.
275 
276     void            ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector);
277     uint32_t        CalculatePollPeriod(void) const;
278     const Neighbor &GetParent(void) const;
279     static void     HandlePollTimer(Timer &aTimer);
280 #if OPENTHREAD_CONFIG_MULTI_RADIO
281     Error GetPollDestinationAddress(Mac::Address &aDest, Mac::RadioType &aRadioType) const;
282 #else
283     Error GetPollDestinationAddress(Mac::Address &aDest) const;
284 #endif
285 
286     TimeMilli mTimerStartTime;
287     uint32_t  mPollPeriod;
288     uint32_t  mExternalPollPeriod : 26; //< In milliseconds.
289     uint8_t   mFastPollsUsers : 6;      //< Number of callers which request fast polls.
290 
291     TimerMilli mTimer;
292 
293     bool    mEnabled : 1;              //< Indicates whether data polling is enabled/started.
294     bool    mAttachMode : 1;           //< Indicates whether in attach mode (to use attach poll period).
295     bool    mRetxMode : 1;             //< Indicates whether last poll tx failed at mac/radio layer (poll retx mode).
296     uint8_t mPollTimeoutCounter : 4;   //< Poll timeouts counter (0 to `kQuickPollsAfterTimout`).
297     uint8_t mPollTxFailureCounter : 4; //< Poll tx failure counter (0 to `kMaxPollRetxAttempts`).
298     uint8_t mRemainingFastPolls : 4;   //< Number of remaining fast polls when in transient fast polling mode.
299 };
300 
301 /**
302  * @}
303  *
304  */
305 
306 } // namespace ot
307 
308 #endif // DATA_POLL_MANAGER_HPP_
309