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 maintaining Thread network topologies.
32 */
33
34 #include "topology.hpp"
35
36 #include "common/code_utils.hpp"
37 #include "common/debug.hpp"
38 #include "common/instance.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/logging.hpp"
41
42 namespace ot {
43
Matches(const Neighbor & aNeighbor) const44 bool Neighbor::AddressMatcher::Matches(const Neighbor &aNeighbor) const
45 {
46 bool matches = false;
47
48 VerifyOrExit(aNeighbor.MatchesFilter(mStateFilter));
49
50 if (mShortAddress != Mac::kShortAddrInvalid)
51 {
52 VerifyOrExit(mShortAddress == aNeighbor.GetRloc16());
53 }
54
55 if (mExtAddress != nullptr)
56 {
57 VerifyOrExit(*mExtAddress == aNeighbor.GetExtAddress());
58 }
59
60 matches = true;
61
62 exit:
63 return matches;
64 }
65
SetFrom(const Neighbor & aNeighbor)66 void Neighbor::Info::SetFrom(const Neighbor &aNeighbor)
67 {
68 Clear();
69
70 mExtAddress = aNeighbor.GetExtAddress();
71 mAge = Time::MsecToSec(TimerMilli::GetNow() - aNeighbor.GetLastHeard());
72 mRloc16 = aNeighbor.GetRloc16();
73 mLinkFrameCounter = aNeighbor.GetLinkFrameCounters().GetMaximum();
74 mMleFrameCounter = aNeighbor.GetMleFrameCounter();
75 mLinkQualityIn = aNeighbor.GetLinkInfo().GetLinkQuality();
76 mAverageRssi = aNeighbor.GetLinkInfo().GetAverageRss();
77 mLastRssi = aNeighbor.GetLinkInfo().GetLastRss();
78 mFrameErrorRate = aNeighbor.GetLinkInfo().GetFrameErrorRate();
79 mMessageErrorRate = aNeighbor.GetLinkInfo().GetMessageErrorRate();
80 mRxOnWhenIdle = aNeighbor.IsRxOnWhenIdle();
81 mFullThreadDevice = aNeighbor.IsFullThreadDevice();
82 mFullNetworkData = aNeighbor.IsFullNetworkData();
83 }
84
Init(Instance & aInstance)85 void Neighbor::Init(Instance &aInstance)
86 {
87 InstanceLocatorInit::Init(aInstance);
88 mLinkInfo.Init(aInstance);
89 SetState(kStateInvalid);
90 }
91
IsStateValidOrAttaching(void) const92 bool Neighbor::IsStateValidOrAttaching(void) const
93 {
94 bool rval = false;
95
96 switch (GetState())
97 {
98 case kStateInvalid:
99 case kStateParentRequest:
100 case kStateParentResponse:
101 break;
102
103 case kStateRestored:
104 case kStateChildIdRequest:
105 case kStateLinkRequest:
106 case kStateChildUpdateRequest:
107 case kStateValid:
108 rval = true;
109 break;
110 }
111
112 return rval;
113 }
114
MatchesFilter(StateFilter aFilter) const115 bool Neighbor::MatchesFilter(StateFilter aFilter) const
116 {
117 bool matches = false;
118
119 switch (aFilter)
120 {
121 case kInStateValid:
122 matches = IsStateValid();
123 break;
124
125 case kInStateValidOrRestoring:
126 matches = IsStateValidOrRestoring();
127 break;
128
129 case kInStateChildIdRequest:
130 matches = IsStateChildIdRequest();
131 break;
132
133 case kInStateValidOrAttaching:
134 matches = IsStateValidOrAttaching();
135 break;
136
137 case kInStateInvalid:
138 matches = IsStateInvalid();
139 break;
140
141 case kInStateAnyExceptInvalid:
142 matches = !IsStateInvalid();
143 break;
144
145 case kInStateAnyExceptValidOrRestoring:
146 matches = !IsStateValidOrRestoring();
147 break;
148
149 case kInStateAny:
150 matches = true;
151 break;
152 }
153
154 return matches;
155 }
156
GenerateChallenge(void)157 void Neighbor::GenerateChallenge(void)
158 {
159 IgnoreError(
160 Random::Crypto::FillBuffer(mValidPending.mPending.mChallenge, sizeof(mValidPending.mPending.mChallenge)));
161 }
162
163 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
AggregateLinkMetrics(uint8_t aSeriesId,uint8_t aFrameType,uint8_t aLqi,int8_t aRss)164 void Neighbor::AggregateLinkMetrics(uint8_t aSeriesId, uint8_t aFrameType, uint8_t aLqi, int8_t aRss)
165 {
166 for (LinkMetrics::SeriesInfo &entry : mLinkMetricsSeriesInfoList)
167 {
168 if (aSeriesId == 0 || aSeriesId == entry.GetSeriesId())
169 {
170 entry.AggregateLinkMetrics(aFrameType, aLqi, aRss);
171 }
172 }
173 }
174
GetForwardTrackingSeriesInfo(const uint8_t & aSeriesId)175 LinkMetrics::SeriesInfo *Neighbor::GetForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
176 {
177 return mLinkMetricsSeriesInfoList.FindMatching(aSeriesId);
178 }
179
AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo & aSeriesInfo)180 void Neighbor::AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo &aSeriesInfo)
181 {
182 mLinkMetricsSeriesInfoList.Push(aSeriesInfo);
183 }
184
RemoveForwardTrackingSeriesInfo(const uint8_t & aSeriesId)185 LinkMetrics::SeriesInfo *Neighbor::RemoveForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
186 {
187 return mLinkMetricsSeriesInfoList.RemoveMatching(aSeriesId);
188 }
189
RemoveAllForwardTrackingSeriesInfo(void)190 void Neighbor::RemoveAllForwardTrackingSeriesInfo(void)
191 {
192 while (!mLinkMetricsSeriesInfoList.IsEmpty())
193 {
194 LinkMetrics::SeriesInfo *seriesInfo = mLinkMetricsSeriesInfoList.Pop();
195 Get<LinkMetrics::LinkMetrics>().mSeriesInfoPool.Free(*seriesInfo);
196 }
197 }
198 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
199
StateToString(State aState)200 const char *Neighbor::StateToString(State aState)
201 {
202 static const char *kStateStrings[] = {
203 "Invalid", // kStateInvalid
204 "Restored", // kStateRestored
205 "ParentReq", // kStateParentRequest
206 "ParentRes", // kStateParentResponse
207 "ChildIdReq", // kStateChildIdRequest
208 "LinkReq", // kStateLinkRequest
209 "ChildUpdateReq", // kStateChildUpdateRequest
210 "Valid", // kStateValid
211 };
212
213 return static_cast<uint8_t>(aState) < OT_ARRAY_LENGTH(kStateStrings) ? kStateStrings[aState] : "Unknown";
214 }
215
216 #if OPENTHREAD_FTD
217
SetFrom(const Child & aChild)218 void Child::Info::SetFrom(const Child &aChild)
219 {
220 Clear();
221 mExtAddress = aChild.GetExtAddress();
222 mTimeout = aChild.GetTimeout();
223 mRloc16 = aChild.GetRloc16();
224 mChildId = Mle::Mle::ChildIdFromRloc16(aChild.GetRloc16());
225 mNetworkDataVersion = aChild.GetNetworkDataVersion();
226 mAge = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
227 mLinkQualityIn = aChild.GetLinkInfo().GetLinkQuality();
228 mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
229 mLastRssi = aChild.GetLinkInfo().GetLastRss();
230 mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
231 mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
232 mQueuedMessageCnt = aChild.GetIndirectMessageCount();
233 mVersion = aChild.GetVersion();
234 mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
235 mFullThreadDevice = aChild.IsFullThreadDevice();
236 mFullNetworkData = aChild.IsFullNetworkData();
237 mIsStateRestoring = aChild.IsStateRestoring();
238 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
239 mIsCslSynced = aChild.IsCslSynchronized();
240 #else
241 mIsCslSynced = false;
242 #endif
243 }
244
GetAddress(void) const245 const Ip6::Address *Child::AddressIterator::GetAddress(void) const
246 {
247 // `mIndex` value of zero indicates mesh-local IPv6 address.
248 // Non-zero value specifies the index into address array starting
249 // from one for first element (i.e, `mIndex - 1` gives the array
250 // index).
251
252 return (mIndex == 0) ? &mMeshLocalAddress : ((mIndex < kMaxIndex) ? &mChild.mIp6Address[mIndex - 1] : nullptr);
253 }
254
Update(void)255 void Child::AddressIterator::Update(void)
256 {
257 const Ip6::Address *address;
258
259 if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone))
260 {
261 mIndex++;
262 }
263
264 while (true)
265 {
266 address = GetAddress();
267
268 VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex);
269
270 VerifyOrExit(!address->MatchesFilter(mFilter));
271 mIndex++;
272 }
273
274 exit:
275 return;
276 }
277
Clear(void)278 void Child::Clear(void)
279 {
280 Instance &instance = GetInstance();
281
282 memset(reinterpret_cast<void *>(this), 0, sizeof(Child));
283 Init(instance);
284 }
285
ClearIp6Addresses(void)286 void Child::ClearIp6Addresses(void)
287 {
288 mMeshLocalIid.Clear();
289 memset(mIp6Address, 0, sizeof(mIp6Address));
290 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
291 mMlrToRegisterMask.Clear();
292 mMlrRegisteredMask.Clear();
293 #endif
294 }
295
SetDeviceMode(Mle::DeviceMode aMode)296 void Child::SetDeviceMode(Mle::DeviceMode aMode)
297 {
298 VerifyOrExit(aMode != GetDeviceMode());
299
300 Neighbor::SetDeviceMode(aMode);
301
302 VerifyOrExit(IsStateValid());
303 Get<NeighborTable>().Signal(NeighborTable::kChildModeChanged, *this);
304
305 exit:
306 return;
307 }
308
GetMeshLocalIp6Address(Ip6::Address & aAddress) const309 Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const
310 {
311 Error error = kErrorNone;
312
313 VerifyOrExit(!mMeshLocalIid.IsUnspecified(), error = kErrorNotFound);
314
315 aAddress.SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
316 aAddress.SetIid(mMeshLocalIid);
317
318 exit:
319 return error;
320 }
321
AddIp6Address(const Ip6::Address & aAddress)322 Error Child::AddIp6Address(const Ip6::Address &aAddress)
323 {
324 Error error = kErrorNone;
325
326 VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
327
328 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
329 {
330 VerifyOrExit(mMeshLocalIid.IsUnspecified(), error = kErrorAlready);
331 mMeshLocalIid = aAddress.GetIid();
332 ExitNow();
333 }
334
335 for (Ip6::Address &ip6Address : mIp6Address)
336 {
337 if (ip6Address.IsUnspecified())
338 {
339 ip6Address = aAddress;
340 ExitNow();
341 }
342
343 VerifyOrExit(ip6Address != aAddress, error = kErrorAlready);
344 }
345
346 error = kErrorNoBufs;
347
348 exit:
349 return error;
350 }
351
RemoveIp6Address(const Ip6::Address & aAddress)352 Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
353 {
354 Error error = kErrorNotFound;
355 uint16_t index;
356
357 VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
358
359 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
360 {
361 if (aAddress.GetIid() == mMeshLocalIid)
362 {
363 mMeshLocalIid.Clear();
364 error = kErrorNone;
365 }
366
367 ExitNow();
368 }
369
370 for (index = 0; index < kNumIp6Addresses; index++)
371 {
372 VerifyOrExit(!mIp6Address[index].IsUnspecified());
373
374 if (mIp6Address[index] == aAddress)
375 {
376 error = kErrorNone;
377 break;
378 }
379 }
380
381 SuccessOrExit(error);
382
383 for (; index < kNumIp6Addresses - 1; index++)
384 {
385 mIp6Address[index] = mIp6Address[index + 1];
386 }
387
388 mIp6Address[kNumIp6Addresses - 1].Clear();
389
390 exit:
391 return error;
392 }
393
HasIp6Address(const Ip6::Address & aAddress) const394 bool Child::HasIp6Address(const Ip6::Address &aAddress) const
395 {
396 bool retval = false;
397
398 VerifyOrExit(!aAddress.IsUnspecified());
399
400 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
401 {
402 retval = (aAddress.GetIid() == mMeshLocalIid);
403 ExitNow();
404 }
405
406 for (const Ip6::Address &ip6Address : mIp6Address)
407 {
408 VerifyOrExit(!ip6Address.IsUnspecified());
409
410 if (ip6Address == aAddress)
411 {
412 ExitNow(retval = true);
413 }
414 }
415
416 exit:
417 return retval;
418 }
419
420 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
GetDomainUnicastAddress(void) const421 const Ip6::Address *Child::GetDomainUnicastAddress(void) const
422 {
423 const Ip6::Address *addr = nullptr;
424
425 for (const Ip6::Address &ip6Address : mIp6Address)
426 {
427 VerifyOrExit(!ip6Address.IsUnspecified());
428
429 if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
430 {
431 ExitNow(addr = &ip6Address);
432 }
433 }
434
435 exit:
436 return addr;
437 }
438 #endif
439
GenerateChallenge(void)440 void Child::GenerateChallenge(void)
441 {
442 IgnoreError(Random::Crypto::FillBuffer(mAttachChallenge, sizeof(mAttachChallenge)));
443 }
444
445 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const446 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
447 {
448 bool has = false;
449
450 VerifyOrExit(mMlrRegisteredMask.HasAny());
451
452 for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
453 {
454 if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress)
455 {
456 ExitNow(has = true);
457 }
458 }
459
460 exit:
461 return has;
462 }
463
GetAddressMlrState(const Ip6::Address & aAddress) const464 MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const
465 {
466 uint16_t addressIndex;
467
468 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < OT_ARRAY_END(mIp6Address));
469
470 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
471
472 return mMlrToRegisterMask.Get(addressIndex)
473 ? kMlrStateToRegister
474 : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering);
475 }
476
SetAddressMlrState(const Ip6::Address & aAddress,MlrState aState)477 void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState)
478 {
479 uint16_t addressIndex;
480
481 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < OT_ARRAY_END(mIp6Address));
482
483 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
484
485 mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister);
486 mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered);
487 }
488 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
489
490 #endif // OPENTHREAD_FTD
491
SetFrom(const Router & aRouter)492 void Router::Info::SetFrom(const Router &aRouter)
493 {
494 Clear();
495 mRloc16 = aRouter.GetRloc16();
496 mRouterId = Mle::Mle::RouterIdFromRloc16(mRloc16);
497 mExtAddress = aRouter.GetExtAddress();
498 mAllocated = true;
499 mNextHop = aRouter.GetNextHop();
500 mLinkEstablished = aRouter.IsStateValid();
501 mPathCost = aRouter.GetCost();
502 mLinkQualityIn = aRouter.GetLinkInfo().GetLinkQuality();
503 mLinkQualityOut = aRouter.GetLinkQualityOut();
504 mAge = static_cast<uint8_t>(Time::MsecToSec(TimerMilli::GetNow() - aRouter.GetLastHeard()));
505 }
506
Clear(void)507 void Router::Clear(void)
508 {
509 Instance &instance = GetInstance();
510
511 memset(reinterpret_cast<void *>(this), 0, sizeof(Router));
512 Init(instance);
513 }
514
515 } // namespace ot
516