1 /*
2 * Copyright (c) 2016-2018, 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 Thread child table.
32 */
33
34 #include "child_table.hpp"
35
36 #if OPENTHREAD_FTD
37
38 #include "instance/instance.hpp"
39
40 namespace ot {
41
Iterator(Instance & aInstance,Child::StateFilter aFilter)42 ChildTable::Iterator::Iterator(Instance &aInstance, Child::StateFilter aFilter)
43 : InstanceLocator(aInstance)
44 , ItemPtrIterator(nullptr)
45 , mFilter(aFilter)
46 {
47 Reset();
48 }
49
Reset(void)50 void ChildTable::Iterator::Reset(void)
51 {
52 mItem = &Get<ChildTable>().mChildren[0];
53
54 if (!mItem->MatchesFilter(mFilter))
55 {
56 Advance();
57 }
58 }
59
Advance(void)60 void ChildTable::Iterator::Advance(void)
61 {
62 VerifyOrExit(mItem != nullptr);
63
64 do
65 {
66 mItem++;
67 VerifyOrExit(mItem < &Get<ChildTable>().mChildren[Get<ChildTable>().mMaxChildrenAllowed], mItem = nullptr);
68 } while (!mItem->MatchesFilter(mFilter));
69
70 exit:
71 return;
72 }
73
ChildTable(Instance & aInstance)74 ChildTable::ChildTable(Instance &aInstance)
75 : InstanceLocator(aInstance)
76 , mMaxChildrenAllowed(kMaxChildren)
77 {
78 for (Child &child : mChildren)
79 {
80 child.Init(aInstance);
81 child.Clear();
82 }
83 }
84
Clear(void)85 void ChildTable::Clear(void)
86 {
87 for (Child &child : mChildren)
88 {
89 child.Clear();
90 }
91 }
92
GetChildAtIndex(uint16_t aChildIndex)93 Child *ChildTable::GetChildAtIndex(uint16_t aChildIndex)
94 {
95 Child *child = nullptr;
96
97 VerifyOrExit(aChildIndex < mMaxChildrenAllowed);
98 child = &mChildren[aChildIndex];
99
100 exit:
101 return child;
102 }
103
GetNewChild(void)104 Child *ChildTable::GetNewChild(void)
105 {
106 Child *child = FindChild(Child::AddressMatcher(Child::kInStateInvalid));
107
108 VerifyOrExit(child != nullptr);
109 child->Clear();
110
111 exit:
112 return child;
113 }
114
FindChild(const Child::AddressMatcher & aMatcher) const115 const Child *ChildTable::FindChild(const Child::AddressMatcher &aMatcher) const
116 {
117 const Child *child = mChildren;
118
119 for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
120 {
121 if (child->Matches(aMatcher))
122 {
123 ExitNow();
124 }
125 }
126
127 child = nullptr;
128
129 exit:
130 return child;
131 }
132
FindChild(uint16_t aRloc16,Child::StateFilter aFilter)133 Child *ChildTable::FindChild(uint16_t aRloc16, Child::StateFilter aFilter)
134 {
135 return FindChild(Child::AddressMatcher(aRloc16, aFilter));
136 }
137
FindChild(const Mac::ExtAddress & aExtAddress,Child::StateFilter aFilter)138 Child *ChildTable::FindChild(const Mac::ExtAddress &aExtAddress, Child::StateFilter aFilter)
139 {
140 return FindChild(Child::AddressMatcher(aExtAddress, aFilter));
141 }
142
FindChild(const Mac::Address & aMacAddress,Child::StateFilter aFilter)143 Child *ChildTable::FindChild(const Mac::Address &aMacAddress, Child::StateFilter aFilter)
144 {
145 return FindChild(Child::AddressMatcher(aMacAddress, aFilter));
146 }
147
HasChildren(Child::StateFilter aFilter) const148 bool ChildTable::HasChildren(Child::StateFilter aFilter) const
149 {
150 return (FindChild(Child::AddressMatcher(aFilter)) != nullptr);
151 }
152
GetNumChildren(Child::StateFilter aFilter) const153 uint16_t ChildTable::GetNumChildren(Child::StateFilter aFilter) const
154 {
155 uint16_t numChildren = 0;
156 const Child *child = mChildren;
157
158 for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
159 {
160 if (child->MatchesFilter(aFilter))
161 {
162 numChildren++;
163 }
164 }
165
166 return numChildren;
167 }
168
SetMaxChildrenAllowed(uint16_t aMaxChildren)169 Error ChildTable::SetMaxChildrenAllowed(uint16_t aMaxChildren)
170 {
171 Error error = kErrorNone;
172
173 VerifyOrExit(aMaxChildren > 0 && aMaxChildren <= kMaxChildren, error = kErrorInvalidArgs);
174 VerifyOrExit(!HasChildren(Child::kInStateAnyExceptInvalid), error = kErrorInvalidState);
175
176 mMaxChildrenAllowed = aMaxChildren;
177
178 exit:
179 return error;
180 }
181
GetChildInfoById(uint16_t aChildId,Child::Info & aChildInfo)182 Error ChildTable::GetChildInfoById(uint16_t aChildId, Child::Info &aChildInfo)
183 {
184 Error error = kErrorNone;
185 Child *child;
186 uint16_t rloc16;
187
188 if ((aChildId & ~Mle::kMaxChildId) != 0)
189 {
190 aChildId = Mle::ChildIdFromRloc16(aChildId);
191 }
192
193 rloc16 = Get<Mle::Mle>().GetRloc16() | aChildId;
194 child = FindChild(rloc16, Child::kInStateValidOrRestoring);
195 VerifyOrExit(child != nullptr, error = kErrorNotFound);
196
197 aChildInfo.SetFrom(*child);
198
199 exit:
200 return error;
201 }
202
GetChildInfoByIndex(uint16_t aChildIndex,Child::Info & aChildInfo)203 Error ChildTable::GetChildInfoByIndex(uint16_t aChildIndex, Child::Info &aChildInfo)
204 {
205 Error error = kErrorNone;
206 Child *child = nullptr;
207
208 child = GetChildAtIndex(aChildIndex);
209 VerifyOrExit((child != nullptr) && child->IsStateValidOrRestoring(), error = kErrorNotFound);
210
211 aChildInfo.SetFrom(*child);
212
213 exit:
214 return error;
215 }
216
Restore(void)217 void ChildTable::Restore(void)
218 {
219 Error error = kErrorNone;
220 bool foundDuplicate = false;
221 uint16_t numChildren = 0;
222
223 for (const Settings::ChildInfo &childInfo : Get<Settings>().IterateChildInfo())
224 {
225 Child *child;
226
227 child = FindChild(childInfo.GetExtAddress(), Child::kInStateAnyExceptInvalid);
228
229 if (child == nullptr)
230 {
231 VerifyOrExit((child = GetNewChild()) != nullptr, error = kErrorNoBufs);
232 }
233 else
234 {
235 foundDuplicate = true;
236 }
237
238 child->Clear();
239
240 child->SetExtAddress(childInfo.GetExtAddress());
241 child->GetLinkInfo().Clear();
242 child->SetRloc16(childInfo.GetRloc16());
243 child->SetTimeout(childInfo.GetTimeout());
244 child->SetDeviceMode(Mle::DeviceMode(childInfo.GetMode()));
245 child->SetState(Neighbor::kStateRestored);
246 child->GenerateChallenge();
247 child->SetLastHeard(TimerMilli::GetNow());
248 child->SetVersion(childInfo.GetVersion());
249 Get<IndirectSender>().SetChildUseShortAddress(*child, true);
250 Get<NeighborTable>().Signal(NeighborTable::kChildAdded, *child);
251 numChildren++;
252 }
253
254 exit:
255
256 if (foundDuplicate || (numChildren > GetMaxChildren()) || (error != kErrorNone))
257 {
258 // If there is any error, e.g., there are more saved children
259 // in non-volatile settings than could be restored or there are
260 // duplicate entries with same extended address, refresh the stored
261 // children info to ensure that the non-volatile settings remain
262 // consistent with the child table.
263
264 RefreshStoredChildren();
265 }
266 }
267
RemoveStoredChild(const Child & aChild)268 void ChildTable::RemoveStoredChild(const Child &aChild)
269 {
270 for (Settings::ChildInfoIterator iter(GetInstance()); !iter.IsDone(); iter++)
271 {
272 if (iter.GetChildInfo().GetRloc16() == aChild.GetRloc16())
273 {
274 IgnoreError(iter.Delete());
275 break;
276 }
277 }
278 }
279
StoreChild(const Child & aChild)280 Error ChildTable::StoreChild(const Child &aChild)
281 {
282 Settings::ChildInfo childInfo;
283
284 RemoveStoredChild(aChild);
285
286 childInfo.Init();
287 childInfo.SetExtAddress(aChild.GetExtAddress());
288 childInfo.SetTimeout(aChild.GetTimeout());
289 childInfo.SetRloc16(aChild.GetRloc16());
290 childInfo.SetMode(aChild.GetDeviceMode().Get());
291 childInfo.SetVersion(aChild.GetVersion());
292
293 return Get<Settings>().AddChildInfo(childInfo);
294 }
295
RefreshStoredChildren(void)296 void ChildTable::RefreshStoredChildren(void)
297 {
298 const Child *child = &mChildren[0];
299
300 SuccessOrExit(Get<Settings>().DeleteAllChildInfo());
301
302 for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
303 {
304 if (child->IsStateInvalid())
305 {
306 continue;
307 }
308
309 SuccessOrExit(StoreChild(*child));
310 }
311
312 exit:
313 return;
314 }
315
HasMinimalChild(uint16_t aRloc16) const316 bool ChildTable::HasMinimalChild(uint16_t aRloc16) const
317 {
318 bool hasMinimalChild = false;
319 const Child *child;
320
321 VerifyOrExit(Get<Mle::Mle>().HasMatchingRouterIdWith(aRloc16));
322
323 child = FindChild(Child::AddressMatcher(aRloc16, Child::kInStateValidOrRestoring));
324 VerifyOrExit(child != nullptr);
325
326 hasMinimalChild = !child->IsFullThreadDevice();
327
328 exit:
329 return hasMinimalChild;
330 }
331
HasSleepyChildWithAddress(const Ip6::Address & aIp6Address) const332 bool ChildTable::HasSleepyChildWithAddress(const Ip6::Address &aIp6Address) const
333 {
334 bool hasChild = false;
335 const Child *child = &mChildren[0];
336
337 for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++)
338 {
339 if (child->IsStateValidOrRestoring() && !child->IsRxOnWhenIdle() && child->HasIp6Address(aIp6Address))
340 {
341 hasChild = true;
342 break;
343 }
344 }
345
346 return hasChild;
347 }
348
349 } // namespace ot
350
351 #endif // OPENTHREAD_FTD
352