• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 implements data poll (mac data request command) sender class.
32  */
33 
34 #include "data_poll_sender.hpp"
35 
36 #include "instance/instance.hpp"
37 
38 namespace ot {
39 
40 RegisterLogModule("DataPollSender");
41 
DataPollSender(Instance & aInstance)42 DataPollSender::DataPollSender(Instance &aInstance)
43     : InstanceLocator(aInstance)
44     , mTimerStartTime(0)
45     , mPollPeriod(0)
46     , mExternalPollPeriod(0)
47     , mFastPollsUsers(0)
48     , mTimer(aInstance)
49     , mEnabled(false)
50     , mAttachMode(false)
51     , mRetxMode(false)
52     , mPollTimeoutCounter(0)
53     , mPollTxFailureCounter(0)
54     , mRemainingFastPolls(0)
55 {
56 }
57 
GetParent(void) const58 const Neighbor &DataPollSender::GetParent(void) const
59 {
60     const Neighbor &parentCandidate = Get<Mle::MleRouter>().GetParentCandidate();
61 
62     return parentCandidate.IsStateValid() ? parentCandidate : Get<Mle::MleRouter>().GetParent();
63 }
64 
StartPolling(void)65 void DataPollSender::StartPolling(void)
66 {
67     VerifyOrExit(!mEnabled);
68 
69     OT_ASSERT(!Get<Mle::MleRouter>().IsRxOnWhenIdle());
70 
71     mEnabled = true;
72     ScheduleNextPoll(kRecalculatePollPeriod);
73 
74 exit:
75     return;
76 }
77 
StopPolling(void)78 void DataPollSender::StopPolling(void)
79 {
80     mTimer.Stop();
81     mAttachMode           = false;
82     mRetxMode             = false;
83     mPollTimeoutCounter   = 0;
84     mPollTxFailureCounter = 0;
85     mRemainingFastPolls   = 0;
86     mFastPollsUsers       = 0;
87     mEnabled              = false;
88 }
89 
SendDataPoll(void)90 Error DataPollSender::SendDataPoll(void)
91 {
92     Error error;
93 
94     VerifyOrExit(mEnabled, error = kErrorInvalidState);
95     VerifyOrExit(!Get<Mac::Mac>().GetRxOnWhenIdle(), error = kErrorInvalidState);
96 
97     VerifyOrExit(GetParent().IsStateValidOrRestoring(), error = kErrorInvalidState);
98 
99     mTimer.Stop();
100 
101     SuccessOrExit(error = Get<Mac::Mac>().RequestDataPollTransmission());
102 
103 exit:
104 
105     switch (error)
106     {
107     case kErrorNone:
108         LogDebg("Sending data poll");
109         ScheduleNextPoll(kUsePreviousPollPeriod);
110         break;
111 
112     case kErrorInvalidState:
113         LogWarn("Data poll tx requested while data polling was not enabled!");
114         StopPolling();
115         break;
116 
117     default:
118         LogWarn("Unexpected error %s requesting data poll", ErrorToString(error));
119         ScheduleNextPoll(kRecalculatePollPeriod);
120         break;
121     }
122 
123     return error;
124 }
125 
126 #if OPENTHREAD_CONFIG_MULTI_RADIO
GetPollDestinationAddress(Mac::Address & aDest,Mac::RadioType & aRadioType) const127 Error DataPollSender::GetPollDestinationAddress(Mac::Address &aDest, Mac::RadioType &aRadioType) const
128 #else
129 Error DataPollSender::GetPollDestinationAddress(Mac::Address &aDest) const
130 #endif
131 {
132     Error           error  = kErrorNone;
133     const Neighbor &parent = GetParent();
134 
135     VerifyOrExit(parent.IsStateValidOrRestoring(), error = kErrorAbort);
136 
137     // Use extended address attaching to a new parent (i.e. parent is the parent candidate).
138     if ((Get<Mac::Mac>().GetShortAddress() == Mac::kShortAddrInvalid) ||
139         (&parent == &Get<Mle::MleRouter>().GetParentCandidate()))
140     {
141         aDest.SetExtended(parent.GetExtAddress());
142     }
143     else
144     {
145         aDest.SetShort(parent.GetRloc16());
146     }
147 
148 #if OPENTHREAD_CONFIG_MULTI_RADIO
149     aRadioType = Get<RadioSelector>().SelectPollFrameRadio(parent);
150 #endif
151 
152 exit:
153     return error;
154 }
155 
SetExternalPollPeriod(uint32_t aPeriod)156 Error DataPollSender::SetExternalPollPeriod(uint32_t aPeriod)
157 {
158     Error error = kErrorNone;
159 
160     if (aPeriod != 0)
161     {
162         VerifyOrExit(aPeriod >= OPENTHREAD_CONFIG_MAC_MINIMUM_POLL_PERIOD, error = kErrorInvalidArgs);
163 
164         aPeriod = Min(aPeriod, kMaxExternalPeriod);
165     }
166 
167     if (mExternalPollPeriod != aPeriod)
168     {
169         mExternalPollPeriod = aPeriod;
170 
171         if (mEnabled)
172         {
173             ScheduleNextPoll(kRecalculatePollPeriod);
174         }
175     }
176 
177 exit:
178     return error;
179 }
180 
GetKeepAlivePollPeriod(void) const181 uint32_t DataPollSender::GetKeepAlivePollPeriod(void) const
182 {
183     uint32_t period = GetDefaultPollPeriod();
184 
185     if (mExternalPollPeriod != 0)
186     {
187         period = Min(period, mExternalPollPeriod);
188     }
189 
190     return period;
191 }
192 
HandlePollSent(Mac::TxFrame & aFrame,Error aError)193 void DataPollSender::HandlePollSent(Mac::TxFrame &aFrame, Error aError)
194 {
195     Mac::Address macDest;
196     bool         shouldRecalculatePollPeriod = false;
197 
198     VerifyOrExit(mEnabled);
199 
200     if (!aFrame.IsEmpty())
201     {
202         IgnoreError(aFrame.GetDstAddr(macDest));
203         Get<MeshForwarder>().UpdateNeighborOnSentFrame(aFrame, aError, macDest, /* aIsDataPoll */ true);
204     }
205 
206     if (GetParent().IsStateInvalid())
207     {
208         StopPolling();
209         IgnoreError(Get<Mle::MleRouter>().BecomeDetached());
210         ExitNow();
211     }
212 
213     switch (aError)
214     {
215     case kErrorNone:
216 
217         if (mRemainingFastPolls != 0)
218         {
219             mRemainingFastPolls--;
220 
221             if (mRemainingFastPolls == 0)
222             {
223                 shouldRecalculatePollPeriod = true;
224                 mFastPollsUsers             = 0;
225             }
226         }
227 
228         if (mRetxMode)
229         {
230             mRetxMode                   = false;
231             mPollTxFailureCounter       = 0;
232             shouldRecalculatePollPeriod = true;
233         }
234 
235         break;
236 
237     case kErrorChannelAccessFailure:
238     case kErrorAbort:
239         mRetxMode                   = true;
240         shouldRecalculatePollPeriod = true;
241         break;
242 
243     default:
244         mPollTxFailureCounter++;
245 
246 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
247         LogInfo("Failed to send data poll, error:%s, retx:%d/%d", ErrorToString(aError), mPollTxFailureCounter,
248                 aFrame.HasCslIe() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts);
249 #else
250         LogInfo("Failed to send data poll, error:%s, retx:%d/%d", ErrorToString(aError), mPollTxFailureCounter,
251                 kMaxPollRetxAttempts);
252 #endif
253 
254 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
255         if (mPollTxFailureCounter < (aFrame.HasCslIe() ? kMaxCslPollRetxAttempts : kMaxPollRetxAttempts))
256 #else
257         if (mPollTxFailureCounter < kMaxPollRetxAttempts)
258 #endif
259         {
260             if (!mRetxMode)
261             {
262                 mRetxMode                   = true;
263                 shouldRecalculatePollPeriod = true;
264             }
265         }
266         else
267         {
268             mRetxMode                   = false;
269             mPollTxFailureCounter       = 0;
270             shouldRecalculatePollPeriod = true;
271         }
272 
273         break;
274     }
275 
276     if (shouldRecalculatePollPeriod)
277     {
278         ScheduleNextPoll(kRecalculatePollPeriod);
279     }
280 
281 exit:
282     return;
283 }
284 
HandlePollTimeout(void)285 void DataPollSender::HandlePollTimeout(void)
286 {
287     // A data poll timeout happened, i.e., the ack in response to
288     // a data poll indicated that a frame was pending, but no frame
289     // was received after timeout interval.
290 
291     VerifyOrExit(mEnabled);
292 
293     mPollTimeoutCounter++;
294 
295     LogInfo("Data poll timeout, retry:%d/%d", mPollTimeoutCounter, kQuickPollsAfterTimeout);
296 
297     if (mPollTimeoutCounter < kQuickPollsAfterTimeout)
298     {
299         IgnoreError(SendDataPoll());
300     }
301     else
302     {
303         mPollTimeoutCounter = 0;
304     }
305 
306 exit:
307     return;
308 }
309 
ProcessRxFrame(const Mac::RxFrame & aFrame)310 void DataPollSender::ProcessRxFrame(const Mac::RxFrame &aFrame)
311 {
312     VerifyOrExit(mEnabled);
313 
314     mPollTimeoutCounter = 0;
315 
316     if (aFrame.GetFramePending())
317     {
318         IgnoreError(SendDataPoll());
319     }
320 
321 exit:
322     return;
323 }
324 
325 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
ProcessTxDone(const Mac::TxFrame & aFrame,const Mac::RxFrame * aAckFrame,Error aError)326 void DataPollSender::ProcessTxDone(const Mac::TxFrame &aFrame, const Mac::RxFrame *aAckFrame, Error aError)
327 {
328     bool sendDataPoll = false;
329 
330     VerifyOrExit(mEnabled);
331     VerifyOrExit(Get<Mle::MleRouter>().GetParent().IsEnhancedKeepAliveSupported());
332     VerifyOrExit(aFrame.GetSecurityEnabled());
333 
334 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
335     if (aFrame.mInfo.mTxInfo.mIsARetx && aFrame.HasCslIe())
336     {
337         // For retransmission frame, use a data poll to resync its parent with correct CSL phase
338         sendDataPoll = true;
339     }
340 #endif
341 
342     if (aError == kErrorNone && aAckFrame != nullptr)
343     {
344         mPollTimeoutCounter = 0;
345 
346         if (aAckFrame->GetFramePending())
347         {
348             sendDataPoll = true;
349         }
350         else
351         {
352             ResetKeepAliveTimer();
353         }
354     }
355 
356     if (sendDataPoll)
357     {
358         IgnoreError(SendDataPoll());
359     }
360 
361 exit:
362     return;
363 }
364 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
365 
RecalculatePollPeriod(void)366 void DataPollSender::RecalculatePollPeriod(void)
367 {
368     if (mEnabled)
369     {
370         ScheduleNextPoll(kRecalculatePollPeriod);
371     }
372 }
373 
SetAttachMode(bool aMode)374 void DataPollSender::SetAttachMode(bool aMode)
375 {
376     if (mAttachMode != aMode)
377     {
378         mAttachMode = aMode;
379 
380         if (mEnabled)
381         {
382             ScheduleNextPoll(kRecalculatePollPeriod);
383         }
384     }
385 }
386 
SendFastPolls(uint8_t aNumFastPolls)387 void DataPollSender::SendFastPolls(uint8_t aNumFastPolls)
388 {
389     bool shouldRecalculatePollPeriod = (mRemainingFastPolls == 0);
390 
391     if (mFastPollsUsers < kMaxFastPollsUsers)
392     {
393         mFastPollsUsers++;
394     }
395 
396     if (aNumFastPolls == 0)
397     {
398         aNumFastPolls = kDefaultFastPolls;
399     }
400 
401     aNumFastPolls       = Min(aNumFastPolls, kMaxFastPolls);
402     mRemainingFastPolls = Max(mRemainingFastPolls, aNumFastPolls);
403 
404     if (mEnabled && shouldRecalculatePollPeriod)
405     {
406         ScheduleNextPoll(kRecalculatePollPeriod);
407     }
408 }
409 
StopFastPolls(void)410 void DataPollSender::StopFastPolls(void)
411 {
412     VerifyOrExit(mFastPollsUsers != 0);
413 
414     // If `mFastPollsUsers` hits the max, let it be cleared
415     // from `HandlePollSent()` (after all fast polls are sent).
416     VerifyOrExit(mFastPollsUsers < kMaxFastPollsUsers);
417 
418     mFastPollsUsers--;
419 
420     VerifyOrExit(mFastPollsUsers == 0);
421 
422     mRemainingFastPolls = 0;
423     ScheduleNextPoll(kRecalculatePollPeriod);
424 
425 exit:
426     return;
427 }
428 
ResetKeepAliveTimer(void)429 void DataPollSender::ResetKeepAliveTimer(void)
430 {
431     if (mTimer.IsRunning() && mPollPeriod == GetDefaultPollPeriod())
432     {
433         mTimerStartTime = TimerMilli::GetNow();
434         mTimer.StartAt(mTimerStartTime, mPollPeriod);
435     }
436 }
437 
ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector)438 void DataPollSender::ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector)
439 {
440     TimeMilli now;
441     uint32_t  oldPeriod = mPollPeriod;
442 
443     if (aPollPeriodSelector == kRecalculatePollPeriod)
444     {
445         mPollPeriod = CalculatePollPeriod();
446     }
447 
448     now = TimerMilli::GetNow();
449 
450     if (mTimer.IsRunning())
451     {
452         if (oldPeriod != mPollPeriod)
453         {
454             // If poll interval did change and re-starting the timer from
455             // last start time with new poll interval would fire quickly
456             // (i.e., fires within window `[now, now + kMinPollPeriod]`)
457             // add an extra minimum delay of `kMinPollPeriod`. This
458             // ensures that when an internal or external request triggers
459             // a switch to a shorter poll interval, the first data poll
460             // will not be sent too quickly (and possibly before the
461             // response is available/prepared on the parent node).
462 
463             if (mTimerStartTime + mPollPeriod < now + kMinPollPeriod)
464             {
465                 mTimer.StartAt(now, kMinPollPeriod);
466             }
467             else
468             {
469                 mTimer.StartAt(mTimerStartTime, mPollPeriod);
470             }
471         }
472         // Do nothing on the running poll timer if the poll interval doesn't change
473     }
474     else
475     {
476         mTimerStartTime = now;
477         mTimer.StartAt(mTimerStartTime, mPollPeriod);
478     }
479 }
480 
CalculatePollPeriod(void) const481 uint32_t DataPollSender::CalculatePollPeriod(void) const
482 {
483     uint32_t period = GetDefaultPollPeriod();
484 
485     if (mAttachMode)
486     {
487         period = Min(period, kAttachDataPollPeriod);
488     }
489 
490     if (mRetxMode)
491     {
492         period = Min(period, kRetxPollPeriod);
493 
494 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
495         if (Get<Mac::Mac>().GetCslPeriodInMsec() > 0)
496         {
497             period = Min(period, Get<Mac::Mac>().GetCslPeriodInMsec());
498         }
499 #endif
500     }
501 
502     if (mRemainingFastPolls != 0)
503     {
504         period = Min(period, kFastPollPeriod);
505     }
506 
507     if (mExternalPollPeriod != 0)
508     {
509         period = Min(period, mExternalPollPeriod);
510     }
511 
512     if (period == 0)
513     {
514         period = kMinPollPeriod;
515     }
516 
517     return period;
518 }
519 
GetDefaultPollPeriod(void) const520 uint32_t DataPollSender::GetDefaultPollPeriod(void) const
521 {
522     uint32_t pollAhead = static_cast<uint32_t>(kRetxPollPeriod) * kMaxPollRetxAttempts;
523     uint32_t period;
524 
525     period = Time::SecToMsec(Min(Get<Mle::MleRouter>().GetTimeout(), Time::MsecToSec(TimerMilli::kMaxDelay)));
526 
527 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_MAC_CSL_AUTO_SYNC_ENABLE
528     if (Get<Mac::Mac>().IsCslEnabled())
529     {
530         period    = Min(period, Time::SecToMsec(Get<Mle::MleRouter>().GetCslTimeout()));
531         pollAhead = static_cast<uint32_t>(kRetxPollPeriod);
532     }
533 #endif
534 
535     if (period > pollAhead)
536     {
537         period -= pollAhead;
538     }
539 
540     return period;
541 }
542 
PrepareDataRequest(Mac::TxFrames & aTxFrames)543 Mac::TxFrame *DataPollSender::PrepareDataRequest(Mac::TxFrames &aTxFrames)
544 {
545     Mac::TxFrame      *frame = nullptr;
546     Mac::TxFrame::Info frameInfo;
547 
548 #if OPENTHREAD_CONFIG_MULTI_RADIO
549     Mac::RadioType radio;
550 
551     SuccessOrExit(GetPollDestinationAddress(frameInfo.mAddrs.mDestination, radio));
552     frame = &aTxFrames.GetTxFrame(radio);
553 #else
554     SuccessOrExit(GetPollDestinationAddress(frameInfo.mAddrs.mDestination));
555     frame = &aTxFrames.GetTxFrame();
556 #endif
557 
558     if (frameInfo.mAddrs.mDestination.IsExtended())
559     {
560         frameInfo.mAddrs.mSource.SetExtended(Get<Mac::Mac>().GetExtAddress());
561     }
562     else
563     {
564         frameInfo.mAddrs.mSource.SetShort(Get<Mac::Mac>().GetShortAddress());
565     }
566 
567     frameInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
568 
569     frameInfo.mType          = Mac::Frame::kTypeMacCmd;
570     frameInfo.mCommandId     = Mac::Frame::kMacCmdDataRequest;
571     frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
572     frameInfo.mKeyIdMode     = Mac::Frame::kKeyIdMode1;
573 
574     Get<MeshForwarder>().PrepareMacHeaders(*frame, frameInfo, nullptr);
575 
576 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
577     if (frame->HasCslIe())
578     {
579         // Disable frame retransmission when the data poll has CSL IE included
580         aTxFrames.SetMaxFrameRetries(0);
581     }
582 #endif
583 
584 exit:
585     return frame;
586 }
587 
588 } // namespace ot
589