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 #include "common/num_utils.hpp"
42 
43 namespace ot {
44 
SetState(State aState)45 void Neighbor::SetState(State aState)
46 {
47     VerifyOrExit(mState != aState);
48     mState = static_cast<uint8_t>(aState);
49 
50 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
51     if (mState == kStateValid)
52     {
53         mConnectionStart = Uptime::MsecToSec(Get<Uptime>().GetUptime());
54     }
55 #endif
56 
57 exit:
58     return;
59 }
60 
61 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
GetConnectionTime(void) const62 uint32_t Neighbor::GetConnectionTime(void) const
63 {
64     return IsStateValid() ? Uptime::MsecToSec(Get<Uptime>().GetUptime()) - mConnectionStart : 0;
65 }
66 #endif
67 
Matches(const Neighbor & aNeighbor) const68 bool Neighbor::AddressMatcher::Matches(const Neighbor &aNeighbor) const
69 {
70     bool matches = false;
71 
72     VerifyOrExit(aNeighbor.MatchesFilter(mStateFilter));
73 
74     if (mShortAddress != Mac::kShortAddrInvalid)
75     {
76         VerifyOrExit(mShortAddress == aNeighbor.GetRloc16());
77     }
78 
79     if (mExtAddress != nullptr)
80     {
81         VerifyOrExit(*mExtAddress == aNeighbor.GetExtAddress());
82     }
83 
84     matches = true;
85 
86 exit:
87     return matches;
88 }
89 
SetFrom(const Neighbor & aNeighbor)90 void Neighbor::Info::SetFrom(const Neighbor &aNeighbor)
91 {
92     Clear();
93 
94     mExtAddress       = aNeighbor.GetExtAddress();
95     mAge              = Time::MsecToSec(TimerMilli::GetNow() - aNeighbor.GetLastHeard());
96     mRloc16           = aNeighbor.GetRloc16();
97     mLinkFrameCounter = aNeighbor.GetLinkFrameCounters().GetMaximum();
98     mMleFrameCounter  = aNeighbor.GetMleFrameCounter();
99     mLinkQualityIn    = aNeighbor.GetLinkQualityIn();
100     mAverageRssi      = aNeighbor.GetLinkInfo().GetAverageRss();
101     mLastRssi         = aNeighbor.GetLinkInfo().GetLastRss();
102     mLinkMargin       = aNeighbor.GetLinkInfo().GetLinkMargin();
103     mFrameErrorRate   = aNeighbor.GetLinkInfo().GetFrameErrorRate();
104     mMessageErrorRate = aNeighbor.GetLinkInfo().GetMessageErrorRate();
105     mRxOnWhenIdle     = aNeighbor.IsRxOnWhenIdle();
106     mFullThreadDevice = aNeighbor.IsFullThreadDevice();
107     mFullNetworkData  = (aNeighbor.GetNetworkDataType() == NetworkData::kFullSet);
108     mVersion          = aNeighbor.GetVersion();
109 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
110     mConnectionTime = aNeighbor.GetConnectionTime();
111 #endif
112 }
113 
Init(Instance & aInstance)114 void Neighbor::Init(Instance &aInstance)
115 {
116     InstanceLocatorInit::Init(aInstance);
117     mLinkInfo.Init(aInstance);
118     SetState(kStateInvalid);
119 }
120 
IsStateValidOrAttaching(void) const121 bool Neighbor::IsStateValidOrAttaching(void) const
122 {
123     bool rval = false;
124 
125     switch (GetState())
126     {
127     case kStateInvalid:
128     case kStateParentRequest:
129     case kStateParentResponse:
130         break;
131 
132     case kStateRestored:
133     case kStateChildIdRequest:
134     case kStateLinkRequest:
135     case kStateChildUpdateRequest:
136     case kStateValid:
137         rval = true;
138         break;
139     }
140 
141     return rval;
142 }
143 
MatchesFilter(StateFilter aFilter) const144 bool Neighbor::MatchesFilter(StateFilter aFilter) const
145 {
146     bool matches = false;
147 
148     switch (aFilter)
149     {
150     case kInStateValid:
151         matches = IsStateValid();
152         break;
153 
154     case kInStateValidOrRestoring:
155         matches = IsStateValidOrRestoring();
156         break;
157 
158     case kInStateChildIdRequest:
159         matches = IsStateChildIdRequest();
160         break;
161 
162     case kInStateValidOrAttaching:
163         matches = IsStateValidOrAttaching();
164         break;
165 
166     case kInStateInvalid:
167         matches = IsStateInvalid();
168         break;
169 
170     case kInStateAnyExceptInvalid:
171         matches = !IsStateInvalid();
172         break;
173 
174     case kInStateAnyExceptValidOrRestoring:
175         matches = !IsStateValidOrRestoring();
176         break;
177 
178     case kInStateAny:
179         matches = true;
180         break;
181     }
182 
183     return matches;
184 }
185 
186 #if OPENTHREAD_CONFIG_MULTI_RADIO
SetLastRxFragmentTag(uint16_t aTag)187 void Neighbor::SetLastRxFragmentTag(uint16_t aTag)
188 {
189     mLastRxFragmentTag     = (aTag == 0) ? 0xffff : aTag;
190     mLastRxFragmentTagTime = TimerMilli::GetNow();
191 }
192 
IsLastRxFragmentTagSet(void) const193 bool Neighbor::IsLastRxFragmentTagSet(void) const
194 {
195     return (mLastRxFragmentTag != 0) && (TimerMilli::GetNow() <= mLastRxFragmentTagTime + kLastRxFragmentTagTimeout);
196 }
197 #endif
198 
GenerateChallenge(void)199 void Neighbor::GenerateChallenge(void)
200 {
201     IgnoreError(
202         Random::Crypto::FillBuffer(mValidPending.mPending.mChallenge, sizeof(mValidPending.mPending.mChallenge)));
203 }
204 
205 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
AggregateLinkMetrics(uint8_t aSeriesId,uint8_t aFrameType,uint8_t aLqi,int8_t aRss)206 void Neighbor::AggregateLinkMetrics(uint8_t aSeriesId, uint8_t aFrameType, uint8_t aLqi, int8_t aRss)
207 {
208     for (LinkMetrics::SeriesInfo &entry : mLinkMetricsSeriesInfoList)
209     {
210         if (aSeriesId == 0 || aSeriesId == entry.GetSeriesId())
211         {
212             entry.AggregateLinkMetrics(aFrameType, aLqi, aRss);
213         }
214     }
215 }
216 
GetForwardTrackingSeriesInfo(const uint8_t & aSeriesId)217 LinkMetrics::SeriesInfo *Neighbor::GetForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
218 {
219     return mLinkMetricsSeriesInfoList.FindMatching(aSeriesId);
220 }
221 
AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo & aSeriesInfo)222 void Neighbor::AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo &aSeriesInfo)
223 {
224     mLinkMetricsSeriesInfoList.Push(aSeriesInfo);
225 }
226 
RemoveForwardTrackingSeriesInfo(const uint8_t & aSeriesId)227 LinkMetrics::SeriesInfo *Neighbor::RemoveForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
228 {
229     return mLinkMetricsSeriesInfoList.RemoveMatching(aSeriesId);
230 }
231 
RemoveAllForwardTrackingSeriesInfo(void)232 void Neighbor::RemoveAllForwardTrackingSeriesInfo(void)
233 {
234     while (!mLinkMetricsSeriesInfoList.IsEmpty())
235     {
236         LinkMetrics::SeriesInfo *seriesInfo = mLinkMetricsSeriesInfoList.Pop();
237         Get<LinkMetrics::Subject>().Free(*seriesInfo);
238     }
239 }
240 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
241 
StateToString(State aState)242 const char *Neighbor::StateToString(State aState)
243 {
244     static const char *const kStateStrings[] = {
245         "Invalid",        // (0) kStateInvalid
246         "Restored",       // (1) kStateRestored
247         "ParentReq",      // (2) kStateParentRequest
248         "ParentRes",      // (3) kStateParentResponse
249         "ChildIdReq",     // (4) kStateChildIdRequest
250         "LinkReq",        // (5) kStateLinkRequest
251         "ChildUpdateReq", // (6) kStateChildUpdateRequest
252         "Valid",          // (7) kStateValid
253     };
254 
255     static_assert(0 == kStateInvalid, "kStateInvalid value is incorrect");
256     static_assert(1 == kStateRestored, "kStateRestored value is incorrect");
257     static_assert(2 == kStateParentRequest, "kStateParentRequest value is incorrect");
258     static_assert(3 == kStateParentResponse, "kStateParentResponse value is incorrect");
259     static_assert(4 == kStateChildIdRequest, "kStateChildIdRequest value is incorrect");
260     static_assert(5 == kStateLinkRequest, "kStateLinkRequest value is incorrect");
261     static_assert(6 == kStateChildUpdateRequest, "kStateChildUpdateRequest value is incorrect");
262     static_assert(7 == kStateValid, "kStateValid value is incorrect");
263 
264     return kStateStrings[aState];
265 }
266 
267 #if OPENTHREAD_FTD
268 
SetFrom(const Child & aChild)269 void Child::Info::SetFrom(const Child &aChild)
270 {
271     Clear();
272     mExtAddress          = aChild.GetExtAddress();
273     mTimeout             = aChild.GetTimeout();
274     mRloc16              = aChild.GetRloc16();
275     mChildId             = Mle::ChildIdFromRloc16(aChild.GetRloc16());
276     mNetworkDataVersion  = aChild.GetNetworkDataVersion();
277     mAge                 = Time::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
278     mLinkQualityIn       = aChild.GetLinkQualityIn();
279     mAverageRssi         = aChild.GetLinkInfo().GetAverageRss();
280     mLastRssi            = aChild.GetLinkInfo().GetLastRss();
281     mFrameErrorRate      = aChild.GetLinkInfo().GetFrameErrorRate();
282     mMessageErrorRate    = aChild.GetLinkInfo().GetMessageErrorRate();
283     mQueuedMessageCnt    = aChild.GetIndirectMessageCount();
284     mVersion             = ClampToUint8(aChild.GetVersion());
285     mRxOnWhenIdle        = aChild.IsRxOnWhenIdle();
286     mFullThreadDevice    = aChild.IsFullThreadDevice();
287     mFullNetworkData     = (aChild.GetNetworkDataType() == NetworkData::kFullSet);
288     mIsStateRestoring    = aChild.IsStateRestoring();
289     mSupervisionInterval = aChild.GetSupervisionInterval();
290 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
291     mIsCslSynced = aChild.IsCslSynchronized();
292 #else
293     mIsCslSynced = false;
294 #endif
295 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
296     mConnectionTime = aChild.GetConnectionTime();
297 #endif
298 }
299 
GetAddress(void) const300 const Ip6::Address *Child::AddressIterator::GetAddress(void) const
301 {
302     // `mIndex` value of zero indicates mesh-local IPv6 address.
303     // Non-zero value specifies the index into address array starting
304     // from one for first element (i.e, `mIndex - 1` gives the array
305     // index).
306 
307     return (mIndex == 0) ? &mMeshLocalAddress : ((mIndex < kMaxIndex) ? &mChild.mIp6Address[mIndex - 1] : nullptr);
308 }
309 
Update(void)310 void Child::AddressIterator::Update(void)
311 {
312     const Ip6::Address *address;
313 
314     if ((mIndex == 0) && (mChild.GetMeshLocalIp6Address(mMeshLocalAddress) != kErrorNone))
315     {
316         mIndex++;
317     }
318 
319     while (true)
320     {
321         address = GetAddress();
322 
323         VerifyOrExit((address != nullptr) && !address->IsUnspecified(), mIndex = kMaxIndex);
324 
325         VerifyOrExit(!address->MatchesFilter(mFilter));
326         mIndex++;
327     }
328 
329 exit:
330     return;
331 }
332 
Clear(void)333 void Child::Clear(void)
334 {
335     Instance &instance = GetInstance();
336 
337     memset(reinterpret_cast<void *>(this), 0, sizeof(Child));
338     Init(instance);
339 }
340 
ClearIp6Addresses(void)341 void Child::ClearIp6Addresses(void)
342 {
343     mMeshLocalIid.Clear();
344     memset(mIp6Address, 0, sizeof(mIp6Address));
345 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
346     mMlrToRegisterMask.Clear();
347     mMlrRegisteredMask.Clear();
348 #endif
349 }
350 
SetDeviceMode(Mle::DeviceMode aMode)351 void Child::SetDeviceMode(Mle::DeviceMode aMode)
352 {
353     VerifyOrExit(aMode != GetDeviceMode());
354 
355     Neighbor::SetDeviceMode(aMode);
356 
357     VerifyOrExit(IsStateValid());
358     Get<NeighborTable>().Signal(NeighborTable::kChildModeChanged, *this);
359 
360 exit:
361     return;
362 }
363 
GetMeshLocalIp6Address(Ip6::Address & aAddress) const364 Error Child::GetMeshLocalIp6Address(Ip6::Address &aAddress) const
365 {
366     Error error = kErrorNone;
367 
368     VerifyOrExit(!mMeshLocalIid.IsUnspecified(), error = kErrorNotFound);
369 
370     aAddress.SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
371     aAddress.SetIid(mMeshLocalIid);
372 
373 exit:
374     return error;
375 }
376 
AddIp6Address(const Ip6::Address & aAddress)377 Error Child::AddIp6Address(const Ip6::Address &aAddress)
378 {
379     Error error = kErrorNone;
380 
381     VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
382 
383     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
384     {
385         VerifyOrExit(mMeshLocalIid.IsUnspecified(), error = kErrorAlready);
386         mMeshLocalIid = aAddress.GetIid();
387         ExitNow();
388     }
389 
390     for (Ip6::Address &ip6Address : mIp6Address)
391     {
392         if (ip6Address.IsUnspecified())
393         {
394             ip6Address = aAddress;
395             ExitNow();
396         }
397 
398         VerifyOrExit(ip6Address != aAddress, error = kErrorAlready);
399     }
400 
401     error = kErrorNoBufs;
402 
403 exit:
404     return error;
405 }
406 
RemoveIp6Address(const Ip6::Address & aAddress)407 Error Child::RemoveIp6Address(const Ip6::Address &aAddress)
408 {
409     Error    error = kErrorNotFound;
410     uint16_t index;
411 
412     VerifyOrExit(!aAddress.IsUnspecified(), error = kErrorInvalidArgs);
413 
414     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
415     {
416         if (aAddress.GetIid() == mMeshLocalIid)
417         {
418             mMeshLocalIid.Clear();
419             error = kErrorNone;
420         }
421 
422         ExitNow();
423     }
424 
425     for (index = 0; index < kNumIp6Addresses; index++)
426     {
427         VerifyOrExit(!mIp6Address[index].IsUnspecified());
428 
429         if (mIp6Address[index] == aAddress)
430         {
431             error = kErrorNone;
432             break;
433         }
434     }
435 
436     SuccessOrExit(error);
437 
438     for (; index < kNumIp6Addresses - 1; index++)
439     {
440         mIp6Address[index] = mIp6Address[index + 1];
441     }
442 
443     mIp6Address[kNumIp6Addresses - 1].Clear();
444 
445 exit:
446     return error;
447 }
448 
HasIp6Address(const Ip6::Address & aAddress) const449 bool Child::HasIp6Address(const Ip6::Address &aAddress) const
450 {
451     bool retval = false;
452 
453     VerifyOrExit(!aAddress.IsUnspecified());
454 
455     if (Get<Mle::MleRouter>().IsMeshLocalAddress(aAddress))
456     {
457         retval = (aAddress.GetIid() == mMeshLocalIid);
458         ExitNow();
459     }
460 
461     for (const Ip6::Address &ip6Address : mIp6Address)
462     {
463         VerifyOrExit(!ip6Address.IsUnspecified());
464 
465         if (ip6Address == aAddress)
466         {
467             ExitNow(retval = true);
468         }
469     }
470 
471 exit:
472     return retval;
473 }
474 
475 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
GetDomainUnicastAddress(void) const476 const Ip6::Address *Child::GetDomainUnicastAddress(void) const
477 {
478     const Ip6::Address *addr = nullptr;
479 
480     for (const Ip6::Address &ip6Address : mIp6Address)
481     {
482         VerifyOrExit(!ip6Address.IsUnspecified());
483 
484         if (Get<BackboneRouter::Leader>().IsDomainUnicast(ip6Address))
485         {
486             ExitNow(addr = &ip6Address);
487         }
488     }
489 
490 exit:
491     return addr;
492 }
493 #endif
494 
GenerateChallenge(void)495 void Child::GenerateChallenge(void)
496 {
497     IgnoreError(Random::Crypto::FillBuffer(mAttachChallenge, sizeof(mAttachChallenge)));
498 }
499 
500 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
HasMlrRegisteredAddress(const Ip6::Address & aAddress) const501 bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const
502 {
503     bool has = false;
504 
505     VerifyOrExit(mMlrRegisteredMask.HasAny());
506 
507     for (const Ip6::Address &address : IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
508     {
509         if (GetAddressMlrState(address) == kMlrStateRegistered && address == aAddress)
510         {
511             ExitNow(has = true);
512         }
513     }
514 
515 exit:
516     return has;
517 }
518 
GetAddressMlrState(const Ip6::Address & aAddress) const519 MlrState Child::GetAddressMlrState(const Ip6::Address &aAddress) const
520 {
521     uint16_t addressIndex;
522 
523     OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
524 
525     addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
526 
527     return mMlrToRegisterMask.Get(addressIndex)
528                ? kMlrStateToRegister
529                : (mMlrRegisteredMask.Get(addressIndex) ? kMlrStateRegistered : kMlrStateRegistering);
530 }
531 
SetAddressMlrState(const Ip6::Address & aAddress,MlrState aState)532 void Child::SetAddressMlrState(const Ip6::Address &aAddress, MlrState aState)
533 {
534     uint16_t addressIndex;
535 
536     OT_ASSERT(&mIp6Address[0] <= &aAddress && &aAddress < GetArrayEnd(mIp6Address));
537 
538     addressIndex = static_cast<uint16_t>(&aAddress - mIp6Address);
539 
540     mMlrToRegisterMask.Set(addressIndex, aState == kMlrStateToRegister);
541     mMlrRegisteredMask.Set(addressIndex, aState == kMlrStateRegistered);
542 }
543 #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
544 
545 #endif // OPENTHREAD_FTD
546 
SetFrom(const Router & aRouter)547 void Router::Info::SetFrom(const Router &aRouter)
548 {
549     Clear();
550     mRloc16          = aRouter.GetRloc16();
551     mRouterId        = Mle::RouterIdFromRloc16(mRloc16);
552     mExtAddress      = aRouter.GetExtAddress();
553     mAllocated       = true;
554     mNextHop         = aRouter.GetNextHop();
555     mLinkEstablished = aRouter.IsStateValid();
556     mPathCost        = aRouter.GetCost();
557     mLinkQualityIn   = aRouter.GetLinkQualityIn();
558     mLinkQualityOut  = aRouter.GetLinkQualityOut();
559     mAge             = static_cast<uint8_t>(Time::MsecToSec(TimerMilli::GetNow() - aRouter.GetLastHeard()));
560     mVersion         = ClampToUint8(aRouter.GetVersion());
561 }
562 
SetFrom(const Parent & aParent)563 void Router::Info::SetFrom(const Parent &aParent)
564 {
565     SetFrom(static_cast<const Router &>(aParent));
566 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
567     mCslClockAccuracy = aParent.GetCslAccuracy().GetClockAccuracy();
568     mCslUncertainty   = aParent.GetCslAccuracy().GetUncertainty();
569 #endif
570 }
571 
Clear(void)572 void Router::Clear(void)
573 {
574     Instance &instance = GetInstance();
575 
576     memset(reinterpret_cast<void *>(this), 0, sizeof(Router));
577     Init(instance);
578 }
579 
GetTwoWayLinkQuality(void) const580 LinkQuality Router::GetTwoWayLinkQuality(void) const { return Min(GetLinkQualityIn(), GetLinkQualityOut()); }
581 
SetFrom(const Parent & aParent)582 void Router::SetFrom(const Parent &aParent)
583 {
584     // We use an intermediate pointer to copy `aParent` to silence
585     // code checkers warning about object slicing (assigning a
586     // sub-class to base class instance).
587 
588     const Router *parentAsRouter = &aParent;
589 
590     *this = *parentAsRouter;
591 }
592 
Clear(void)593 void Parent::Clear(void)
594 {
595     Instance &instance = GetInstance();
596 
597     memset(reinterpret_cast<void *>(this), 0, sizeof(Parent));
598     Init(instance);
599 }
600 
SetNextHopAndCost(uint8_t aNextHop,uint8_t aCost)601 bool Router::SetNextHopAndCost(uint8_t aNextHop, uint8_t aCost)
602 {
603     bool changed = false;
604 
605     if (mNextHop != aNextHop)
606     {
607         mNextHop = aNextHop;
608         changed  = true;
609     }
610 
611     if (mCost != aCost)
612     {
613         mCost   = aCost;
614         changed = true;
615     }
616 
617     return changed;
618 }
619 
SetNextHopToInvalid(void)620 bool Router::SetNextHopToInvalid(void) { return SetNextHopAndCost(Mle::kInvalidRouterId, 0); }
621 
622 } // namespace ot
623