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