1 /*
2  *  Copyright (c) 2016-2017, 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 a Thread `Child`.
32  */
33 
34 #include "child.hpp"
35 
36 #include "common/array.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/num_utils.hpp"
42 
43 namespace ot {
44 
45 #if OPENTHREAD_FTD
46 
SetFrom(const Child & aChild)47 void Child::Info::SetFrom(const Child &aChild)
48 {
49     Clear();
50     mExtAddress          = aChild.GetExtAddress();
51     mTimeout             = aChild.GetTimeout();
52     mRloc16              = aChild.GetRloc16();
53     mChildId             = Mle::ChildIdFromRloc16(aChild.GetRloc16());
54     mNetworkDataVersion  = aChild.GetNetworkDataVersion();
55     mAge                 = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
56     mLinkQualityIn       = aChild.GetLinkQualityIn();
57     mAverageRssi         = aChild.GetLinkInfo().GetAverageRss();
58     mLastRssi            = aChild.GetLinkInfo().GetLastRss();
59     mFrameErrorRate      = aChild.GetLinkInfo().GetFrameErrorRate();
60     mMessageErrorRate    = aChild.GetLinkInfo().GetMessageErrorRate();
61     mQueuedMessageCnt    = aChild.GetIndirectMessageCount();
62     mVersion             = ClampToUint8(aChild.GetVersion());
63     mRxOnWhenIdle        = aChild.IsRxOnWhenIdle();
64     mFullThreadDevice    = aChild.IsFullThreadDevice();
65     mFullNetworkData     = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
66     mIsStateRestoring    = aChild.IsStateRestoring();
67     mSupervisionInterval = aChild.GetSupervisionInterval();
68 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
69     mIsCslSynced = aChild.IsCslSynchronized();
70 #else
71     mIsCslSynced = false;
72 #endif
73 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
74     mConnectionTime = aChild.GetConnectionTime();
75 #endif
76 }
77 
GetAddress(void) const78 const Ip6::Address *Child::AddressIterator::GetAddress(void) const
79 {
80     // `mIndex` value of zero indicates mesh-local IPv6 address.
81     // Non-zero value specifies the index into address array starting
82     // from one for first element (i.e, `mIndex - 1` gives the array
83     // index).
84 
85     return (mIndex == 0) ? &mMeshLocalAddress : ((mIndex < kMaxIndex) ? &mChild.mIp6Address[mIndex - 1] : nullptr);
86 }
87 
Update(void)88 void Child::AddressIterator::Update(void)
89 {
90     const Ip6::Address *address;
91 
92     if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone))
93     {
94         mIndex++;
95     }
96 
97     while (true)
98     {
99         address = GetAddress();
100 
101         VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex);
102 
103         VerifyOrExit(!address->MatchesFilter(mFilter));
104         mIndex++;
105     }
106 
107 exit:
108     return;
109 }
110 
Clear(void)111 void Child::Clear(void)
112 {
113     Instance &instance = GetInstance();
114 
115     memset(reinterpret_cast<void *>(this), 0, sizeof(Child));
116     Init(instance);
117 }
118 
ClearIp6Addresses(void)119 void Child::ClearIp6Addresses(void)
120 {
121     mMeshLocalIid.Clear();
122     memset(mIp6Address, 0, sizeof(mIp6Address));
123 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
124     mMlrToRegisterMask.Clear();
125     mMlrRegisteredMask.Clear();
126 #endif
127 }
128 
SetDeviceMode(Mle::DeviceMode aMode)129 void Child::SetDeviceMode(Mle::DeviceMode aMode)
130 {
131     VerifyOrExit(aMode != GetDeviceMode());
132 
133     Neighbor::SetDeviceMode(aMode);
134 
135     VerifyOrExit(IsStateValid());
136     Get<NeighborTable>().Signal(NeighborTable::kChildModeChanged, *this);
137 
138 exit:
139     return;
140 }
141 
GetMeshLocalIp6Address(Ip6::Address & aAddress) const142 Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const
143 {
144     Error error = kErrorNone;
145 
146     VerifyOrExit(!mMeshLocalIid.IsUnspecified(), error = kErrorNotFound);
147 
148     aAddress.SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
149     aAddress.SetIid(mMeshLocalIid);
150 
151 exit:
152     return error;
153 }
154 
AddIp6Address(const Ip6::Address & aAddress)155 Error Child::AddIp6Address(const Ip6::Address &aAddress)
156 {
157     Error error = kErrorNone;
158 
159     VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
160 
161     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
162     {
163         VerifyOrExit(mMeshLocalIid.IsUnspecified(), error = kErrorAlready);
164         mMeshLocalIid = aAddress.GetIid();
165         ExitNow();
166     }
167 
168     for (Ip6::Address &ip6Address : mIp6Address)
169     {
170         if (ip6Address.IsUnspecified())
171         {
172             ip6Address = aAddress;
173             ExitNow();
174         }
175 
176         VerifyOrExit(ip6Address != aAddress, error = kErrorAlready);
177     }
178 
179     error = kErrorNoBufs;
180 
181 exit:
182     return error;
183 }
184 
RemoveIp6Address(const Ip6::Address & aAddress)185 Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
186 {
187     Error    error = kErrorNotFound;
188     uint16_t index;
189 
190     VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
191 
192     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
193     {
194         if (aAddress.GetIid() == mMeshLocalIid)
195         {
196             mMeshLocalIid.Clear();
197             error = kErrorNone;
198         }
199 
200         ExitNow();
201     }
202 
203     for (index = 0; index < kNumIp6Addresses; index++)
204     {
205         VerifyOrExit(!mIp6Address[index].IsUnspecified());
206 
207         if (mIp6Address[index] == aAddress)
208         {
209             error = kErrorNone;
210             break;
211         }
212     }
213 
214     SuccessOrExit(error);
215 
216     for (; index < kNumIp6Addresses - 1; index++)
217     {
218         mIp6Address[index] = mIp6Address[index + 1];
219     }
220 
221     mIp6Address[kNumIp6Addresses - 1].Clear();
222 
223 exit:
224     return error;
225 }
226 
HasIp6Address(const Ip6::Address & aAddress) const227 bool Child::HasIp6Address(const Ip6::Address &aAddress) const
228 {
229     bool retval = false;
230 
231     VerifyOrExit(!aAddress.IsUnspecified());
232 
233     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
234     {
235         retval = (aAddress.GetIid() == mMeshLocalIid);
236         ExitNow();
237     }
238 
239     for (const Ip6::Address &ip6Address : mIp6Address)
240     {
241         VerifyOrExit(!ip6Address.IsUnspecified());
242 
243         if (ip6Address == aAddress)
244         {
245             ExitNow(retval = true);
246         }
247     }
248 
249 exit:
250     return retval;
251 }
252 
253 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
GetDomainUnicastAddress(void) const254 const Ip6::Address *Child::GetDomainUnicastAddress(void) const
255 {
256     const Ip6::Address *addr = nullptr;
257 
258     for (const Ip6::Address &ip6Address : mIp6Address)
259     {
260         VerifyOrExit(!ip6Address.IsUnspecified());
261 
262         if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
263         {
264             ExitNow(addr = &ip6Address);
265         }
266     }
267 
268 exit:
269     return addr;
270 }
271 #endif
272 
273 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const274 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
275 {
276     bool has = false;
277 
278     VerifyOrExit(mMlrRegisteredMask.HasAny());
279 
280     for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
281     {
282         if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress)
283         {
284             ExitNow(has = true);
285         }
286     }
287 
288 exit:
289     return has;
290 }
291 
GetAddressMlrState(const Ip6::Address & aAddress) const292 MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const
293 {
294     uint16_t addressIndex;
295 
296     OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
297 
298     addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
299 
300     return mMlrToRegisterMask.Get(addressIndex)
301                ? kMlrStateToRegister
302                : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering);
303 }
304 
SetAddressMlrState(const Ip6::Address & aAddress,MlrState aState)305 void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState)
306 {
307     uint16_t addressIndex;
308 
309     OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
310 
311     addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
312 
313     mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister);
314     mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered);
315 }
316 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
317 
318 #endif // OPENTHREAD_FTD
319 
320 } // namespace ot
321