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