• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 the implementation for handling of data polls and indirect frame transmission.
32  */
33 
34 #include "data_poll_handler.hpp"
35 
36 #if OPENTHREAD_FTD
37 
38 #include "common/code_utils.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 
43 namespace ot {
44 
45 RegisterLogModule("DataPollHandlr");
46 
Callbacks(Instance & aInstance)47 DataPollHandler::Callbacks::Callbacks(Instance &aInstance)
48     : InstanceLocator(aInstance)
49 {
50 }
51 
PrepareFrameForChild(Mac::TxFrame & aFrame,FrameContext & aContext,Child & aChild)52 inline Error DataPollHandler::Callbacks::PrepareFrameForChild(Mac::TxFrame &aFrame,
53                                                               FrameContext &aContext,
54                                                               Child &       aChild)
55 {
56     return Get<IndirectSender>().PrepareFrameForChild(aFrame, aContext, aChild);
57 }
58 
HandleSentFrameToChild(const Mac::TxFrame & aFrame,const FrameContext & aContext,Error aError,Child & aChild)59 inline void DataPollHandler::Callbacks::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
60                                                                const FrameContext &aContext,
61                                                                Error               aError,
62                                                                Child &             aChild)
63 {
64     Get<IndirectSender>().HandleSentFrameToChild(aFrame, aContext, aError, aChild);
65 }
66 
HandleFrameChangeDone(Child & aChild)67 inline void DataPollHandler::Callbacks::HandleFrameChangeDone(Child &aChild)
68 {
69     Get<IndirectSender>().HandleFrameChangeDone(aChild);
70 }
71 
72 //---------------------------------------------------------
73 
DataPollHandler(Instance & aInstance)74 DataPollHandler::DataPollHandler(Instance &aInstance)
75     : InstanceLocator(aInstance)
76     , mIndirectTxChild(nullptr)
77     , mFrameContext()
78     , mCallbacks(aInstance)
79 {
80 }
81 
Clear(void)82 void DataPollHandler::Clear(void)
83 {
84     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
85     {
86         child.SetDataPollPending(false);
87         child.SetFrameReplacePending(false);
88         child.SetFramePurgePending(false);
89         child.ResetIndirectTxAttempts();
90     }
91 
92     mIndirectTxChild = nullptr;
93 }
94 
HandleNewFrame(Child & aChild)95 void DataPollHandler::HandleNewFrame(Child &aChild)
96 {
97     OT_UNUSED_VARIABLE(aChild);
98 
99     // There is no need to take any action with current data poll
100     // handler implementation, since the preparation of the frame
101     // happens after receiving of a data poll from the child. This
102     // method is included for use by other data poll handler models
103     // (e.g., in RCP/host model if the handling of data polls is
104     // delegated to RCP).
105 }
106 
RequestFrameChange(FrameChange aChange,Child & aChild)107 void DataPollHandler::RequestFrameChange(FrameChange aChange, Child &aChild)
108 {
109     if ((mIndirectTxChild == &aChild) && Get<Mac::Mac>().IsPerformingIndirectTransmit())
110     {
111         switch (aChange)
112         {
113         case kReplaceFrame:
114             aChild.SetFrameReplacePending(true);
115             break;
116 
117         case kPurgeFrame:
118             aChild.SetFramePurgePending(true);
119             break;
120         }
121     }
122     else
123     {
124         mCallbacks.HandleFrameChangeDone(aChild);
125     }
126 }
127 
HandleDataPoll(Mac::RxFrame & aFrame)128 void DataPollHandler::HandleDataPoll(Mac::RxFrame &aFrame)
129 {
130     Mac::Address macSource;
131     Child *      child;
132     uint16_t     indirectMsgCount;
133 
134     VerifyOrExit(aFrame.GetSecurityEnabled());
135     VerifyOrExit(!Get<Mle::MleRouter>().IsDetached());
136 
137     SuccessOrExit(aFrame.GetSrcAddr(macSource));
138     child = Get<ChildTable>().FindChild(macSource, Child::kInStateValidOrRestoring);
139     VerifyOrExit(child != nullptr);
140 
141     child->SetLastHeard(TimerMilli::GetNow());
142     child->ResetLinkFailures();
143 #if OPENTHREAD_CONFIG_MULTI_RADIO
144     child->SetLastPollRadioType(aFrame.GetRadioType());
145 #endif
146 
147     indirectMsgCount = child->GetIndirectMessageCount();
148 
149     LogInfo("Rx data poll, src:0x%04x, qed_msgs:%d, rss:%d, ack-fp:%d", child->GetRloc16(), indirectMsgCount,
150             aFrame.GetRssi(), aFrame.IsAckedWithFramePending());
151 
152     if (!aFrame.IsAckedWithFramePending())
153     {
154         if ((indirectMsgCount > 0) && macSource.IsShort())
155         {
156             Get<SourceMatchController>().SetSrcMatchAsShort(*child, true);
157         }
158 
159         ExitNow();
160     }
161 
162     if (mIndirectTxChild == nullptr)
163     {
164         mIndirectTxChild = child;
165         Get<Mac::Mac>().RequestIndirectFrameTransmission();
166     }
167     else
168     {
169         child->SetDataPollPending(true);
170     }
171 
172 exit:
173     return;
174 }
175 
HandleFrameRequest(Mac::TxFrames & aTxFrames)176 Mac::TxFrame *DataPollHandler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
177 {
178     Mac::TxFrame *frame = nullptr;
179 
180     VerifyOrExit(mIndirectTxChild != nullptr);
181 
182 #if OPENTHREAD_CONFIG_MULTI_RADIO
183     frame = &aTxFrames.GetTxFrame(mIndirectTxChild->GetLastPollRadioType());
184 #else
185     frame = &aTxFrames.GetTxFrame();
186 #endif
187 
188     VerifyOrExit(mCallbacks.PrepareFrameForChild(*frame, mFrameContext, *mIndirectTxChild) == kErrorNone,
189                  frame = nullptr);
190 
191     if (mIndirectTxChild->GetIndirectTxAttempts() > 0)
192     {
193         // For a re-transmission of an indirect frame to a sleepy
194         // child, we ensure to use the same frame counter, key id, and
195         // data sequence number as the previous attempt.
196 
197         frame->SetIsARetransmission(true);
198         frame->SetSequence(mIndirectTxChild->GetIndirectDataSequenceNumber());
199 
200         if (frame->GetSecurityEnabled())
201         {
202             frame->SetFrameCounter(mIndirectTxChild->GetIndirectFrameCounter());
203             frame->SetKeyId(mIndirectTxChild->GetIndirectKeyId());
204         }
205     }
206     else
207     {
208         frame->SetIsARetransmission(false);
209     }
210 
211 exit:
212     return frame;
213 }
214 
HandleSentFrame(const Mac::TxFrame & aFrame,Error aError)215 void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
216 {
217     Child *child = mIndirectTxChild;
218 
219     VerifyOrExit(child != nullptr);
220 
221     mIndirectTxChild = nullptr;
222     HandleSentFrame(aFrame, aError, *child);
223 
224 exit:
225     ProcessPendingPolls();
226 }
227 
HandleSentFrame(const Mac::TxFrame & aFrame,Error aError,Child & aChild)228 void DataPollHandler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild)
229 {
230     if (aChild.IsFramePurgePending())
231     {
232         aChild.SetFramePurgePending(false);
233         aChild.SetFrameReplacePending(false);
234         aChild.ResetIndirectTxAttempts();
235         mCallbacks.HandleFrameChangeDone(aChild);
236         ExitNow();
237     }
238 
239     switch (aError)
240     {
241     case kErrorNone:
242         aChild.ResetIndirectTxAttempts();
243         aChild.SetFrameReplacePending(false);
244         break;
245 
246     case kErrorNoAck:
247         OT_ASSERT(!aFrame.GetSecurityEnabled() || aFrame.IsHeaderUpdated());
248 
249         aChild.IncrementIndirectTxAttempts();
250         LogInfo("Indirect tx to child %04x failed, attempt %d/%d", aChild.GetRloc16(), aChild.GetIndirectTxAttempts(),
251                 kMaxPollTriggeredTxAttempts);
252 
253         OT_FALL_THROUGH;
254 
255     case kErrorChannelAccessFailure:
256     case kErrorAbort:
257 
258         if (aChild.IsFrameReplacePending())
259         {
260             aChild.SetFrameReplacePending(false);
261             aChild.ResetIndirectTxAttempts();
262             mCallbacks.HandleFrameChangeDone(aChild);
263             ExitNow();
264         }
265 
266         if ((aChild.GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts) && !aFrame.IsEmpty())
267         {
268             // We save the frame counter, key id, and data sequence number of
269             // current frame so we use the same values for the retransmission
270             // of the frame following the receipt of the next data poll.
271 
272             aChild.SetIndirectDataSequenceNumber(aFrame.GetSequence());
273 
274             if (aFrame.GetSecurityEnabled() && aFrame.IsHeaderUpdated())
275             {
276                 uint32_t frameCounter;
277                 uint8_t  keyId;
278 
279                 SuccessOrAssert(aFrame.GetFrameCounter(frameCounter));
280                 aChild.SetIndirectFrameCounter(frameCounter);
281 
282                 SuccessOrAssert(aFrame.GetKeyId(keyId));
283                 aChild.SetIndirectKeyId(keyId);
284             }
285 
286             ExitNow();
287         }
288 
289         aChild.ResetIndirectTxAttempts();
290         break;
291 
292     default:
293         OT_ASSERT(false);
294         OT_UNREACHABLE_CODE(break);
295     }
296 
297     mCallbacks.HandleSentFrameToChild(aFrame, mFrameContext, aError, aChild);
298 
299 exit:
300     return;
301 }
302 
ProcessPendingPolls(void)303 void DataPollHandler::ProcessPendingPolls(void)
304 {
305     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
306     {
307         if (!child.IsDataPollPending())
308         {
309             continue;
310         }
311 
312         // Find the child with earliest poll receive time.
313 
314         if ((mIndirectTxChild == nullptr) || (child.GetLastHeard() < mIndirectTxChild->GetLastHeard()))
315         {
316             mIndirectTxChild = &child;
317         }
318     }
319 
320     if (mIndirectTxChild != nullptr)
321     {
322         mIndirectTxChild->SetDataPollPending(false);
323         Get<Mac::Mac>().RequestIndirectFrameTransmission();
324     }
325 }
326 
327 } // namespace ot
328 
329 #endif // #if OPENTHREAD_FTD
330