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