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