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/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
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.GetNetworkDataType() == NetworkData::kFullSet);
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
157 #if OPENTHREAD_CONFIG_MULTI_RADIO
SetLastRxFragmentTag(uint16_t aTag)158 void Neighbor::SetLastRxFragmentTag(uint16_t aTag)
159 {
160 mLastRxFragmentTag = (aTag == 0) ? 0xffff : aTag;
161 mLastRxFragmentTagTime = TimerMilli::GetNow();
162 }
163
IsLastRxFragmentTagSet(void) const164 bool Neighbor::IsLastRxFragmentTagSet(void) const
165 {
166 return (mLastRxFragmentTag != 0) && (TimerMilli::GetNow() <= mLastRxFragmentTagTime + kLastRxFragmentTagTimeout);
167 }
168 #endif
169
GenerateChallenge(void)170 void Neighbor::GenerateChallenge(void)
171 {
172 IgnoreError(
173 Random::Crypto::FillBuffer(mValidPending.mPending.mChallenge, sizeof(mValidPending.mPending.mChallenge)));
174 }
175
176 #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)177 void Neighbor::AggregateLinkMetrics(uint8_t aSeriesId, uint8_t aFrameType, uint8_t aLqi, int8_t aRss)
178 {
179 for (LinkMetrics::SeriesInfo &entry : mLinkMetricsSeriesInfoList)
180 {
181 if (aSeriesId == 0 || aSeriesId == entry.GetSeriesId())
182 {
183 entry.AggregateLinkMetrics(aFrameType, aLqi, aRss);
184 }
185 }
186 }
187
GetForwardTrackingSeriesInfo(const uint8_t & aSeriesId)188 LinkMetrics::SeriesInfo *Neighbor::GetForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
189 {
190 return mLinkMetricsSeriesInfoList.FindMatching(aSeriesId);
191 }
192
AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo & aSeriesInfo)193 void Neighbor::AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo &aSeriesInfo)
194 {
195 mLinkMetricsSeriesInfoList.Push(aSeriesInfo);
196 }
197
RemoveForwardTrackingSeriesInfo(const uint8_t & aSeriesId)198 LinkMetrics::SeriesInfo *Neighbor::RemoveForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
199 {
200 return mLinkMetricsSeriesInfoList.RemoveMatching(aSeriesId);
201 }
202
RemoveAllForwardTrackingSeriesInfo(void)203 void Neighbor::RemoveAllForwardTrackingSeriesInfo(void)
204 {
205 while (!mLinkMetricsSeriesInfoList.IsEmpty())
206 {
207 LinkMetrics::SeriesInfo *seriesInfo = mLinkMetricsSeriesInfoList.Pop();
208 Get<LinkMetrics::LinkMetrics>().mSeriesInfoPool.Free(*seriesInfo);
209 }
210 }
211 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
212
StateToString(State aState)213 const char *Neighbor::StateToString(State aState)
214 {
215 static const char *const kStateStrings[] = {
216 "Invalid", // (0) kStateInvalid
217 "Restored", // (1) kStateRestored
218 "ParentReq", // (2) kStateParentRequest
219 "ParentRes", // (3) kStateParentResponse
220 "ChildIdReq", // (4) kStateChildIdRequest
221 "LinkReq", // (5) kStateLinkRequest
222 "ChildUpdateReq", // (6) kStateChildUpdateRequest
223 "Valid", // (7) kStateValid
224 };
225
226 static_assert(0 == kStateInvalid, "kStateInvalid value is incorrect");
227 static_assert(1 == kStateRestored, "kStateRestored value is incorrect");
228 static_assert(2 == kStateParentRequest, "kStateParentRequest value is incorrect");
229 static_assert(3 == kStateParentResponse, "kStateParentResponse value is incorrect");
230 static_assert(4 == kStateChildIdRequest, "kStateChildIdRequest value is incorrect");
231 static_assert(5 == kStateLinkRequest, "kStateLinkRequest value is incorrect");
232 static_assert(6 == kStateChildUpdateRequest, "kStateChildUpdateRequest value is incorrect");
233 static_assert(7 == kStateValid, "kStateValid value is incorrect");
234
235 return kStateStrings[aState];
236 }
237
238 #if OPENTHREAD_FTD
239
SetFrom(const Child & aChild)240 void Child::Info::SetFrom(const Child &aChild)
241 {
242 Clear();
243 mExtAddress = aChild.GetExtAddress();
244 mTimeout = aChild.GetTimeout();
245 mRloc16 = aChild.GetRloc16();
246 mChildId = Mle::Mle::ChildIdFromRloc16(aChild.GetRloc16());
247 mNetworkDataVersion = aChild.GetNetworkDataVersion();
248 mAge = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
249 mLinkQualityIn = aChild.GetLinkInfo().GetLinkQuality();
250 mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
251 mLastRssi = aChild.GetLinkInfo().GetLastRss();
252 mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
253 mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
254 mQueuedMessageCnt = aChild.GetIndirectMessageCount();
255 mVersion = aChild.GetVersion();
256 mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
257 mFullThreadDevice = aChild.IsFullThreadDevice();
258 mFullNetworkData = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
259 mIsStateRestoring = aChild.IsStateRestoring();
260 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
261 mIsCslSynced = aChild.IsCslSynchronized();
262 #else
263 mIsCslSynced = false;
264 #endif
265 }
266
GetAddress(void) const267 const Ip6::Address *Child::AddressIterator::GetAddress(void) const
268 {
269 // `mIndex` value of zero indicates mesh-local IPv6 address.
270 // Non-zero value specifies the index into address array starting
271 // from one for first element (i.e, `mIndex - 1` gives the array
272 // index).
273
274 return (mIndex == 0) ? &mMeshLocalAddress : ((mIndex < kMaxIndex) ? &mChild.mIp6Address[mIndex - 1] : nullptr);
275 }
276
Update(void)277 void Child::AddressIterator::Update(void)
278 {
279 const Ip6::Address *address;
280
281 if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone))
282 {
283 mIndex++;
284 }
285
286 while (true)
287 {
288 address = GetAddress();
289
290 VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex);
291
292 VerifyOrExit(!address->MatchesFilter(mFilter));
293 mIndex++;
294 }
295
296 exit:
297 return;
298 }
299
Clear(void)300 void Child::Clear(void)
301 {
302 Instance &instance = GetInstance();
303
304 memset(reinterpret_cast<void *>(this), 0, sizeof(Child));
305 Init(instance);
306 }
307
ClearIp6Addresses(void)308 void Child::ClearIp6Addresses(void)
309 {
310 mMeshLocalIid.Clear();
311 memset(mIp6Address, 0, sizeof(mIp6Address));
312 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
313 mMlrToRegisterMask.Clear();
314 mMlrRegisteredMask.Clear();
315 #endif
316 }
317
SetDeviceMode(Mle::DeviceMode aMode)318 void Child::SetDeviceMode(Mle::DeviceMode aMode)
319 {
320 VerifyOrExit(aMode != GetDeviceMode());
321
322 Neighbor::SetDeviceMode(aMode);
323
324 VerifyOrExit(IsStateValid());
325 Get<NeighborTable>().Signal(NeighborTable::kChildModeChanged, *this);
326
327 exit:
328 return;
329 }
330
GetMeshLocalIp6Address(Ip6::Address & aAddress) const331 Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const
332 {
333 Error error = kErrorNone;
334
335 VerifyOrExit(!mMeshLocalIid.IsUnspecified(), error = kErrorNotFound);
336
337 aAddress.SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
338 aAddress.SetIid(mMeshLocalIid);
339
340 exit:
341 return error;
342 }
343
AddIp6Address(const Ip6::Address & aAddress)344 Error Child::AddIp6Address(const Ip6::Address &aAddress)
345 {
346 Error error = kErrorNone;
347
348 VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
349
350 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
351 {
352 VerifyOrExit(mMeshLocalIid.IsUnspecified(), error = kErrorAlready);
353 mMeshLocalIid = aAddress.GetIid();
354 ExitNow();
355 }
356
357 for (Ip6::Address &ip6Address : mIp6Address)
358 {
359 if (ip6Address.IsUnspecified())
360 {
361 ip6Address = aAddress;
362 ExitNow();
363 }
364
365 VerifyOrExit(ip6Address != aAddress, error = kErrorAlready);
366 }
367
368 error = kErrorNoBufs;
369
370 exit:
371 return error;
372 }
373
RemoveIp6Address(const Ip6::Address & aAddress)374 Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
375 {
376 Error error = kErrorNotFound;
377 uint16_t index;
378
379 VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
380
381 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
382 {
383 if (aAddress.GetIid() == mMeshLocalIid)
384 {
385 mMeshLocalIid.Clear();
386 error = kErrorNone;
387 }
388
389 ExitNow();
390 }
391
392 for (index = 0; index < kNumIp6Addresses; index++)
393 {
394 VerifyOrExit(!mIp6Address[index].IsUnspecified());
395
396 if (mIp6Address[index] == aAddress)
397 {
398 error = kErrorNone;
399 break;
400 }
401 }
402
403 SuccessOrExit(error);
404
405 for (; index < kNumIp6Addresses - 1; index++)
406 {
407 mIp6Address[index] = mIp6Address[index + 1];
408 }
409
410 mIp6Address[kNumIp6Addresses - 1].Clear();
411
412 exit:
413 return error;
414 }
415
HasIp6Address(const Ip6::Address & aAddress) const416 bool Child::HasIp6Address(const Ip6::Address &aAddress) const
417 {
418 bool retval = false;
419
420 VerifyOrExit(!aAddress.IsUnspecified());
421
422 if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
423 {
424 retval = (aAddress.GetIid() == mMeshLocalIid);
425 ExitNow();
426 }
427
428 for (const Ip6::Address &ip6Address : mIp6Address)
429 {
430 VerifyOrExit(!ip6Address.IsUnspecified());
431
432 if (ip6Address == aAddress)
433 {
434 ExitNow(retval = true);
435 }
436 }
437
438 exit:
439 return retval;
440 }
441
442 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
GetDomainUnicastAddress(void) const443 const Ip6::Address *Child::GetDomainUnicastAddress(void) const
444 {
445 const Ip6::Address *addr = nullptr;
446
447 for (const Ip6::Address &ip6Address : mIp6Address)
448 {
449 VerifyOrExit(!ip6Address.IsUnspecified());
450
451 if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
452 {
453 ExitNow(addr = &ip6Address);
454 }
455 }
456
457 exit:
458 return addr;
459 }
460 #endif
461
GenerateChallenge(void)462 void Child::GenerateChallenge(void)
463 {
464 IgnoreError(Random::Crypto::FillBuffer(mAttachChallenge, sizeof(mAttachChallenge)));
465 }
466
467 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const468 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
469 {
470 bool has = false;
471
472 VerifyOrExit(mMlrRegisteredMask.HasAny());
473
474 for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
475 {
476 if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress)
477 {
478 ExitNow(has = true);
479 }
480 }
481
482 exit:
483 return has;
484 }
485
GetAddressMlrState(const Ip6::Address & aAddress) const486 MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const
487 {
488 uint16_t addressIndex;
489
490 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
491
492 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
493
494 return mMlrToRegisterMask.Get(addressIndex)
495 ? kMlrStateToRegister
496 : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering);
497 }
498
SetAddressMlrState(const Ip6::Address & aAddress,MlrState aState)499 void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState)
500 {
501 uint16_t addressIndex;
502
503 OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
504
505 addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
506
507 mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister);
508 mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered);
509 }
510 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
511
512 #endif // OPENTHREAD_FTD
513
SetFrom(const Router & aRouter)514 void Router::Info::SetFrom(const Router &aRouter)
515 {
516 Clear();
517 mRloc16 = aRouter.GetRloc16();
518 mRouterId = Mle::Mle::RouterIdFromRloc16(mRloc16);
519 mExtAddress = aRouter.GetExtAddress();
520 mAllocated = true;
521 mNextHop = aRouter.GetNextHop();
522 mLinkEstablished = aRouter.IsStateValid();
523 mPathCost = aRouter.GetCost();
524 mLinkQualityIn = aRouter.GetLinkInfo().GetLinkQuality();
525 mLinkQualityOut = aRouter.GetLinkQualityOut();
526 mAge = static_cast<uint8_t>(Time::MsecToSec(TimerMilli::GetNow() - aRouter.GetLastHeard()));
527 }
528
Clear(void)529 void Router::Clear(void)
530 {
531 Instance &instance = GetInstance();
532
533 memset(reinterpret_cast<void *>(this), 0, sizeof(Router));
534 Init(instance);
535 }
536
537 } // namespace ot
538