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
47 //---------------------------------------------------------------------------------------------------------------------
48 // Child::Info
49
SetFrom(const Child & aChild)50 void Child::Info::SetFrom(const Child &aChild)
51 {
52 Clear();
53 mExtAddress = aChild.GetExtAddress();
54 mTimeout = aChild.GetTimeout();
55 mRloc16 = aChild.GetRloc16();
56 mChildId = Mle::ChildIdFromRloc16(aChild.GetRloc16());
57 mNetworkDataVersion = aChild.GetNetworkDataVersion();
58 mAge = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
59 mLinkQualityIn = aChild.GetLinkQualityIn();
60 mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
61 mLastRssi = aChild.GetLinkInfo().GetLastRss();
62 mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
63 mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
64 mQueuedMessageCnt = aChild.GetIndirectMessageCount();
65 mVersion = ClampToUint8(aChild.GetVersion());
66 mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
67 mFullThreadDevice = aChild.IsFullThreadDevice();
68 mFullNetworkData = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
69 mIsStateRestoring = aChild.IsStateRestoring();
70 mSupervisionInterval = aChild.GetSupervisionInterval();
71 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
72 mIsCslSynced = aChild.IsCslSynchronized();
73 #else
74 mIsCslSynced = false;
75 #endif
76 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
77 mConnectionTime = aChild.GetConnectionTime();
78 #endif
79 }
80
81 //---------------------------------------------------------------------------------------------------------------------
82 // Child::Ip6AddrEntry
83
84 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
85
GetMlrState(const Child & aChild) const86 MlrState Child::Ip6AddrEntry::GetMlrState(const Child &aChild) const
87 {
88 MlrState state = kMlrStateRegistering;
89 Ip6AddressArray::IndexType index;
90
91 OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this));
92
93 index = aChild.mIp6Addresses.IndexOf(*this);
94
95 if (aChild.mMlrToRegisterMask.Get(index))
96 {
97 state = kMlrStateToRegister;
98 }
99 else if (aChild.mMlrRegisteredMask.Get(index))
100 {
101 state = kMlrStateRegistered;
102 }
103
104 return state;
105 }
106
107 // NOLINTNEXTLINE(readability-make-member-function-const)
SetMlrState(MlrState aState,Child & aChild)108 void Child::Ip6AddrEntry::SetMlrState(MlrState aState, Child &aChild)
109 {
110 Ip6AddressArray::IndexType index;
111
112 OT_ASSERT(aChild.mIp6Addresses.IsInArrayBuffer(this));
113
114 index = aChild.mIp6Addresses.IndexOf(*this);
115
116 aChild.mMlrToRegisterMask.Set(index, aState == kMlrStateToRegister);
117 aChild.mMlrRegisteredMask.Set(index, aState == kMlrStateRegistered);
118 }
119
120 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
121
122 //---------------------------------------------------------------------------------------------------------------------
123 // Child
124
Clear(void)125 void Child::Clear(void)
126 {
127 Instance &instance = GetInstance();
128
129 ClearAllBytes(*this);
130 Init(instance);
131 }
132
ClearIp6Addresses(void)133 void Child::ClearIp6Addresses(void)
134 {
135 mMeshLocalIid.Clear();
136 mIp6Addresses.Clear();
137 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
138 mMlrToRegisterMask.Clear();
139 mMlrRegisteredMask.Clear();
140 #endif
141 }
142
SetDeviceMode(Mle::DeviceMode aMode)143 void Child::SetDeviceMode(Mle::DeviceMode aMode)
144 {
145 VerifyOrExit(aMode != GetDeviceMode());
146
147 Neighbor::SetDeviceMode(aMode);
148
149 VerifyOrExit(IsStateValid());
150 Get<NeighborTable>().Signal(NeighborTable::kChildModeChanged, *this);
151
152 exit:
153 return;
154 }
155
GetMeshLocalIp6Address(Ip6::Address & aAddress) const156 Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const
157 {
158 Error error = kErrorNone;
159
160 VerifyOrExit(!mMeshLocalIid.IsUnspecified(), error = kErrorNotFound);
161
162 aAddress.SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
163 aAddress.SetIid(mMeshLocalIid);
164
165 exit:
166 return error;
167 }
168
GetNextIp6Address(AddressIterator & aIterator,Ip6::Address & aAddress) const169 Error Child::GetNextIp6Address(AddressIterator &aIterator, Ip6::Address &aAddress) const
170 {
171 Error error = kErrorNone;
172
173 if (aIterator == 0)
174 {
175 aIterator++;
176
177 if (GetMeshLocalIp6Address(aAddress) == kErrorNone)
178 {
179 ExitNow();
180 }
181 }
182
183 VerifyOrExit(aIterator - 1 < mIp6Addresses.GetLength(), error = kErrorNotFound);
184
185 aAddress = mIp6Addresses[static_cast<Ip6AddressArray::IndexType>(aIterator - 1)];
186 aIterator++;
187
188 exit:
189 return error;
190 }
191
AddIp6Address(const Ip6::Address & aAddress)192 Error Child::AddIp6Address(const Ip6::Address &aAddress)
193 {
194 Error error = kErrorNone;
195
196 VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
197
198 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
199 {
200 VerifyOrExit(mMeshLocalIid.IsUnspecified(), error = kErrorAlready);
201 mMeshLocalIid = aAddress.GetIid();
202 ExitNow();
203 }
204
205 VerifyOrExit(!mIp6Addresses.ContainsMatching(aAddress), error = kErrorAlready);
206 error = mIp6Addresses.PushBack(static_cast<const Ip6AddrEntry &>(aAddress));
207
208 exit:
209 return error;
210 }
211
RemoveIp6Address(const Ip6::Address & aAddress)212 Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
213 {
214 Error error = kErrorNotFound;
215 Ip6AddrEntry *entry;
216
217 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
218 {
219 if (aAddress.GetIid() == mMeshLocalIid)
220 {
221 mMeshLocalIid.Clear();
222 error = kErrorNone;
223 }
224
225 ExitNow();
226 }
227
228 entry = mIp6Addresses.FindMatching(aAddress);
229 VerifyOrExit(entry != nullptr);
230
231 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
232 {
233 // `Array::Remove()` will replace the removed entry with the
234 // last one in the array. We also update the MLR bit vectors
235 // to reflect this change.
236
237 uint16_t entryIndex = mIp6Addresses.IndexOf(*entry);
238 uint16_t lastIndex = mIp6Addresses.GetLength() - 1;
239
240 mMlrToRegisterMask.Set(entryIndex, mMlrToRegisterMask.Get(lastIndex));
241 mMlrToRegisterMask.Set(lastIndex, false);
242
243 mMlrRegisteredMask.Set(entryIndex, mMlrRegisteredMask.Get(lastIndex));
244 mMlrRegisteredMask.Set(lastIndex, false);
245 }
246 #endif
247
248 mIp6Addresses.Remove(*entry);
249 error = kErrorNone;
250
251 exit:
252 return error;
253 }
254
HasIp6Address(const Ip6::Address & aAddress) const255 bool Child::HasIp6Address(const Ip6::Address &aAddress) const
256 {
257 bool hasAddress = false;
258
259 VerifyOrExit(!aAddress.IsUnspecified());
260
261 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
262 {
263 hasAddress = (aAddress.GetIid() == mMeshLocalIid);
264 ExitNow();
265 }
266
267 hasAddress = mIp6Addresses.ContainsMatching(aAddress);
268
269 exit:
270 return hasAddress;
271 }
272
273 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
GetDomainUnicastAddress(Ip6::Address & aAddress) const274 Error Child::GetDomainUnicastAddress(Ip6::Address &aAddress) const
275 {
276 Error error = kErrorNotFound;
277
278 for (const Ip6::Address &ip6Address : mIp6Addresses)
279 {
280 if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
281 {
282 aAddress = ip6Address;
283 error = kErrorNone;
284 ExitNow();
285 }
286 }
287
288 exit:
289 return error;
290 }
291 #endif
292
293 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
294
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const295 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
296 {
297 bool hasAddress = false;
298 const Ip6AddrEntry *entry;
299
300 entry = mIp6Addresses.FindMatching(aAddress);
301 VerifyOrExit(entry != nullptr);
302 hasAddress = entry->GetMlrState(*this) == kMlrStateRegistered;
303
304 exit:
305 return hasAddress;
306 }
307
308 #endif
309
310 #endif // OPENTHREAD_FTD
311
312 } // namespace ot
313