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::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(static_cast<uint8_t>(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