• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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