• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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