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