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/locator_getters.hpp"
40 #include "common/num_utils.hpp"
41 #include "instance/instance.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 ClearAllBytes(*this);
116 Init(instance);
117 }
118
ClearIp6Addresses(void)119 void Child::ClearIp6Addresses(void)
120 {
121 mMeshLocalIid.Clear();
122 ClearAllBytes(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(Ip6::Address & aAddress) const254 Error Child::GetDomainUnicastAddress(Ip6::Address &aAddress) const
255 {
256 Error error = kErrorNotFound;
257
258 for (const Ip6::Address &ip6Address : mIp6Address)
259 {
260 VerifyOrExit(!ip6Address.IsUnspecified());
261
262 if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
263 {
264 aAddress = ip6Address;
265 error = kErrorNone;
266 ExitNow();
267 }
268 }
269
270 exit:
271 return error;
272 }
273 #endif
274
275 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const276 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
277 {
278 bool has = false;
279
280 VerifyOrExit(mMlrRegisteredMask.HasAny());
281
282 for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
283 {
284 if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress)
285 {
286 ExitNow(has = true);
287 }
288 }
289
290 exit:
291 return has;
292 }
293
GetAddressMlrState(const Ip6::Address & aAddress) const294 MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const
295 {
296 uint16_t addressIndex;
297
298 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
299
300 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
301
302 return mMlrToRegisterMask.Get(addressIndex)
303 ? kMlrStateToRegister
304 : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering);
305 }
306
SetAddressMlrState(const Ip6::Address & aAddress,MlrState aState)307 void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState)
308 {
309 uint16_t addressIndex;
310
311 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
312
313 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
314
315 mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister);
316 mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered);
317 }
318 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
319
320 #endif // OPENTHREAD_FTD
321
322 } // namespace ot
323