• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *  1. Redistributions of source code must retain the above copyright
7  *     notice, this list of conditions and the following disclaimer.
8  *  2. Redistributions in binary form must reproduce the above copyright
9  *     notice, this list of conditions and the following disclaimer in the
10  *     documentation and/or other materials provided with the distribution.
11  *  3. Neither the name of the copyright holder nor the
12  *     names of its contributors may be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file implements MLE functionality required for the Thread Router and Leader roles.
31  */
32 
33 #include "mle_router.hpp"
34 
35 #if OPENTHREAD_FTD
36 
37 #include "common/as_core_type.hpp"
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/encoding.hpp"
41 #include "common/instance.hpp"
42 #include "common/locator_getters.hpp"
43 #include "common/random.hpp"
44 #include "common/serial_number.hpp"
45 #include "common/settings.hpp"
46 #include "mac/mac_types.hpp"
47 #include "meshcop/meshcop.hpp"
48 #include "net/icmp6.hpp"
49 #include "thread/key_manager.hpp"
50 #include "thread/thread_netif.hpp"
51 #include "thread/thread_tlvs.hpp"
52 #include "thread/time_sync_service.hpp"
53 #include "thread/uri_paths.hpp"
54 #include "utils/otns.hpp"
55 
56 namespace ot {
57 namespace Mle {
58 
59 RegisterLogModule("Mle");
60 
MleRouter(Instance & aInstance)61 MleRouter::MleRouter(Instance &aInstance)
62     : Mle(aInstance)
63     , mAdvertiseTrickleTimer(aInstance, MleRouter::HandleAdvertiseTrickleTimer)
64     , mAddressSolicit(UriPath::kAddressSolicit, &MleRouter::HandleAddressSolicit, this)
65     , mAddressRelease(UriPath::kAddressRelease, &MleRouter::HandleAddressRelease, this)
66     , mChildTable(aInstance)
67     , mRouterTable(aInstance)
68     , mChallengeTimeout(0)
69     , mNextChildId(kMaxChildId)
70     , mNetworkIdTimeout(kNetworkIdTimeout)
71     , mRouterUpgradeThreshold(kRouterUpgradeThreshold)
72     , mRouterDowngradeThreshold(kRouterDowngradeThreshold)
73     , mLeaderWeight(kLeaderWeight)
74 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
75     , mPreferredLeaderPartitionId(0)
76     , mCcmEnabled(false)
77     , mThreadVersionCheckEnabled(true)
78 #endif
79     , mRouterEligible(true)
80     , mAddressSolicitPending(false)
81     , mAddressSolicitRejected(false)
82     , mPreviousPartitionIdRouter(0)
83     , mPreviousPartitionId(0)
84     , mPreviousPartitionRouterIdSequence(0)
85     , mPreviousPartitionIdTimeout(0)
86     , mRouterSelectionJitter(kRouterSelectionJitter)
87     , mRouterSelectionJitterTimeout(0)
88     , mLinkRequestDelay(0)
89     , mParentPriority(kParentPriorityUnspecified)
90 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
91     , mBackboneRouterRegistrationDelay(0)
92 #endif
93 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
94     , mMaxChildIpAddresses(0)
95 #endif
96     , mDiscoveryRequestCallback(nullptr)
97     , mDiscoveryRequestCallbackContext(nullptr)
98 {
99     mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData);
100 
101     SetRouterId(kInvalidRouterId);
102 
103 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
104     mSteeringData.Clear();
105 #endif
106 }
107 
HandlePartitionChange(void)108 void MleRouter::HandlePartitionChange(void)
109 {
110     mPreviousPartitionId               = mLeaderData.GetPartitionId();
111     mPreviousPartitionRouterIdSequence = mRouterTable.GetRouterIdSequence();
112     mPreviousPartitionIdTimeout        = GetNetworkIdTimeout();
113 
114     Get<AddressResolver>().Clear();
115     IgnoreError(Get<Tmf::Agent>().AbortTransaction(&MleRouter::HandleAddressSolicitResponse, this));
116     mRouterTable.Clear();
117 }
118 
IsRouterEligible(void) const119 bool MleRouter::IsRouterEligible(void) const
120 {
121     bool                  rval      = false;
122     const SecurityPolicy &secPolicy = Get<KeyManager>().GetSecurityPolicy();
123 
124     VerifyOrExit(mRouterEligible && IsFullThreadDevice());
125 
126 #if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
127     VerifyOrExit(secPolicy.mRoutersEnabled);
128 #else
129     if (secPolicy.mCommercialCommissioningEnabled)
130     {
131 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
132         VerifyOrExit(mCcmEnabled || secPolicy.mNonCcmRoutersEnabled);
133 #else
134         VerifyOrExit(secPolicy.mNonCcmRoutersEnabled);
135 #endif
136     }
137     if (!secPolicy.mRoutersEnabled)
138     {
139 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
140         VerifyOrExit(!mThreadVersionCheckEnabled ||
141                      secPolicy.mVersionThresholdForRouting + SecurityPolicy::kVersionThresholdOffsetVersion <=
142                          kThreadVersion);
143 #else
144         VerifyOrExit(secPolicy.mVersionThresholdForRouting + SecurityPolicy::kVersionThresholdOffsetVersion <=
145                      kThreadVersion);
146 #endif
147     }
148 #endif
149 
150     rval = true;
151 
152 exit:
153     return rval;
154 }
155 
SetRouterEligible(bool aEligible)156 Error MleRouter::SetRouterEligible(bool aEligible)
157 {
158     Error error = kErrorNone;
159 
160     VerifyOrExit(IsFullThreadDevice() || !aEligible, error = kErrorNotCapable);
161 
162     mRouterEligible = aEligible;
163 
164     switch (mRole)
165     {
166     case kRoleDisabled:
167     case kRoleDetached:
168         break;
169 
170     case kRoleChild:
171         Get<Mac::Mac>().SetBeaconEnabled(mRouterEligible);
172         break;
173 
174     case kRoleRouter:
175     case kRoleLeader:
176         if (!mRouterEligible)
177         {
178             IgnoreError(BecomeDetached());
179         }
180 
181         break;
182     }
183 
184 exit:
185     return error;
186 }
187 
BecomeRouter(ThreadStatusTlv::Status aStatus)188 Error MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
189 {
190     Error error = kErrorNone;
191 
192     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
193     VerifyOrExit(!IsRouter(), error = kErrorNone);
194     VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
195 
196     LogInfo("Attempt to become router");
197 
198     Get<MeshForwarder>().SetRxOnWhenIdle(true);
199     mRouterSelectionJitterTimeout = 0;
200     mLinkRequestDelay             = 0;
201 
202     switch (mRole)
203     {
204     case kRoleDetached:
205         SuccessOrExit(error = SendLinkRequest(nullptr));
206         Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
207         break;
208 
209     case kRoleChild:
210         SuccessOrExit(error = SendAddressSolicit(aStatus));
211         break;
212 
213     default:
214         OT_ASSERT(false);
215         OT_UNREACHABLE_CODE(break);
216     }
217 
218 exit:
219     return error;
220 }
221 
BecomeLeader(void)222 Error MleRouter::BecomeLeader(void)
223 {
224     Error    error = kErrorNone;
225     Router * router;
226     uint32_t partitionId;
227     uint8_t  leaderId;
228 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
229     uint8_t minRouterId;
230     uint8_t maxRouterId;
231 #endif
232 
233     VerifyOrExit(!Get<MeshCoP::ActiveDatasetManager>().IsPartiallyComplete(), error = kErrorInvalidState);
234     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
235     VerifyOrExit(!IsLeader(), error = kErrorNone);
236     VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
237 
238     mRouterTable.Clear();
239 
240 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
241     partitionId = mPreferredLeaderPartitionId ? mPreferredLeaderPartitionId : Random::NonCrypto::GetUint32();
242 #else
243     partitionId = Random::NonCrypto::GetUint32();
244 #endif
245 
246 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
247     mRouterTable.GetRouterIdRange(minRouterId, maxRouterId);
248     if (IsRouterIdValid(mPreviousRouterId) && minRouterId <= mPreviousRouterId && mPreviousRouterId <= maxRouterId)
249     {
250         leaderId = mPreviousRouterId;
251     }
252     else
253     {
254         leaderId = Random::NonCrypto::GetUint8InRange(minRouterId, maxRouterId + 1);
255     }
256 #else
257     leaderId    = IsRouterIdValid(mPreviousRouterId) ? mPreviousRouterId
258                                                   : Random::NonCrypto::GetUint8InRange(0, kMaxRouterId + 1);
259 #endif
260 
261     SetLeaderData(partitionId, mLeaderWeight, leaderId);
262 
263     router = mRouterTable.Allocate(leaderId);
264     OT_ASSERT(router != nullptr);
265 
266     SetRouterId(leaderId);
267     router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
268 
269     Get<NetworkData::Leader>().Reset();
270     Get<MeshCoP::Leader>().SetEmptyCommissionerData();
271 
272     SetStateLeader(Rloc16FromRouterId(leaderId), kStartingAsLeader);
273 
274 exit:
275     return error;
276 }
277 
StopLeader(void)278 void MleRouter::StopLeader(void)
279 {
280     Get<Tmf::Agent>().RemoveResource(mAddressSolicit);
281     Get<Tmf::Agent>().RemoveResource(mAddressRelease);
282     Get<MeshCoP::ActiveDatasetManager>().StopLeader();
283     Get<MeshCoP::PendingDatasetManager>().StopLeader();
284     StopAdvertiseTrickleTimer();
285     Get<NetworkData::Leader>().Stop();
286     Get<ThreadNetif>().UnsubscribeAllRoutersMulticast();
287 }
288 
HandleDetachStart(void)289 void MleRouter::HandleDetachStart(void)
290 {
291     mRouterTable.ClearNeighbors();
292     StopLeader();
293     Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter);
294 }
295 
HandleChildStart(AttachMode aMode)296 void MleRouter::HandleChildStart(AttachMode aMode)
297 {
298     mLinkRequestDelay       = 0;
299     mAddressSolicitRejected = false;
300 
301     mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
302 
303     StopLeader();
304     Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
305 
306     if (mRouterEligible)
307     {
308         Get<Mac::Mac>().SetBeaconEnabled(true);
309     }
310 
311     Get<ThreadNetif>().SubscribeAllRoutersMulticast();
312 
313     VerifyOrExit(IsRouterIdValid(mPreviousRouterId));
314 
315     switch (aMode)
316     {
317     case kDowngradeToReed:
318         SendAddressRelease();
319 
320         // reset children info if any
321         if (HasChildren())
322         {
323             RemoveChildren();
324         }
325 
326         // reset routerId info
327         SetRouterId(kInvalidRouterId);
328         break;
329 
330     case kSamePartition:
331     case kSamePartitionRetry:
332         if (HasChildren())
333         {
334             IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
335         }
336 
337         break;
338 
339     case kAnyPartition:
340     case kBetterParent:
341         // If attach was started due to receiving MLE Announce Messages, all rx-on-when-idle devices would
342         // start attach immediately when receiving such Announce message as in Thread 1.1 specification,
343         // Section 4.8.1,
344         // "If the received value is newer and the channel and/or PAN ID in the Announce message differ
345         //  from those currently in use, the receiving device attempts to attach using the channel and
346         //  PAN ID received from the Announce message."
347         //
348         // That is, Parent-child relationship is highly unlikely to be kept in the new partition, so here
349         // removes all children, leaving whether to become router according to the new partition status.
350         if (IsAnnounceAttach() && HasChildren())
351         {
352             RemoveChildren();
353         }
354 
355         OT_FALL_THROUGH;
356 
357     case kBetterPartition:
358         if (HasChildren() && mPreviousPartitionIdRouter != mLeaderData.GetPartitionId())
359         {
360             IgnoreError(BecomeRouter(ThreadStatusTlv::kParentPartitionChange));
361         }
362 
363         break;
364     }
365 
366 exit:
367 
368     if (mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold &&
369         (!IsRouterIdValid(mPreviousRouterId) || !HasChildren()))
370     {
371         SetRouterId(kInvalidRouterId);
372     }
373 }
374 
SetStateRouter(uint16_t aRloc16)375 void MleRouter::SetStateRouter(uint16_t aRloc16)
376 {
377     SetRloc16(aRloc16);
378 
379     SetRole(kRoleRouter);
380     SetAttachState(kAttachStateIdle);
381     mAttachCounter = 0;
382     mAttachTimer.Stop();
383     mMessageTransmissionTimer.Stop();
384     StopAdvertiseTrickleTimer();
385     ResetAdvertiseInterval();
386 
387     Get<ThreadNetif>().SubscribeAllRoutersMulticast();
388     mPreviousPartitionIdRouter = mLeaderData.GetPartitionId();
389     Get<NetworkData::Leader>().Stop();
390     Get<Ip6::Ip6>().SetForwardingEnabled(true);
391     Get<Ip6::Mpl>().SetTimerExpirations(kMplRouterDataMessageTimerExpirations);
392     Get<Mac::Mac>().SetBeaconEnabled(true);
393 
394     // remove children that do not have matching RLOC16
395     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
396     {
397         if (RouterIdFromRloc16(child.GetRloc16()) != mRouterId)
398         {
399             RemoveNeighbor(child);
400         }
401     }
402 
403 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
404     Get<Mac::Mac>().UpdateCsl();
405 #endif
406 }
407 
SetStateLeader(uint16_t aRloc16,LeaderStartMode aStartMode)408 void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
409 {
410     IgnoreError(Get<MeshCoP::ActiveDatasetManager>().Restore());
411     IgnoreError(Get<MeshCoP::PendingDatasetManager>().Restore());
412     SetRloc16(aRloc16);
413 
414     SetRole(kRoleLeader);
415     SetAttachState(kAttachStateIdle);
416     mAttachCounter = 0;
417     mAttachTimer.Stop();
418     mMessageTransmissionTimer.Stop();
419     StopAdvertiseTrickleTimer();
420     ResetAdvertiseInterval();
421     IgnoreError(GetLeaderAloc(mLeaderAloc.GetAddress()));
422     Get<ThreadNetif>().AddUnicastAddress(mLeaderAloc);
423 
424     Get<ThreadNetif>().SubscribeAllRoutersMulticast();
425     mPreviousPartitionIdRouter = mLeaderData.GetPartitionId();
426     Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
427 
428     Get<NetworkData::Leader>().Start(aStartMode);
429     Get<MeshCoP::ActiveDatasetManager>().StartLeader();
430     Get<MeshCoP::PendingDatasetManager>().StartLeader();
431     Get<Tmf::Agent>().AddResource(mAddressSolicit);
432     Get<Tmf::Agent>().AddResource(mAddressRelease);
433     Get<Ip6::Ip6>().SetForwardingEnabled(true);
434     Get<Ip6::Mpl>().SetTimerExpirations(kMplRouterDataMessageTimerExpirations);
435     Get<Mac::Mac>().SetBeaconEnabled(true);
436     Get<AddressResolver>().Clear();
437 
438     // remove children that do not have matching RLOC16
439     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
440     {
441         if (RouterIdFromRloc16(child.GetRloc16()) != mRouterId)
442         {
443             RemoveNeighbor(child);
444         }
445     }
446 
447 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
448     Get<Mac::Mac>().UpdateCsl();
449 #endif
450 
451     LogNote("Leader partition id 0x%x", mLeaderData.GetPartitionId());
452 }
453 
HandleAdvertiseTrickleTimer(TrickleTimer & aTimer)454 void MleRouter::HandleAdvertiseTrickleTimer(TrickleTimer &aTimer)
455 {
456     aTimer.Get<MleRouter>().HandleAdvertiseTrickleTimer();
457 }
458 
HandleAdvertiseTrickleTimer(void)459 void MleRouter::HandleAdvertiseTrickleTimer(void)
460 {
461     VerifyOrExit(IsRouterEligible(), mAdvertiseTrickleTimer.Stop());
462 
463     SendAdvertisement();
464 
465 exit:
466     return;
467 }
468 
StopAdvertiseTrickleTimer(void)469 void MleRouter::StopAdvertiseTrickleTimer(void)
470 {
471     mAdvertiseTrickleTimer.Stop();
472 }
473 
ResetAdvertiseInterval(void)474 void MleRouter::ResetAdvertiseInterval(void)
475 {
476     VerifyOrExit(IsRouterOrLeader());
477 
478     if (!mAdvertiseTrickleTimer.IsRunning())
479     {
480         mAdvertiseTrickleTimer.Start(TrickleTimer::kModeTrickle, Time::SecToMsec(kAdvertiseIntervalMin),
481                                      Time::SecToMsec(kAdvertiseIntervalMax));
482     }
483 
484     mAdvertiseTrickleTimer.IndicateInconsistent();
485 
486 exit:
487     return;
488 }
489 
SendAdvertisement(void)490 void MleRouter::SendAdvertisement(void)
491 {
492     Error        error = kErrorNone;
493     Ip6::Address destination;
494     TxMessage *  message = nullptr;
495 
496     // Suppress MLE Advertisements when trying to attach to a better partition.
497     //
498     // Without this suppression, a device may send an MLE Advertisement before receiving the MLE Child ID Response.
499     // The candidate parent then removes the attaching device because the Source Address TLV includes an RLOC16 that
500     // indicates a Router role (i.e. a Child ID equal to zero).
501     VerifyOrExit(!IsAttaching());
502 
503     // Suppress MLE Advertisements when transitioning to the router role.
504     //
505     // When trying to attach to a new partition, sending out advertisements as a REED can cause already-attached
506     // children to detach.
507     VerifyOrExit(!mAddressSolicitPending);
508 
509     // Suppress MLE Advertisements before sending multicast Link Request.
510     //
511     // Before sending the multicast Link Request message, no links have been established to neighboring routers.
512     VerifyOrExit(mLinkRequestDelay == 0);
513 
514     VerifyOrExit((message = NewMleMessage(kCommandAdvertisement)) != nullptr, error = kErrorNoBufs);
515     SuccessOrExit(error = message->AppendSourceAddressTlv());
516     SuccessOrExit(error = message->AppendLeaderDataTlv());
517 
518     switch (mRole)
519     {
520     case kRoleDisabled:
521     case kRoleDetached:
522         OT_ASSERT(false);
523         OT_UNREACHABLE_CODE(break);
524 
525     case kRoleChild:
526         break;
527 
528     case kRoleRouter:
529     case kRoleLeader:
530         SuccessOrExit(error = message->AppendRouteTlv());
531         break;
532     }
533 
534     destination.SetToLinkLocalAllNodesMulticast();
535     SuccessOrExit(error = message->SendTo(destination));
536 
537     Log(kMessageSend, kTypeAdvertisement, destination);
538 
539 exit:
540     FreeMessageOnError(message, error);
541     LogSendError(kTypeAdvertisement, error);
542 }
543 
SendLinkRequest(Neighbor * aNeighbor)544 Error MleRouter::SendLinkRequest(Neighbor *aNeighbor)
545 {
546     static const uint8_t detachedTlvs[]      = {Tlv::kAddress16, Tlv::kRoute};
547     static const uint8_t routerTlvs[]        = {Tlv::kLinkMargin};
548     static const uint8_t validNeighborTlvs[] = {Tlv::kLinkMargin, Tlv::kRoute};
549     Error                error               = kErrorNone;
550     TxMessage *          message             = nullptr;
551     Ip6::Address         destination;
552 
553     VerifyOrExit(mLinkRequestDelay == 0 && mChallengeTimeout == 0);
554 
555     destination.Clear();
556 
557     VerifyOrExit((message = NewMleMessage(kCommandLinkRequest)) != nullptr, error = kErrorNoBufs);
558     SuccessOrExit(error = message->AppendVersionTlv());
559 
560     switch (mRole)
561     {
562     case kRoleDisabled:
563         OT_ASSERT(false);
564         OT_UNREACHABLE_CODE(break);
565 
566     case kRoleDetached:
567         SuccessOrExit(error = message->AppendTlvRequestTlv(detachedTlvs, sizeof(detachedTlvs)));
568         break;
569 
570     case kRoleChild:
571         SuccessOrExit(error = message->AppendSourceAddressTlv());
572         SuccessOrExit(error = message->AppendLeaderDataTlv());
573         break;
574 
575     case kRoleRouter:
576     case kRoleLeader:
577         if (aNeighbor == nullptr || !aNeighbor->IsStateValid())
578         {
579             SuccessOrExit(error = message->AppendTlvRequestTlv(routerTlvs, sizeof(routerTlvs)));
580         }
581         else
582         {
583             SuccessOrExit(error = message->AppendTlvRequestTlv(validNeighborTlvs, sizeof(validNeighborTlvs)));
584         }
585 
586         SuccessOrExit(error = message->AppendSourceAddressTlv());
587         SuccessOrExit(error = message->AppendLeaderDataTlv());
588         break;
589     }
590 
591 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
592     SuccessOrExit(error = message->AppendTimeRequestTlv());
593 #endif
594 
595     if (aNeighbor == nullptr)
596     {
597         mChallenge.GenerateRandom();
598         mChallengeTimeout = (((2 * kMaxResponseDelay) + kStateUpdatePeriod - 1) / kStateUpdatePeriod);
599 
600         SuccessOrExit(error = message->AppendChallengeTlv(mChallenge));
601         destination.SetToLinkLocalAllRoutersMulticast();
602     }
603     else
604     {
605         if (!aNeighbor->IsStateValid())
606         {
607             aNeighbor->GenerateChallenge();
608             SuccessOrExit(error =
609                               message->AppendChallengeTlv(aNeighbor->GetChallenge(), aNeighbor->GetChallengeSize()));
610         }
611         else
612         {
613             Challenge challenge;
614 
615             challenge.GenerateRandom();
616             SuccessOrExit(error = message->AppendChallengeTlv(challenge));
617         }
618 
619         destination.SetToLinkLocalAddress(aNeighbor->GetExtAddress());
620     }
621 
622     SuccessOrExit(error = message->SendTo(destination));
623 
624     Log(kMessageSend, kTypeLinkRequest, destination);
625 
626 exit:
627     FreeMessageOnError(message, error);
628     return error;
629 }
630 
HandleLinkRequest(RxInfo & aRxInfo)631 void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
632 {
633     Error         error    = kErrorNone;
634     Neighbor *    neighbor = nullptr;
635     Challenge     challenge;
636     uint16_t      version;
637     LeaderData    leaderData;
638     uint16_t      sourceAddress;
639     RequestedTlvs requestedTlvs;
640 
641     Log(kMessageReceive, kTypeLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr());
642 
643     VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
644 
645     VerifyOrExit(!IsAttaching(), error = kErrorInvalidState);
646 
647     // Challenge
648     SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
649 
650     // Version
651     SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
652     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = kErrorParse);
653 
654     // Leader Data
655     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
656     {
657     case kErrorNone:
658         VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId(), error = kErrorInvalidState);
659         break;
660     case kErrorNotFound:
661         break;
662     default:
663         ExitNow(error = kErrorParse);
664     }
665 
666     // Source Address
667     switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
668     {
669     case kErrorNone:
670         if (IsActiveRouter(sourceAddress))
671         {
672             Mac::ExtAddress extAddr;
673 
674             aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
675 
676             neighbor = mRouterTable.GetRouter(RouterIdFromRloc16(sourceAddress));
677             VerifyOrExit(neighbor != nullptr, error = kErrorParse);
678             VerifyOrExit(!neighbor->IsStateLinkRequest(), error = kErrorAlready);
679 
680             if (!neighbor->IsStateValid())
681             {
682                 neighbor->SetExtAddress(extAddr);
683                 neighbor->GetLinkInfo().Clear();
684                 neighbor->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
685                 neighbor->ResetLinkFailures();
686                 neighbor->SetLastHeard(TimerMilli::GetNow());
687                 neighbor->SetState(Neighbor::kStateLinkRequest);
688             }
689             else
690             {
691                 VerifyOrExit(neighbor->GetExtAddress() == extAddr);
692             }
693         }
694 
695         break;
696 
697     case kErrorNotFound:
698         // lack of source address indicates router coming out of reset
699         VerifyOrExit(aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid() &&
700                          IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()),
701                      error = kErrorDrop);
702         neighbor = aRxInfo.mNeighbor;
703         break;
704 
705     default:
706         ExitNow(error = kErrorParse);
707     }
708 
709     // TLV Request
710     switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs))
711     {
712     case kErrorNone:
713         break;
714     case kErrorNotFound:
715         requestedTlvs.mNumTlvs = 0;
716         break;
717     default:
718         ExitNow(error = kErrorParse);
719     }
720 
721 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
722     if (neighbor != nullptr)
723     {
724         neighbor->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
725     }
726 #endif
727 
728 #if OPENTHREAD_CONFIG_MULTI_RADIO
729     if (neighbor != nullptr)
730     {
731         neighbor->ClearLastRxFragmentTag();
732     }
733 #endif
734 
735     aRxInfo.mClass = RxInfo::kPeerMessage;
736 
737     SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, neighbor, requestedTlvs, challenge));
738 
739 exit:
740     LogProcessError(kTypeLinkRequest, error);
741 }
742 
SendLinkAccept(const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor,const RequestedTlvs & aRequestedTlvs,const Challenge & aChallenge)743 Error MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo,
744                                 Neighbor *              aNeighbor,
745                                 const RequestedTlvs &   aRequestedTlvs,
746                                 const Challenge &       aChallenge)
747 {
748     Error                error        = kErrorNone;
749     static const uint8_t routerTlvs[] = {Tlv::kLinkMargin};
750     TxMessage *          message;
751     Command              command;
752     uint8_t              linkMargin;
753 
754     command = (aNeighbor == nullptr || aNeighbor->IsStateValid()) ? kCommandLinkAccept : kCommandLinkAcceptAndRequest;
755 
756     VerifyOrExit((message = NewMleMessage(command)) != nullptr, error = kErrorNoBufs);
757     SuccessOrExit(error = message->AppendVersionTlv());
758     SuccessOrExit(error = message->AppendSourceAddressTlv());
759     SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
760     SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
761     SuccessOrExit(error = message->AppendMleFrameCounterTlv());
762 
763     // always append a link margin, regardless of whether or not it was requested
764     linkMargin = LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(),
765                                                          aMessageInfo.GetThreadLinkInfo()->GetRss());
766 
767     SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin));
768 
769     if (aNeighbor != nullptr && IsActiveRouter(aNeighbor->GetRloc16()))
770     {
771         SuccessOrExit(error = message->AppendLeaderDataTlv());
772     }
773 
774     for (uint8_t i = 0; i < aRequestedTlvs.mNumTlvs; i++)
775     {
776         switch (aRequestedTlvs.mTlvs[i])
777         {
778         case Tlv::kRoute:
779             SuccessOrExit(error = message->AppendRouteTlv(aNeighbor));
780             break;
781 
782         case Tlv::kAddress16:
783             VerifyOrExit(aNeighbor != nullptr, error = kErrorDrop);
784             SuccessOrExit(error = message->AppendAddress16Tlv(aNeighbor->GetRloc16()));
785             break;
786 
787         case Tlv::kLinkMargin:
788             break;
789 
790         default:
791             ExitNow(error = kErrorDrop);
792         }
793     }
794 
795     if (aNeighbor != nullptr && !aNeighbor->IsStateValid())
796     {
797         aNeighbor->GenerateChallenge();
798 
799         SuccessOrExit(error = message->AppendChallengeTlv(aNeighbor->GetChallenge(), aNeighbor->GetChallengeSize()));
800         SuccessOrExit(error = message->AppendTlvRequestTlv(routerTlvs, sizeof(routerTlvs)));
801         aNeighbor->SetLastHeard(TimerMilli::GetNow());
802         aNeighbor->SetState(Neighbor::kStateLinkRequest);
803     }
804 
805 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
806     if (aNeighbor != nullptr && aNeighbor->IsTimeSyncEnabled())
807     {
808         message->SetTimeSync(true);
809     }
810 #endif
811 
812     if (aMessageInfo.GetSockAddr().IsMulticast())
813     {
814         SuccessOrExit(error = message->SendAfterDelay(aMessageInfo.GetPeerAddr(),
815                                                       1 + Random::NonCrypto::GetUint16InRange(0, kMaxResponseDelay)));
816 
817         Log(kMessageDelay, kTypeLinkAccept, aMessageInfo.GetPeerAddr());
818     }
819     else
820     {
821         SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
822 
823         Log(kMessageSend, kTypeLinkAccept, aMessageInfo.GetPeerAddr());
824     }
825 
826 exit:
827     FreeMessageOnError(message, error);
828     return error;
829 }
830 
HandleLinkAccept(RxInfo & aRxInfo)831 void MleRouter::HandleLinkAccept(RxInfo &aRxInfo)
832 {
833     Error error = HandleLinkAccept(aRxInfo, false);
834 
835     LogProcessError(kTypeLinkAccept, error);
836 }
837 
HandleLinkAcceptAndRequest(RxInfo & aRxInfo)838 void MleRouter::HandleLinkAcceptAndRequest(RxInfo &aRxInfo)
839 {
840     Error error = HandleLinkAccept(aRxInfo, true);
841 
842     LogProcessError(kTypeLinkAcceptAndRequest, error);
843 }
844 
HandleLinkAccept(RxInfo & aRxInfo,bool aRequest)845 Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
846 {
847     static const uint8_t dataRequestTlvs[] = {Tlv::kNetworkData};
848 
849     Error           error = kErrorNone;
850     Router *        router;
851     Neighbor::State neighborState;
852     Mac::ExtAddress extAddr;
853     uint16_t        version;
854     Challenge       response;
855     uint16_t        sourceAddress;
856     uint32_t        linkFrameCounter;
857     uint32_t        mleFrameCounter;
858     uint8_t         routerId;
859     uint16_t        address16;
860     RouteTlv        routeTlv;
861     LeaderData      leaderData;
862     uint8_t         linkMargin;
863 
864     // Source Address
865     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
866 
867     Log(kMessageReceive, aRequest ? kTypeLinkAcceptAndRequest : kTypeLinkAccept, aRxInfo.mMessageInfo.GetPeerAddr(),
868         sourceAddress);
869 
870     VerifyOrExit(IsActiveRouter(sourceAddress), error = kErrorParse);
871 
872     routerId      = RouterIdFromRloc16(sourceAddress);
873     router        = mRouterTable.GetRouter(routerId);
874     neighborState = (router != nullptr) ? router->GetState() : Neighbor::kStateInvalid;
875 
876     // Response
877     SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
878 
879     // verify response
880     switch (neighborState)
881     {
882     case Neighbor::kStateLinkRequest:
883         VerifyOrExit(response.Matches(router->GetChallenge(), router->GetChallengeSize()), error = kErrorSecurity);
884         break;
885 
886     case Neighbor::kStateInvalid:
887         VerifyOrExit((mChallengeTimeout > 0) && (response == mChallenge), error = kErrorSecurity);
888 
889         OT_FALL_THROUGH;
890 
891     case Neighbor::kStateValid:
892         break;
893 
894     default:
895         ExitNow(error = kErrorSecurity);
896     }
897 
898     // Remove stale neighbors
899     if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != sourceAddress)
900     {
901         RemoveNeighbor(*aRxInfo.mNeighbor);
902     }
903 
904     // Version
905     SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
906     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = kErrorParse);
907 
908     // Link and MLE Frame Counters
909     SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
910 
911     // Link Margin
912     switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMargin))
913     {
914     case kErrorNone:
915         break;
916     case kErrorNotFound:
917         // Link Margin TLV may be skipped in Router Synchronization process after Reset
918         VerifyOrExit(IsDetached(), error = kErrorNotFound);
919         // Wait for an MLE Advertisement to establish a routing cost to the neighbor
920         linkMargin = 0;
921         break;
922     default:
923         ExitNow(error = kErrorParse);
924     }
925 
926     switch (mRole)
927     {
928     case kRoleDisabled:
929         OT_ASSERT(false);
930         OT_UNREACHABLE_CODE(break);
931 
932     case kRoleDetached:
933         // Address16
934         SuccessOrExit(error = Tlv::Find<Address16Tlv>(aRxInfo.mMessage, address16));
935         VerifyOrExit(GetRloc16() == address16, error = kErrorDrop);
936 
937         // Leader Data
938         SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
939         SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
940 
941         // Route
942         mRouterTable.Clear();
943         SuccessOrExit(error = ProcessRouteTlv(aRxInfo));
944         router = mRouterTable.GetRouter(routerId);
945         VerifyOrExit(router != nullptr);
946 
947         if (mLeaderData.GetLeaderRouterId() == RouterIdFromRloc16(GetRloc16()))
948         {
949             SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset);
950         }
951         else
952         {
953             SetStateRouter(GetRloc16());
954         }
955 
956         mRetrieveNewNetworkData = true;
957         IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), dataRequestTlvs, sizeof(dataRequestTlvs), 0));
958 
959 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
960         Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
961 #endif
962         break;
963 
964     case kRoleChild:
965         VerifyOrExit(router != nullptr);
966         break;
967 
968     case kRoleRouter:
969     case kRoleLeader:
970         VerifyOrExit(router != nullptr);
971 
972         // Leader Data
973         SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
974         VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
975 
976         if (mRetrieveNewNetworkData ||
977             SerialNumber::IsGreater(leaderData.GetDataVersion(NetworkData::kFullSet),
978                                     Get<NetworkData::Leader>().GetVersion(NetworkData::kFullSet)))
979         {
980             IgnoreError(
981                 SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), dataRequestTlvs, sizeof(dataRequestTlvs), 0));
982         }
983 
984         // Route (optional)
985         switch (error = ProcessRouteTlv(aRxInfo, routeTlv))
986         {
987         case kErrorNone:
988             UpdateRoutes(routeTlv, routerId);
989             // Need to update router after ProcessRouteTlv
990             router = mRouterTable.GetRouter(routerId);
991             OT_ASSERT(router != nullptr);
992             break;
993 
994         case kErrorNotFound:
995             error = kErrorNone;
996             break;
997 
998         default:
999             ExitNow();
1000         }
1001 
1002         // update routing table
1003         if (routerId != mRouterId && !IsRouterIdValid(router->GetNextHop()))
1004         {
1005             ResetAdvertiseInterval();
1006         }
1007 
1008         break;
1009     }
1010 
1011     // finish link synchronization
1012     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
1013     router->SetExtAddress(extAddr);
1014     router->SetRloc16(sourceAddress);
1015     router->GetLinkFrameCounters().SetAll(linkFrameCounter);
1016     router->SetLinkAckFrameCounter(linkFrameCounter);
1017     router->SetMleFrameCounter(mleFrameCounter);
1018     router->SetLastHeard(TimerMilli::GetNow());
1019     router->SetVersion(static_cast<uint8_t>(version));
1020     router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
1021                                      DeviceMode::kModeFullNetworkData));
1022     router->GetLinkInfo().Clear();
1023     router->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
1024     router->SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMargin));
1025     router->ResetLinkFailures();
1026     router->SetState(Neighbor::kStateValid);
1027     router->SetKeySequence(aRxInfo.mKeySequence);
1028 
1029     mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
1030 
1031     aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
1032 
1033     if (aRequest)
1034     {
1035         Challenge     challenge;
1036         RequestedTlvs requestedTlvs;
1037 
1038         // Challenge
1039         SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
1040 
1041         // TLV Request
1042         switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs))
1043         {
1044         case kErrorNone:
1045             break;
1046         case kErrorNotFound:
1047             requestedTlvs.mNumTlvs = 0;
1048             break;
1049         default:
1050             ExitNow(error = kErrorParse);
1051         }
1052 
1053         SuccessOrExit(error = SendLinkAccept(aRxInfo.mMessageInfo, router, requestedTlvs, challenge));
1054     }
1055 
1056 exit:
1057     return error;
1058 }
1059 
LinkQualityToCost(uint8_t aLinkQuality)1060 uint8_t MleRouter::LinkQualityToCost(uint8_t aLinkQuality)
1061 {
1062     uint8_t rval;
1063 
1064     switch (aLinkQuality)
1065     {
1066     case 1:
1067         rval = kLinkQuality1LinkCost;
1068         break;
1069 
1070     case 2:
1071         rval = kLinkQuality2LinkCost;
1072         break;
1073 
1074     case 3:
1075         rval = kLinkQuality3LinkCost;
1076         break;
1077 
1078     default:
1079         rval = kLinkQuality0LinkCost;
1080         break;
1081     }
1082 
1083     return rval;
1084 }
1085 
GetLinkCost(uint8_t aRouterId)1086 uint8_t MleRouter::GetLinkCost(uint8_t aRouterId)
1087 {
1088     uint8_t rval = kMaxRouteCost;
1089     Router *router;
1090 
1091     router = mRouterTable.GetRouter(aRouterId);
1092 
1093     // `nullptr` aRouterId indicates non-existing next hop, hence return kMaxRouteCost for it.
1094     VerifyOrExit(router != nullptr);
1095 
1096     rval = mRouterTable.GetLinkCost(*router);
1097 
1098 exit:
1099     return rval;
1100 }
1101 
SetRouterSelectionJitter(uint8_t aRouterJitter)1102 Error MleRouter::SetRouterSelectionJitter(uint8_t aRouterJitter)
1103 {
1104     Error error = kErrorNone;
1105 
1106     VerifyOrExit(aRouterJitter > 0, error = kErrorInvalidArgs);
1107 
1108     mRouterSelectionJitter = aRouterJitter;
1109 
1110 exit:
1111     return error;
1112 }
1113 
ProcessRouteTlv(RxInfo & aRxInfo)1114 Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo)
1115 {
1116     RouteTlv routeTlv;
1117 
1118     return ProcessRouteTlv(aRxInfo, routeTlv);
1119 }
1120 
ProcessRouteTlv(RxInfo & aRxInfo,RouteTlv & aRouteTlv)1121 Error MleRouter::ProcessRouteTlv(RxInfo &aRxInfo, RouteTlv &aRouteTlv)
1122 {
1123     // This method processes Route TLV in a received MLE message
1124     // (from `RxInfo`). In case of success, `aRouteTlv` is updated
1125     // to return the read/processed route TLV from the message.
1126     // If the message contains no Route TLV, `kErrorNotFound` is
1127     // returned.
1128     //
1129     // During processing of Route TLV, the entries in the router table
1130     // may shuffle. This method ensures that the `aRxInfo.mNeighbor`
1131     // (which indicates the neighbor from which the MLE message was
1132     // received) is correctly updated to point to the same neighbor
1133     // (in case `mNeighbor` was pointing to a router entry from the
1134     // `RouterTable`).
1135 
1136     Error    error;
1137     uint16_t neighborRloc16 = Mac::kShortAddrInvalid;
1138 
1139     if ((aRxInfo.mNeighbor != nullptr) && Get<RouterTable>().Contains(*aRxInfo.mNeighbor))
1140     {
1141         neighborRloc16 = aRxInfo.mNeighbor->GetRloc16();
1142     }
1143 
1144     SuccessOrExit(error = Tlv::FindTlv(aRxInfo.mMessage, aRouteTlv));
1145 
1146     VerifyOrExit(aRouteTlv.IsValid(), error = kErrorParse);
1147 
1148     Get<RouterTable>().UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask());
1149 
1150     if (IsRouter() && !Get<RouterTable>().IsAllocated(mRouterId))
1151     {
1152         IgnoreError(BecomeDetached());
1153         error = kErrorNoRoute;
1154     }
1155 
1156     if (neighborRloc16 != Mac::kShortAddrInvalid)
1157     {
1158         aRxInfo.mNeighbor = Get<RouterTable>().GetNeighbor(neighborRloc16);
1159     }
1160 
1161 exit:
1162     return error;
1163 }
1164 
IsSingleton(void)1165 bool MleRouter::IsSingleton(void)
1166 {
1167     bool rval = true;
1168 
1169     if (IsAttached() && IsRouterEligible())
1170     {
1171         // not a singleton if any other routers exist
1172         if (mRouterTable.GetActiveRouterCount() > 1)
1173         {
1174             ExitNow(rval = false);
1175         }
1176     }
1177 
1178 exit:
1179     return rval;
1180 }
1181 
ComparePartitions(bool aSingletonA,const LeaderData & aLeaderDataA,bool aSingletonB,const LeaderData & aLeaderDataB)1182 int MleRouter::ComparePartitions(bool              aSingletonA,
1183                                  const LeaderData &aLeaderDataA,
1184                                  bool              aSingletonB,
1185                                  const LeaderData &aLeaderDataB)
1186 {
1187     int rval = 0;
1188 
1189     if (aLeaderDataA.GetWeighting() != aLeaderDataB.GetWeighting())
1190     {
1191         ExitNow(rval = aLeaderDataA.GetWeighting() > aLeaderDataB.GetWeighting() ? 1 : -1);
1192     }
1193 
1194     if (aSingletonA != aSingletonB)
1195     {
1196         ExitNow(rval = aSingletonB ? 1 : -1);
1197     }
1198 
1199     if (aLeaderDataA.GetPartitionId() != aLeaderDataB.GetPartitionId())
1200     {
1201         ExitNow(rval = aLeaderDataA.GetPartitionId() > aLeaderDataB.GetPartitionId() ? 1 : -1);
1202     }
1203 
1204 exit:
1205     return rval;
1206 }
1207 
IsSingleton(const RouteTlv & aRouteTlv)1208 bool MleRouter::IsSingleton(const RouteTlv &aRouteTlv)
1209 {
1210     bool    rval  = true;
1211     uint8_t count = 0;
1212 
1213     // REEDs do not include a Route TLV and indicate not a singleton
1214     if (!aRouteTlv.IsValid())
1215     {
1216         ExitNow(rval = false);
1217     }
1218 
1219     // Check if 2 or more active routers
1220     for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++)
1221     {
1222         if (aRouteTlv.IsRouterIdSet(routerId) && (++count >= 2))
1223         {
1224             ExitNow(rval = false);
1225         }
1226     }
1227 
1228 exit:
1229     return rval;
1230 }
1231 
HandleAdvertisement(RxInfo & aRxInfo)1232 Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo)
1233 {
1234     Error                 error    = kErrorNone;
1235     const ThreadLinkInfo *linkInfo = aRxInfo.mMessageInfo.GetThreadLinkInfo();
1236     uint8_t linkMargin = LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(), linkInfo->GetRss());
1237     Mac::ExtAddress extAddr;
1238     uint16_t        sourceAddress = Mac::kShortAddrInvalid;
1239     LeaderData      leaderData;
1240     RouteTlv        route;
1241     uint32_t        partitionId;
1242     Router *        router;
1243     uint8_t         routerId;
1244     uint8_t         routerCount;
1245 
1246     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
1247 
1248     // Source Address
1249     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
1250 
1251     // Leader Data
1252     SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
1253 
1254     // Route Data (optional)
1255     if (Tlv::FindTlv(aRxInfo.mMessage, route) == kErrorNone)
1256     {
1257         VerifyOrExit(route.IsValid(), error = kErrorParse);
1258     }
1259     else
1260     {
1261         // mark that a Route TLV was not included
1262         route.SetLength(0);
1263     }
1264 
1265     partitionId = leaderData.GetPartitionId();
1266 
1267     if (partitionId != mLeaderData.GetPartitionId())
1268     {
1269         LogNote("Different partition (peer:%u, local:%u)", partitionId, mLeaderData.GetPartitionId());
1270 
1271         VerifyOrExit(linkMargin >= OPENTHREAD_CONFIG_MLE_PARTITION_MERGE_MARGIN_MIN, error = kErrorLinkMarginLow);
1272 
1273         if (route.IsValid() && IsFullThreadDevice() && (mPreviousPartitionIdTimeout > 0) &&
1274             (partitionId == mPreviousPartitionId))
1275         {
1276             VerifyOrExit(SerialNumber::IsGreater(route.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence),
1277                          error = kErrorDrop);
1278         }
1279 
1280         if (IsChild() && (aRxInfo.mNeighbor == &mParent || !IsFullThreadDevice()))
1281         {
1282             ExitNow();
1283         }
1284 
1285         if (ComparePartitions(IsSingleton(route), leaderData, IsSingleton(), mLeaderData) > 0
1286 #if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
1287             // if time sync is required, it will only migrate to a better network which also enables time sync.
1288             && aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
1289 #endif
1290         )
1291         {
1292             Attach(kBetterPartition);
1293         }
1294 
1295         ExitNow(error = kErrorDrop);
1296     }
1297     else if (leaderData.GetLeaderRouterId() != GetLeaderId())
1298     {
1299         VerifyOrExit(aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid());
1300 
1301         if (!IsChild())
1302         {
1303             LogInfo("Leader ID mismatch");
1304             IgnoreError(BecomeDetached());
1305             error = kErrorDrop;
1306         }
1307 
1308         ExitNow();
1309     }
1310 
1311     VerifyOrExit(IsActiveRouter(sourceAddress) && route.IsValid());
1312     routerId = RouterIdFromRloc16(sourceAddress);
1313 
1314 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1315     Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
1316 #endif
1317 
1318     if (IsFullThreadDevice() && (aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid()) &&
1319         ((mRouterTable.GetActiveRouterCount() == 0) ||
1320          SerialNumber::IsGreater(route.GetRouterIdSequence(), mRouterTable.GetRouterIdSequence())))
1321     {
1322         bool processRouteTlv = false;
1323 
1324         switch (mRole)
1325         {
1326         case kRoleDisabled:
1327         case kRoleDetached:
1328             break;
1329 
1330         case kRoleChild:
1331             if (sourceAddress == mParent.GetRloc16())
1332             {
1333                 processRouteTlv = true;
1334             }
1335             else
1336             {
1337                 router = mRouterTable.GetRouter(routerId);
1338 
1339                 if (router != nullptr && router->IsStateValid())
1340                 {
1341                     processRouteTlv = true;
1342                 }
1343             }
1344 
1345             break;
1346 
1347         case kRoleRouter:
1348         case kRoleLeader:
1349             processRouteTlv = true;
1350             break;
1351         }
1352 
1353         if (processRouteTlv)
1354         {
1355             SuccessOrExit(error = ProcessRouteTlv(aRxInfo));
1356         }
1357     }
1358 
1359     switch (mRole)
1360     {
1361     case kRoleDisabled:
1362     case kRoleDetached:
1363         ExitNow();
1364 
1365     case kRoleChild:
1366         if (aRxInfo.mNeighbor == &mParent)
1367         {
1368             // MLE Advertisement from parent
1369             router = &mParent;
1370 
1371             if (mParent.GetRloc16() != sourceAddress)
1372             {
1373                 IgnoreError(BecomeDetached());
1374                 ExitNow(error = kErrorDetached);
1375             }
1376 
1377             if (IsFullThreadDevice())
1378             {
1379                 Router *leader;
1380 
1381                 if ((mRouterSelectionJitterTimeout == 0) &&
1382                     (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
1383                 {
1384                     mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
1385                     ExitNow();
1386                 }
1387 
1388                 leader = mRouterTable.GetLeader();
1389 
1390                 if (leader != nullptr)
1391                 {
1392                     for (uint8_t id = 0, routeCount = 0; id <= kMaxRouterId; id++)
1393                     {
1394                         if (!route.IsRouterIdSet(id))
1395                         {
1396                             continue;
1397                         }
1398 
1399                         if (id != GetLeaderId())
1400                         {
1401                             routeCount++;
1402                             continue;
1403                         }
1404 
1405                         if (route.GetRouteCost(routeCount) > 0)
1406                         {
1407                             leader->SetNextHop(id);
1408                             leader->SetCost(route.GetRouteCost(routeCount));
1409                         }
1410                         else
1411                         {
1412                             leader->SetNextHop(kInvalidRouterId);
1413                             leader->SetCost(0);
1414                         }
1415 
1416                         break;
1417                     }
1418                 }
1419             }
1420         }
1421         else
1422         {
1423             // MLE Advertisement not from parent, but from some other neighboring router
1424             router = mRouterTable.GetRouter(routerId);
1425             VerifyOrExit(router != nullptr);
1426 
1427             if (IsFullThreadDevice() && !router->IsStateValid() && !router->IsStateLinkRequest() &&
1428                 (mRouterTable.GetActiveLinkCount() < OPENTHREAD_CONFIG_MLE_CHILD_ROUTER_LINKS))
1429             {
1430                 router->SetExtAddress(extAddr);
1431                 router->GetLinkInfo().Clear();
1432                 router->GetLinkInfo().AddRss(linkInfo->GetRss());
1433                 router->ResetLinkFailures();
1434                 router->SetLastHeard(TimerMilli::GetNow());
1435                 router->SetState(Neighbor::kStateLinkRequest);
1436                 IgnoreError(SendLinkRequest(router));
1437                 ExitNow(error = kErrorNoRoute);
1438             }
1439         }
1440 
1441         router->SetLastHeard(TimerMilli::GetNow());
1442 
1443         ExitNow();
1444 
1445     case kRoleRouter:
1446         if (mLinkRequestDelay > 0 && route.IsRouterIdSet(mRouterId))
1447         {
1448             mLinkRequestDelay = 0;
1449             IgnoreError(SendLinkRequest(nullptr));
1450         }
1451 
1452         router = mRouterTable.GetRouter(routerId);
1453         VerifyOrExit(router != nullptr);
1454 
1455         // check current active router number
1456         routerCount = 0;
1457 
1458         for (uint8_t id = 0; id <= kMaxRouterId; id++)
1459         {
1460             if (route.IsRouterIdSet(id))
1461             {
1462                 routerCount++;
1463             }
1464         }
1465 
1466         if (routerCount > mRouterDowngradeThreshold && mRouterSelectionJitterTimeout == 0 &&
1467             HasMinDowngradeNeighborRouters() && HasSmallNumberOfChildren() &&
1468             HasOneNeighborWithComparableConnectivity(route, routerId)
1469 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
1470             && !Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter()
1471 #endif
1472         )
1473         {
1474             mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
1475         }
1476 
1477         OT_FALL_THROUGH;
1478 
1479     case kRoleLeader:
1480         router = mRouterTable.GetRouter(routerId);
1481         VerifyOrExit(router != nullptr);
1482 
1483         // Send unicast link request if no link to router and no unicast/multicast link request in progress
1484         if (!router->IsStateValid() && !router->IsStateLinkRequest() && (mChallengeTimeout == 0) &&
1485             (linkMargin >= OPENTHREAD_CONFIG_MLE_LINK_REQUEST_MARGIN_MIN))
1486         {
1487             router->SetExtAddress(extAddr);
1488             router->GetLinkInfo().Clear();
1489             router->GetLinkInfo().AddRss(linkInfo->GetRss());
1490             router->ResetLinkFailures();
1491             router->SetLastHeard(TimerMilli::GetNow());
1492             router->SetState(Neighbor::kStateLinkRequest);
1493             IgnoreError(SendLinkRequest(router));
1494             ExitNow(error = kErrorNoRoute);
1495         }
1496 
1497         router->SetLastHeard(TimerMilli::GetNow());
1498         break;
1499     }
1500 
1501     UpdateRoutes(route, routerId);
1502 
1503 exit:
1504     if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != sourceAddress)
1505     {
1506         // Remove stale neighbors
1507         RemoveNeighbor(*aRxInfo.mNeighbor);
1508     }
1509 
1510     return error;
1511 }
1512 
UpdateRoutes(const RouteTlv & aRoute,uint8_t aRouterId)1513 void MleRouter::UpdateRoutes(const RouteTlv &aRoute, uint8_t aRouterId)
1514 {
1515     Router *neighbor;
1516     bool    resetAdvInterval = false;
1517     bool    changed          = false;
1518 
1519     neighbor = mRouterTable.GetRouter(aRouterId);
1520     VerifyOrExit(neighbor != nullptr);
1521 
1522     // update link quality out to neighbor
1523     changed = UpdateLinkQualityOut(aRoute, *neighbor, resetAdvInterval);
1524 
1525     // update routes
1526     for (uint8_t routerId = 0, routeCount = 0; routerId <= kMaxRouterId; routerId++)
1527     {
1528         Router *router;
1529         Router *nextHop;
1530         uint8_t oldNextHop;
1531         uint8_t cost;
1532 
1533         if (!aRoute.IsRouterIdSet(routerId))
1534         {
1535             continue;
1536         }
1537 
1538         router = mRouterTable.GetRouter(routerId);
1539 
1540         if (router == nullptr || router->GetRloc16() == GetRloc16() || router == neighbor)
1541         {
1542             routeCount++;
1543             continue;
1544         }
1545 
1546         oldNextHop = router->GetNextHop();
1547         nextHop    = mRouterTable.GetRouter(oldNextHop);
1548 
1549         cost = aRoute.GetRouteCost(routeCount);
1550 
1551         if (cost == 0)
1552         {
1553             cost = kMaxRouteCost;
1554         }
1555 
1556         if (nextHop == nullptr || nextHop == neighbor)
1557         {
1558             // router has no next hop or next hop is neighbor (sender)
1559 
1560             if (cost + mRouterTable.GetLinkCost(*neighbor) < kMaxRouteCost)
1561             {
1562                 if (nextHop == nullptr && mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
1563                 {
1564                     resetAdvInterval = true;
1565                 }
1566 
1567                 if (router->GetNextHop() != aRouterId)
1568                 {
1569                     router->SetNextHop(aRouterId);
1570                     changed = true;
1571                 }
1572 
1573                 if (router->GetCost() != cost)
1574                 {
1575                     router->SetCost(cost);
1576                     changed = true;
1577                 }
1578             }
1579             else if (nextHop == neighbor)
1580             {
1581                 if (mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
1582                 {
1583                     resetAdvInterval = true;
1584                 }
1585 
1586                 router->SetNextHop(kInvalidRouterId);
1587                 router->SetCost(0);
1588                 router->SetLastHeard(TimerMilli::GetNow());
1589                 changed = true;
1590             }
1591         }
1592         else
1593         {
1594             uint8_t curCost = router->GetCost() + mRouterTable.GetLinkCost(*nextHop);
1595             uint8_t newCost = cost + mRouterTable.GetLinkCost(*neighbor);
1596 
1597             if (newCost < curCost)
1598             {
1599                 router->SetNextHop(aRouterId);
1600                 router->SetCost(cost);
1601                 changed = true;
1602             }
1603         }
1604 
1605         routeCount++;
1606     }
1607 
1608     if (resetAdvInterval)
1609     {
1610         ResetAdvertiseInterval();
1611     }
1612 
1613 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1614 
1615     VerifyOrExit(changed);
1616     LogInfo("Route table updated");
1617 
1618     for (Router &router : Get<RouterTable>().Iterate())
1619     {
1620         LogInfo("    %04x -> %04x, cost:%d %d, lqin:%d, lqout:%d, link:%s", router.GetRloc16(),
1621                 (router.GetNextHop() == kInvalidRouterId) ? 0xffff : Rloc16FromRouterId(router.GetNextHop()),
1622                 router.GetCost(), mRouterTable.GetLinkCost(router), router.GetLinkInfo().GetLinkQuality(),
1623                 router.GetLinkQualityOut(),
1624                 router.GetRloc16() == GetRloc16() ? "device" : ToYesNo(router.IsStateValid()));
1625     }
1626 
1627 #else
1628     OT_UNUSED_VARIABLE(changed);
1629 #endif
1630 
1631 exit:
1632     return;
1633 }
1634 
UpdateLinkQualityOut(const RouteTlv & aRoute,Router & aNeighbor,bool & aResetAdvInterval)1635 bool MleRouter::UpdateLinkQualityOut(const RouteTlv &aRoute, Router &aNeighbor, bool &aResetAdvInterval)
1636 {
1637     bool        changed = false;
1638     LinkQuality linkQuality;
1639     uint8_t     myRouterId;
1640     uint8_t     myRouteCount;
1641     uint8_t     oldLinkCost;
1642     Router *    nextHop;
1643 
1644     myRouterId = RouterIdFromRloc16(GetRloc16());
1645     VerifyOrExit(aRoute.IsRouterIdSet(myRouterId));
1646 
1647     myRouteCount = 0;
1648     for (uint8_t routerId = 0; routerId < myRouterId; routerId++)
1649     {
1650         myRouteCount += aRoute.IsRouterIdSet(routerId);
1651     }
1652 
1653     linkQuality = aRoute.GetLinkQualityIn(myRouteCount);
1654     VerifyOrExit(aNeighbor.GetLinkQualityOut() != linkQuality);
1655 
1656     oldLinkCost = mRouterTable.GetLinkCost(aNeighbor);
1657 
1658     aNeighbor.SetLinkQualityOut(linkQuality);
1659     nextHop = mRouterTable.GetRouter(aNeighbor.GetNextHop());
1660 
1661     // reset MLE advertisement timer if neighbor route cost changed to or from infinite
1662     if (nextHop == nullptr && (oldLinkCost >= kMaxRouteCost) != (mRouterTable.GetLinkCost(aNeighbor) >= kMaxRouteCost))
1663     {
1664         aResetAdvInterval = true;
1665     }
1666     changed = true;
1667 
1668 exit:
1669     return changed;
1670 }
1671 
HandleParentRequest(RxInfo & aRxInfo)1672 void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
1673 {
1674     Error           error = kErrorNone;
1675     Mac::ExtAddress extAddr;
1676     uint16_t        version;
1677     uint8_t         scanMask;
1678     Challenge       challenge;
1679     Router *        leader;
1680     Child *         child;
1681     uint8_t         modeBitmask;
1682     DeviceMode      mode;
1683 
1684     Log(kMessageReceive, kTypeParentRequest, aRxInfo.mMessageInfo.GetPeerAddr());
1685 
1686     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
1687 
1688     // A Router/REED MUST NOT send an MLE Parent Response if:
1689 
1690     // 0. It is detached or attempting to another partition
1691     VerifyOrExit(!IsDetached() && !IsAttaching(), error = kErrorDrop);
1692 
1693     // 1. It has no available Child capacity (if Max Child Count minus
1694     // Child Count would be equal to zero)
1695     // ==> verified below when allocating a child entry
1696 
1697     // 2. It is disconnected from its Partition (that is, it has not
1698     // received an updated ID sequence number within LEADER_TIMEOUT
1699     // seconds)
1700     VerifyOrExit(mRouterTable.GetLeaderAge() < mNetworkIdTimeout, error = kErrorDrop);
1701 
1702     // 3. Its current routing path cost to the Leader is infinite.
1703     leader = mRouterTable.GetLeader();
1704     OT_ASSERT(leader != nullptr);
1705 
1706     VerifyOrExit(IsLeader() || GetLinkCost(GetLeaderId()) < kMaxRouteCost ||
1707                      (IsChild() && leader->GetCost() + 1 < kMaxRouteCost) ||
1708                      (leader->GetCost() + GetLinkCost(leader->GetNextHop()) < kMaxRouteCost),
1709                  error = kErrorDrop);
1710 
1711     // 4. It is a REED and there are already `kMaxRouters` active routers in
1712     // the network (because Leader would reject any further address solicit).
1713     // ==> Verified below when checking the scan mask.
1714 
1715     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
1716 
1717     // Version
1718     SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
1719     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = kErrorParse);
1720 
1721     // Scan Mask
1722     SuccessOrExit(error = Tlv::Find<ScanMaskTlv>(aRxInfo.mMessage, scanMask));
1723 
1724     switch (mRole)
1725     {
1726     case kRoleDisabled:
1727     case kRoleDetached:
1728         ExitNow();
1729 
1730     case kRoleChild:
1731         VerifyOrExit(ScanMaskTlv::IsEndDeviceFlagSet(scanMask));
1732         VerifyOrExit(mRouterTable.GetActiveRouterCount() < kMaxRouters, error = kErrorDrop);
1733         break;
1734 
1735     case kRoleRouter:
1736     case kRoleLeader:
1737         VerifyOrExit(ScanMaskTlv::IsRouterFlagSet(scanMask));
1738         break;
1739     }
1740 
1741     // Challenge
1742     SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
1743 
1744     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
1745 
1746     if (child == nullptr)
1747     {
1748         VerifyOrExit((child = mChildTable.GetNewChild()) != nullptr, error = kErrorNoBufs);
1749 
1750         // MAC Address
1751         child->SetExtAddress(extAddr);
1752         child->GetLinkInfo().Clear();
1753         child->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
1754         child->ResetLinkFailures();
1755         child->SetState(Neighbor::kStateParentRequest);
1756 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1757         child->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
1758 #endif
1759         if (Tlv::Find<ModeTlv>(aRxInfo.mMessage, modeBitmask) == kErrorNone)
1760         {
1761             mode.Set(modeBitmask);
1762             child->SetDeviceMode(mode);
1763             child->SetVersion(static_cast<uint8_t>(version));
1764         }
1765     }
1766     else if (TimerMilli::GetNow() - child->GetLastHeard() < kParentRequestRouterTimeout - kParentRequestDuplicateMargin)
1767     {
1768         ExitNow(error = kErrorDuplicated);
1769     }
1770 
1771     if (!child->IsStateValidOrRestoring())
1772     {
1773         child->SetLastHeard(TimerMilli::GetNow());
1774         child->SetTimeout(Time::MsecToSec(kMaxChildIdRequestTimeout));
1775     }
1776 
1777     aRxInfo.mClass = RxInfo::kPeerMessage;
1778 
1779     SendParentResponse(child, challenge, !ScanMaskTlv::IsEndDeviceFlagSet(scanMask));
1780 
1781 exit:
1782     LogProcessError(kTypeParentRequest, error);
1783 }
1784 
HasNeighborWithGoodLinkQuality(void) const1785 bool MleRouter::HasNeighborWithGoodLinkQuality(void) const
1786 {
1787     bool    haveNeighbor = true;
1788     uint8_t linkMargin;
1789 
1790     linkMargin =
1791         LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(), mParent.GetLinkInfo().GetLastRss());
1792 
1793     if (linkMargin >= OPENTHREAD_CONFIG_MLE_LINK_REQUEST_MARGIN_MIN)
1794     {
1795         ExitNow();
1796     }
1797 
1798     for (Router &router : Get<RouterTable>().Iterate())
1799     {
1800         if (!router.IsStateValid())
1801         {
1802             continue;
1803         }
1804 
1805         linkMargin =
1806             LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(), router.GetLinkInfo().GetLastRss());
1807 
1808         if (linkMargin >= OPENTHREAD_CONFIG_MLE_LINK_REQUEST_MARGIN_MIN)
1809         {
1810             ExitNow();
1811         }
1812     }
1813 
1814     haveNeighbor = false;
1815 
1816 exit:
1817     return haveNeighbor;
1818 }
1819 
HandleTimeTick(void)1820 void MleRouter::HandleTimeTick(void)
1821 {
1822     bool routerStateUpdate = false;
1823 
1824     VerifyOrExit(IsFullThreadDevice(), Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter));
1825 
1826     if (mLinkRequestDelay > 0 && --mLinkRequestDelay == 0)
1827     {
1828         IgnoreError(SendLinkRequest(nullptr));
1829     }
1830 
1831     if (mChallengeTimeout > 0)
1832     {
1833         mChallengeTimeout--;
1834     }
1835 
1836     if (mPreviousPartitionIdTimeout > 0)
1837     {
1838         mPreviousPartitionIdTimeout--;
1839     }
1840 
1841     if (mRouterSelectionJitterTimeout > 0)
1842     {
1843         mRouterSelectionJitterTimeout--;
1844 
1845         if (mRouterSelectionJitterTimeout == 0)
1846         {
1847             routerStateUpdate = true;
1848         }
1849     }
1850 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
1851     // Delay register only when `mRouterSelectionJitterTimeout` is 0,
1852     // that is, when the device has decided to stay as REED or Router.
1853     else if (mBackboneRouterRegistrationDelay > 0)
1854     {
1855         mBackboneRouterRegistrationDelay--;
1856 
1857         if (mBackboneRouterRegistrationDelay == 0)
1858         {
1859             // If no Backbone Router service after jitter, try to register its own Backbone Router Service.
1860             if (!Get<BackboneRouter::Leader>().HasPrimary())
1861             {
1862                 if (Get<BackboneRouter::Local>().AddService() == kErrorNone)
1863                 {
1864                     Get<NetworkData::Notifier>().HandleServerDataUpdated();
1865                 }
1866             }
1867         }
1868     }
1869 #endif
1870 
1871     switch (mRole)
1872     {
1873     case kRoleDisabled:
1874         OT_ASSERT(false);
1875         OT_UNREACHABLE_CODE(break);
1876 
1877     case kRoleDetached:
1878         if (mChallengeTimeout == 0)
1879         {
1880             IgnoreError(BecomeDetached());
1881             ExitNow();
1882         }
1883 
1884         break;
1885 
1886     case kRoleChild:
1887         if (routerStateUpdate)
1888         {
1889             if (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality())
1890             {
1891                 // upgrade to Router
1892                 IgnoreError(BecomeRouter(ThreadStatusTlv::kTooFewRouters));
1893             }
1894             else
1895             {
1896                 // send announce after decided to stay in REED if needed
1897                 InformPreviousChannel();
1898             }
1899 
1900             if (!mAdvertiseTrickleTimer.IsRunning())
1901             {
1902                 SendAdvertisement();
1903 
1904                 mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, Time::SecToMsec(kReedAdvertiseInterval),
1905                                              Time::SecToMsec(kReedAdvertiseInterval + kReedAdvertiseJitter));
1906             }
1907 
1908             ExitNow();
1909         }
1910 
1911         OT_FALL_THROUGH;
1912 
1913     case kRoleRouter:
1914         // verify path to leader
1915         LogDebg("network id timeout = %d", mRouterTable.GetLeaderAge());
1916 
1917         if ((mRouterTable.GetActiveRouterCount() > 0) && (mRouterTable.GetLeaderAge() >= mNetworkIdTimeout))
1918         {
1919             LogInfo("Router ID Sequence timeout");
1920             Attach(kSamePartition);
1921         }
1922 
1923         if (routerStateUpdate && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
1924         {
1925             LogNote("Downgrade to REED");
1926             Attach(kDowngradeToReed);
1927         }
1928 
1929         break;
1930 
1931     case kRoleLeader:
1932         break;
1933     }
1934 
1935     // update children state
1936     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
1937     {
1938         uint32_t timeout = 0;
1939 
1940         switch (child.GetState())
1941         {
1942         case Neighbor::kStateInvalid:
1943         case Neighbor::kStateChildIdRequest:
1944             continue;
1945 
1946         case Neighbor::kStateParentRequest:
1947         case Neighbor::kStateValid:
1948         case Neighbor::kStateRestored:
1949         case Neighbor::kStateChildUpdateRequest:
1950             timeout = Time::SecToMsec(child.GetTimeout());
1951             break;
1952 
1953         case Neighbor::kStateParentResponse:
1954         case Neighbor::kStateLinkRequest:
1955             OT_ASSERT(false);
1956             OT_UNREACHABLE_CODE(break);
1957         }
1958 
1959 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1960         if (child.IsCslSynchronized() &&
1961             TimerMilli::GetNow() - child.GetCslLastHeard() >= Time::SecToMsec(child.GetCslTimeout()))
1962         {
1963             LogInfo("Child CSL synchronization expired");
1964             child.SetCslSynchronized(false);
1965             Get<CslTxScheduler>().Update();
1966         }
1967 #endif
1968 
1969         if (TimerMilli::GetNow() - child.GetLastHeard() >= timeout)
1970         {
1971             LogInfo("Child timeout expired");
1972             RemoveNeighbor(child);
1973         }
1974         else if (IsRouterOrLeader() && child.IsStateRestored())
1975         {
1976             IgnoreError(SendChildUpdateRequest(child));
1977         }
1978     }
1979 
1980     // update router state
1981     for (Router &router : Get<RouterTable>().Iterate())
1982     {
1983         uint32_t age;
1984 
1985         if (router.GetRloc16() == GetRloc16())
1986         {
1987             router.SetLastHeard(TimerMilli::GetNow());
1988             continue;
1989         }
1990 
1991         age = TimerMilli::GetNow() - router.GetLastHeard();
1992 
1993         if (router.IsStateValid())
1994         {
1995 #if OPENTHREAD_CONFIG_MLE_SEND_LINK_REQUEST_ON_ADV_TIMEOUT == 0
1996 
1997             if (age >= Time::SecToMsec(kMaxNeighborAge))
1998             {
1999                 LogInfo("Router timeout expired");
2000                 RemoveNeighbor(router);
2001                 continue;
2002             }
2003 
2004 #else
2005 
2006             if (age >= Time::SecToMsec(kMaxNeighborAge))
2007             {
2008                 if (age < Time::SecToMsec(kMaxNeighborAge) + kMaxTransmissionCount * kUnicastRetransmissionDelay)
2009                 {
2010                     LogInfo("Router timeout expired");
2011                     IgnoreError(SendLinkRequest(&router));
2012                 }
2013                 else
2014                 {
2015                     RemoveNeighbor(router);
2016                     continue;
2017                 }
2018             }
2019 
2020 #endif
2021         }
2022         else if (router.IsStateLinkRequest())
2023         {
2024             if (age >= kMaxLinkRequestTimeout)
2025             {
2026                 LogInfo("Link Request timeout expired");
2027                 RemoveNeighbor(router);
2028                 continue;
2029             }
2030         }
2031 
2032         if (IsLeader())
2033         {
2034             if (mRouterTable.GetRouter(router.GetNextHop()) == nullptr &&
2035                 mRouterTable.GetLinkCost(router) >= kMaxRouteCost && age >= Time::SecToMsec(kMaxLeaderToRouterTimeout))
2036             {
2037                 LogInfo("Router ID timeout expired (no route)");
2038                 IgnoreError(mRouterTable.Release(router.GetRouterId()));
2039             }
2040         }
2041     }
2042 
2043     mRouterTable.HandleTimeTick();
2044 
2045     SynchronizeChildNetworkData();
2046 
2047 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2048     if (IsRouterOrLeader())
2049     {
2050         Get<TimeSync>().ProcessTimeSync();
2051     }
2052 #endif
2053 
2054 exit:
2055     return;
2056 }
2057 
SendParentResponse(Child * aChild,const Challenge & aChallenge,bool aRoutersOnlyRequest)2058 void MleRouter::SendParentResponse(Child *aChild, const Challenge &aChallenge, bool aRoutersOnlyRequest)
2059 {
2060     Error        error = kErrorNone;
2061     Ip6::Address destination;
2062     TxMessage *  message;
2063     uint16_t     delay;
2064 
2065     VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs);
2066     message->SetDirectTransmission();
2067 
2068     SuccessOrExit(error = message->AppendSourceAddressTlv());
2069     SuccessOrExit(error = message->AppendLeaderDataTlv());
2070     SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
2071     SuccessOrExit(error = message->AppendMleFrameCounterTlv());
2072     SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
2073 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2074     if (aChild->IsTimeSyncEnabled())
2075     {
2076         SuccessOrExit(error = message->AppendTimeParameterTlv());
2077     }
2078 #endif
2079 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2080     if (aChild->IsThreadVersionCslCapable())
2081     {
2082         SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
2083     }
2084 #endif
2085 
2086     aChild->GenerateChallenge();
2087 
2088     SuccessOrExit(error = message->AppendChallengeTlv(aChild->GetChallenge(), aChild->GetChallengeSize()));
2089     error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin());
2090     SuccessOrExit(error);
2091 
2092     SuccessOrExit(error = message->AppendConnectivityTlv());
2093     SuccessOrExit(error = message->AppendVersionTlv());
2094 
2095     destination.SetToLinkLocalAddress(aChild->GetExtAddress());
2096 
2097     if (aRoutersOnlyRequest)
2098     {
2099         delay = 1 + Random::NonCrypto::GetUint16InRange(0, kParentResponseMaxDelayRouters);
2100     }
2101     else
2102     {
2103         delay = 1 + Random::NonCrypto::GetUint16InRange(0, kParentResponseMaxDelayAll);
2104     }
2105 
2106     SuccessOrExit(error = message->SendAfterDelay(destination, delay));
2107 
2108     Log(kMessageDelay, kTypeParentResponse, destination);
2109 
2110 exit:
2111     FreeMessageOnError(message, error);
2112     LogSendError(kTypeParentResponse, error);
2113 }
2114 
GetMaxChildIpAddresses(void) const2115 uint8_t MleRouter::GetMaxChildIpAddresses(void) const
2116 {
2117     uint8_t num = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD;
2118 
2119 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2120     if (mMaxChildIpAddresses != 0)
2121     {
2122         num = mMaxChildIpAddresses;
2123     }
2124 #endif
2125 
2126     return num;
2127 }
2128 
2129 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)2130 Error MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)
2131 {
2132     Error error = kErrorNone;
2133 
2134     VerifyOrExit(aMaxIpAddresses <= OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD, error = kErrorInvalidArgs);
2135 
2136     mMaxChildIpAddresses = aMaxIpAddresses;
2137 
2138 exit:
2139     return error;
2140 }
2141 #endif
2142 
UpdateChildAddresses(const Message & aMessage,uint16_t aOffset,Child & aChild)2143 Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Child &aChild)
2144 {
2145     Error                    error = kErrorNone;
2146     AddressRegistrationEntry entry;
2147     Ip6::Address             address;
2148     Lowpan::Context          context;
2149     Tlv                      tlv;
2150     uint8_t                  registeredCount = 0;
2151     uint8_t                  storedCount     = 0;
2152     uint16_t                 offset          = 0;
2153     uint16_t                 end             = 0;
2154 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2155     Ip6::Address        oldDua;
2156     const Ip6::Address *oldDuaPtr = nullptr;
2157     bool                hasDua    = false;
2158 #endif
2159 
2160 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2161     Ip6::Address oldMlrRegisteredAddresses[OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1];
2162     uint16_t     oldMlrRegisteredAddressNum = 0;
2163 #endif
2164 
2165     SuccessOrExit(error = aMessage.Read(aOffset, tlv));
2166     VerifyOrExit(tlv.GetLength() <= (aMessage.GetLength() - aOffset - sizeof(tlv)), error = kErrorParse);
2167 
2168     offset = aOffset + sizeof(tlv);
2169     end    = offset + tlv.GetLength();
2170 
2171 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2172     if ((oldDuaPtr = aChild.GetDomainUnicastAddress()) != nullptr)
2173     {
2174         oldDua = *oldDuaPtr;
2175     }
2176 #endif
2177 
2178 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2179     // Retrieve registered multicast addresses of the Child
2180     if (aChild.HasAnyMlrRegisteredAddress())
2181     {
2182         OT_ASSERT(aChild.IsStateValid());
2183 
2184         for (const Ip6::Address &childAddress :
2185              aChild.IterateIp6Addresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal))
2186         {
2187             if (aChild.GetAddressMlrState(childAddress) == kMlrStateRegistered)
2188             {
2189                 oldMlrRegisteredAddresses[oldMlrRegisteredAddressNum++] = childAddress;
2190             }
2191         }
2192     }
2193 #endif
2194 
2195     aChild.ClearIp6Addresses();
2196 
2197     while (offset < end)
2198     {
2199         uint8_t len;
2200 
2201         // read out the control field
2202         SuccessOrExit(error = aMessage.Read(offset, &entry, sizeof(uint8_t)));
2203 
2204         len = entry.GetLength();
2205 
2206         SuccessOrExit(error = aMessage.Read(offset, &entry, len));
2207 
2208         offset += len;
2209         registeredCount++;
2210 
2211         if (entry.IsCompressed())
2212         {
2213             if (Get<NetworkData::Leader>().GetContext(entry.GetContextId(), context) != kErrorNone)
2214             {
2215                 LogWarn("Failed to get context %d for compressed address from child 0x%04x", entry.GetContextId(),
2216                         aChild.GetRloc16());
2217                 continue;
2218             }
2219 
2220             address.Clear();
2221             address.SetPrefix(context.mPrefix);
2222             address.SetIid(entry.GetIid());
2223         }
2224         else
2225         {
2226             address = entry.GetIp6Address();
2227         }
2228 
2229 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2230         if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
2231         {
2232             // Skip remaining address registration entries but keep logging skipped addresses.
2233             error = kErrorNoBufs;
2234         }
2235         else
2236 #endif
2237         {
2238             // We try to accept/add as many IPv6 addresses as possible.
2239             // "Child ID/Update Response" will indicate the accepted
2240             // addresses.
2241             error = aChild.AddIp6Address(address);
2242         }
2243 
2244         if (error == kErrorNone)
2245         {
2246             storedCount++;
2247 
2248 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2249             if (Get<BackboneRouter::Leader>().IsDomainUnicast(address))
2250             {
2251                 hasDua = true;
2252 
2253                 if (oldDuaPtr != nullptr)
2254                 {
2255                     Get<DuaManager>().UpdateChildDomainUnicastAddress(
2256                         aChild, oldDua != address ? ChildDuaState::kChanged : ChildDuaState::kUnchanged);
2257                 }
2258                 else
2259                 {
2260                     Get<DuaManager>().UpdateChildDomainUnicastAddress(aChild, ChildDuaState::kAdded);
2261                 }
2262             }
2263 #endif
2264 
2265             LogInfo("Child 0x%04x IPv6 address[%d]=%s", aChild.GetRloc16(), storedCount,
2266                     address.ToString().AsCString());
2267         }
2268         else
2269         {
2270 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2271             if (Get<BackboneRouter::Leader>().IsDomainUnicast(address))
2272             {
2273                 // if not able to store DUA, then assume child does not have one
2274                 hasDua = false;
2275             }
2276 #endif
2277 
2278             LogWarn("Error %s adding IPv6 address %s to child 0x%04x", ErrorToString(error),
2279                     address.ToString().AsCString(), aChild.GetRloc16());
2280         }
2281 
2282         if (address.IsMulticast())
2283         {
2284             continue;
2285         }
2286 
2287         // We check if the same address is in-use by another child, if so
2288         // remove it. This implements "last-in wins" duplicate address
2289         // resolution policy.
2290         //
2291         // Duplicate addresses can occur if a previously attached child
2292         // attaches to same parent again (after a reset, memory wipe) using
2293         // a new random extended address before the old entry in the child
2294         // table is timed out and then trying to register its globally unique
2295         // IPv6 address as the new child.
2296 
2297         for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
2298         {
2299             if (&child == &aChild)
2300             {
2301                 continue;
2302             }
2303 
2304             IgnoreError(child.RemoveIp6Address(address));
2305         }
2306 
2307         // Clear EID-to-RLOC cache for the unicast address registered by the child.
2308         Get<AddressResolver>().Remove(address);
2309     }
2310 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2311     // Dua is removed
2312     if (oldDuaPtr != nullptr && !hasDua)
2313     {
2314         Get<DuaManager>().UpdateChildDomainUnicastAddress(aChild, ChildDuaState::kRemoved);
2315     }
2316 #endif
2317 
2318 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2319     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses, oldMlrRegisteredAddressNum);
2320 #endif
2321 
2322     if (registeredCount == 0)
2323     {
2324         LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
2325     }
2326     else
2327     {
2328         LogInfo("Child 0x%04x has %d registered IPv6 address%s, %d address%s stored", aChild.GetRloc16(),
2329                 registeredCount, (registeredCount == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
2330     }
2331 
2332     error = kErrorNone;
2333 
2334 exit:
2335     return error;
2336 }
2337 
HandleChildIdRequest(RxInfo & aRxInfo)2338 void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
2339 {
2340     Error              error = kErrorNone;
2341     Mac::ExtAddress    extAddr;
2342     uint16_t           version;
2343     Challenge          response;
2344     uint32_t           linkFrameCounter;
2345     uint32_t           mleFrameCounter;
2346     uint8_t            modeBitmask;
2347     DeviceMode         mode;
2348     uint32_t           timeout;
2349     RequestedTlvs      requestedTlvs;
2350     MeshCoP::Timestamp timestamp;
2351     bool               needsActiveDatasetTlv;
2352     bool               needsPendingDatasetTlv;
2353     Child *            child;
2354     Router *           router;
2355     uint8_t            numTlvs;
2356     uint16_t           addressRegistrationOffset = 0;
2357 
2358     Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2359 
2360     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2361 
2362     // only process message when operating as a child, router, or leader
2363     VerifyOrExit(IsAttached(), error = kErrorInvalidState);
2364 
2365     // Find Child
2366     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2367 
2368     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2369     VerifyOrExit(child != nullptr, error = kErrorAlready);
2370 
2371     // Version
2372     SuccessOrExit(error = Tlv::Find<VersionTlv>(aRxInfo.mMessage, version));
2373     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = kErrorParse);
2374 
2375     // Response
2376     SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
2377     VerifyOrExit(response.Matches(child->GetChallenge(), child->GetChallengeSize()), error = kErrorSecurity);
2378 
2379     // Remove existing MLE messages
2380     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleGeneral);
2381     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildIdRequest);
2382     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildUpdateRequest);
2383     Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleDataResponse);
2384 
2385     // Link-Layer and MLE Frame Counters
2386     SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
2387 
2388     // Mode
2389     SuccessOrExit(error = Tlv::Find<ModeTlv>(aRxInfo.mMessage, modeBitmask));
2390     mode.Set(modeBitmask);
2391 
2392     // Timeout
2393     SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
2394 
2395     // TLV Request
2396     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs));
2397     VerifyOrExit(requestedTlvs.mNumTlvs <= Child::kMaxRequestTlvs, error = kErrorParse);
2398 
2399     // Active Timestamp
2400     needsActiveDatasetTlv = true;
2401     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2402     {
2403     case kErrorNone:
2404         needsActiveDatasetTlv =
2405             (MeshCoP::Timestamp::Compare(&timestamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()) != 0);
2406         break;
2407     case kErrorNotFound:
2408         break;
2409     default:
2410         ExitNow(error = kErrorParse);
2411     }
2412 
2413     // Pending Timestamp
2414     needsPendingDatasetTlv = true;
2415     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2416     {
2417     case kErrorNone:
2418         needsPendingDatasetTlv =
2419             (MeshCoP::Timestamp::Compare(&timestamp, Get<MeshCoP::PendingDatasetManager>().GetTimestamp()) != 0);
2420         break;
2421     case kErrorNotFound:
2422         break;
2423     default:
2424         ExitNow(error = kErrorParse);
2425     }
2426 
2427     if (!mode.IsFullThreadDevice())
2428     {
2429         SuccessOrExit(error =
2430                           Tlv::FindTlvOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addressRegistrationOffset));
2431         SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addressRegistrationOffset, *child));
2432     }
2433 
2434     // Remove from router table
2435     router = mRouterTable.GetRouter(extAddr);
2436     if (router != nullptr)
2437     {
2438         // The `router` here can be invalid
2439         RemoveNeighbor(*router);
2440     }
2441 
2442     if (!child->IsStateValid())
2443     {
2444         child->SetState(Neighbor::kStateChildIdRequest);
2445     }
2446     else
2447     {
2448         RemoveNeighbor(*child);
2449     }
2450 
2451     child->SetLastHeard(TimerMilli::GetNow());
2452     child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2453     child->SetLinkAckFrameCounter(linkFrameCounter);
2454     child->SetMleFrameCounter(mleFrameCounter);
2455     child->SetKeySequence(aRxInfo.mKeySequence);
2456     child->SetDeviceMode(mode);
2457     child->SetVersion(static_cast<uint8_t>(version));
2458     child->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
2459     child->SetTimeout(timeout);
2460 #if OPENTHREAD_CONFIG_MULTI_RADIO
2461     child->ClearLastRxFragmentTag();
2462 #endif
2463 
2464     child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType()));
2465     child->ClearRequestTlvs();
2466 
2467     for (numTlvs = 0; numTlvs < requestedTlvs.mNumTlvs; numTlvs++)
2468     {
2469         child->SetRequestTlv(numTlvs, requestedTlvs.mTlvs[numTlvs]);
2470     }
2471 
2472     if (needsActiveDatasetTlv)
2473     {
2474         child->SetRequestTlv(numTlvs++, Tlv::kActiveDataset);
2475     }
2476 
2477     if (needsPendingDatasetTlv)
2478     {
2479         child->SetRequestTlv(numTlvs++, Tlv::kPendingDataset);
2480     }
2481 
2482     aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
2483 
2484     switch (mRole)
2485     {
2486     case kRoleDisabled:
2487     case kRoleDetached:
2488         OT_ASSERT(false);
2489         OT_UNREACHABLE_CODE(break);
2490 
2491     case kRoleChild:
2492         child->SetState(Neighbor::kStateChildIdRequest);
2493         IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
2494         break;
2495 
2496     case kRoleRouter:
2497     case kRoleLeader:
2498         SuccessOrExit(error = SendChildIdResponse(*child));
2499         break;
2500     }
2501 
2502 exit:
2503     LogProcessError(kTypeChildIdRequest, error);
2504 }
2505 
HandleChildUpdateRequest(RxInfo & aRxInfo)2506 void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
2507 {
2508     static const uint8_t kMaxResponseTlvs = 10;
2509 
2510     Error           error = kErrorNone;
2511     Mac::ExtAddress extAddr;
2512     uint8_t         modeBitmask;
2513     DeviceMode      mode;
2514     Challenge       challenge;
2515     LeaderData      leaderData;
2516     uint32_t        timeout;
2517     Child *         child;
2518     DeviceMode      oldMode;
2519     RequestedTlvs   requestedTlvs;
2520     uint8_t         tlvs[kMaxResponseTlvs];
2521     uint8_t         tlvslength                = 0;
2522     uint16_t        addressRegistrationOffset = 0;
2523     bool            childDidChange            = false;
2524 
2525     Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
2526 
2527     // Mode
2528     SuccessOrExit(error = Tlv::Find<ModeTlv>(aRxInfo.mMessage, modeBitmask));
2529     mode.Set(modeBitmask);
2530 
2531     // Challenge
2532     switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
2533     {
2534     case kErrorNone:
2535         tlvs[tlvslength++] = Tlv::kResponse;
2536         break;
2537     case kErrorNotFound:
2538         challenge.mLength = 0;
2539         break;
2540     default:
2541         ExitNow(error = kErrorParse);
2542     }
2543 
2544     tlvs[tlvslength++] = Tlv::kSourceAddress;
2545 
2546     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2547     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2548 
2549     if (child == nullptr)
2550     {
2551         // For invalid non-sleepy child, send Child Update Response with
2552         // Status TLV (error).
2553         if (mode.IsRxOnWhenIdle())
2554         {
2555             tlvs[tlvslength++] = Tlv::kStatus;
2556             SendChildUpdateResponse(nullptr, aRxInfo.mMessageInfo, tlvs, tlvslength, challenge);
2557         }
2558 
2559         ExitNow();
2560     }
2561 
2562     // Ignore "Child Update Request" from a child that is present in the
2563     // child table but it is not yet in valid state. For example, a
2564     // child which is being restored (due to parent reset) or is in the
2565     // middle of the attach process (in `kStateParentRequest` or
2566     // `kStateChildIdRequest`).
2567 
2568     VerifyOrExit(child->IsStateValid());
2569 
2570     oldMode = child->GetDeviceMode();
2571     child->SetDeviceMode(mode);
2572 
2573     tlvs[tlvslength++] = Tlv::kMode;
2574 
2575     // Parent MUST include Leader Data TLV in Child Update Response
2576     tlvs[tlvslength++] = Tlv::kLeaderData;
2577 
2578     if (challenge.mLength != 0)
2579     {
2580         tlvs[tlvslength++] = Tlv::kMleFrameCounter;
2581         tlvs[tlvslength++] = Tlv::kLinkFrameCounter;
2582     }
2583 
2584     // IPv6 Address TLV
2585     if (Tlv::FindTlvOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addressRegistrationOffset) == kErrorNone)
2586     {
2587         SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addressRegistrationOffset, *child));
2588         tlvs[tlvslength++] = Tlv::kAddressRegistration;
2589     }
2590 
2591     // Leader Data
2592     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2593     {
2594     case kErrorNone:
2595         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2596         break;
2597     case kErrorNotFound:
2598         break;
2599     default:
2600         ExitNow(error = kErrorParse);
2601     }
2602 
2603     // Timeout
2604     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2605     {
2606     case kErrorNone:
2607         if (child->GetTimeout() != timeout)
2608         {
2609             child->SetTimeout(timeout);
2610             childDidChange = true;
2611         }
2612 
2613         tlvs[tlvslength++] = Tlv::kTimeout;
2614         break;
2615 
2616     case kErrorNotFound:
2617         break;
2618 
2619     default:
2620         ExitNow(error = kErrorParse);
2621     }
2622 
2623     // TLV Request
2624     switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs))
2625     {
2626     case kErrorNone:
2627         VerifyOrExit(requestedTlvs.mNumTlvs <= (kMaxResponseTlvs - tlvslength), error = kErrorParse);
2628         for (uint8_t i = 0; i < requestedTlvs.mNumTlvs; i++)
2629         {
2630             // Skip LeaderDataTlv since it is already included by default.
2631             if (requestedTlvs.mTlvs[i] != Tlv::kLeaderData)
2632             {
2633                 tlvs[tlvslength++] = requestedTlvs.mTlvs[i];
2634             }
2635         }
2636         break;
2637     case kErrorNotFound:
2638         break;
2639     default:
2640         ExitNow(error = kErrorParse);
2641     }
2642 
2643 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2644     if (child->IsCslSynchronized())
2645     {
2646         CslChannelTlv cslChannel;
2647         uint32_t      cslTimeout;
2648 
2649         if (Tlv::Find<CslTimeoutTlv>(aRxInfo.mMessage, cslTimeout) == kErrorNone)
2650         {
2651             child->SetCslTimeout(cslTimeout);
2652             // MUST include CSL accuracy TLV when request includes CSL timeout
2653             tlvs[tlvslength++] = Tlv::kCslClockAccuracy;
2654         }
2655 
2656         if (Tlv::FindTlv(aRxInfo.mMessage, cslChannel) == kErrorNone)
2657         {
2658             child->SetCslChannel(static_cast<uint8_t>(cslChannel.GetChannel()));
2659         }
2660         else
2661         {
2662             // Set CSL Channel unspecified.
2663             child->SetCslChannel(0);
2664         }
2665     }
2666 #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2667 
2668     child->SetLastHeard(TimerMilli::GetNow());
2669 
2670     if (oldMode != child->GetDeviceMode())
2671     {
2672         LogNote("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
2673                 child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
2674 
2675         childDidChange = true;
2676 
2677 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2678         if (child->IsRxOnWhenIdle())
2679         {
2680             // Clear CSL synchronization state
2681             child->SetCslSynchronized(false);
2682         }
2683 #endif
2684 
2685         // The `IndirectSender::HandleChildModeChange()` needs to happen
2686         // after "Child Update" message is fully parsed to ensure that
2687         // any registered IPv6 addresses included in the "Child Update"
2688         // are added to the child.
2689 
2690         Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
2691     }
2692 
2693     if (childDidChange)
2694     {
2695         IgnoreError(mChildTable.StoreChild(*child));
2696     }
2697 
2698 #if OPENTHREAD_CONFIG_MULTI_RADIO
2699     // We clear the fragment tag only if the "Child Update Request" is
2700     // from a detached child trying to restore its link with its
2701     // parent which is indicated by the presence of Challenge TLV in
2702     // the message.
2703     if (challenge.mLength != 0)
2704     {
2705         child->ClearLastRxFragmentTag();
2706     }
2707 #endif
2708 
2709     SendChildUpdateResponse(child, aRxInfo.mMessageInfo, tlvs, tlvslength, challenge);
2710 
2711     aRxInfo.mClass = RxInfo::kPeerMessage;
2712 
2713 exit:
2714     LogProcessError(kTypeChildUpdateRequestOfChild, error);
2715 }
2716 
HandleChildUpdateResponse(RxInfo & aRxInfo)2717 void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
2718 {
2719     Error      error = kErrorNone;
2720     uint16_t   sourceAddress;
2721     uint32_t   timeout;
2722     Challenge  response;
2723     uint8_t    status;
2724     uint32_t   linkFrameCounter;
2725     uint32_t   mleFrameCounter;
2726     LeaderData leaderData;
2727     Child *    child;
2728     uint16_t   addressRegistrationOffset = 0;
2729 
2730     if ((aRxInfo.mNeighbor == nullptr) || IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()))
2731     {
2732         Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr());
2733         ExitNow(error = kErrorNotFound);
2734     }
2735 
2736     child = static_cast<Child *>(aRxInfo.mNeighbor);
2737 
2738     // Response
2739     switch (aRxInfo.mMessage.ReadResponseTlv(response))
2740     {
2741     case kErrorNone:
2742         VerifyOrExit(response.Matches(child->GetChallenge(), child->GetChallengeSize()), error = kErrorSecurity);
2743         break;
2744     case kErrorNotFound:
2745         VerifyOrExit(child->IsStateValid(), error = kErrorSecurity);
2746         response.mLength = 0;
2747         break;
2748     default:
2749         ExitNow(error = kErrorNone);
2750     }
2751 
2752     Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
2753 
2754     // Source Address
2755     switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
2756     {
2757     case kErrorNone:
2758         if (child->GetRloc16() != sourceAddress)
2759         {
2760             RemoveNeighbor(*child);
2761             ExitNow();
2762         }
2763 
2764         break;
2765 
2766     case kErrorNotFound:
2767         break;
2768 
2769     default:
2770         ExitNow(error = kErrorParse);
2771     }
2772 
2773     // Status
2774     switch (Tlv::Find<ThreadStatusTlv>(aRxInfo.mMessage, status))
2775     {
2776     case kErrorNone:
2777         VerifyOrExit(status != StatusTlv::kError, RemoveNeighbor(*child));
2778         break;
2779     case kErrorNotFound:
2780         break;
2781     default:
2782         ExitNow(error = kErrorParse);
2783     }
2784 
2785     // Link-Layer Frame Counter
2786 
2787     switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
2788     {
2789     case kErrorNone:
2790         child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2791         child->SetLinkAckFrameCounter(linkFrameCounter);
2792         break;
2793     case kErrorNotFound:
2794         break;
2795     default:
2796         ExitNow(error = kErrorParse);
2797     }
2798 
2799     // MLE Frame Counter
2800     switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
2801     {
2802     case kErrorNone:
2803         child->SetMleFrameCounter(mleFrameCounter);
2804         break;
2805     case kErrorNotFound:
2806         break;
2807     default:
2808         ExitNow(error = kErrorNone);
2809     }
2810 
2811     // Timeout
2812     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2813     {
2814     case kErrorNone:
2815         child->SetTimeout(timeout);
2816         break;
2817     case kErrorNotFound:
2818         break;
2819     default:
2820         ExitNow(error = kErrorParse);
2821     }
2822 
2823     // IPv6 Address
2824     if (Tlv::FindTlvOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addressRegistrationOffset) == kErrorNone)
2825     {
2826         SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addressRegistrationOffset, *child));
2827     }
2828 
2829     // Leader Data
2830     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2831     {
2832     case kErrorNone:
2833         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2834         break;
2835     case kErrorNotFound:
2836         break;
2837     default:
2838         ExitNow(error = kErrorParse);
2839     }
2840 
2841     SetChildStateToValid(*child);
2842     child->SetLastHeard(TimerMilli::GetNow());
2843     child->SetKeySequence(aRxInfo.mKeySequence);
2844     child->GetLinkInfo().AddRss(aRxInfo.mMessageInfo.GetThreadLinkInfo()->GetRss());
2845 
2846     aRxInfo.mClass = (response.mLength == 0) ? RxInfo::kPeerMessage : RxInfo::kAuthoritativeMessage;
2847 
2848 exit:
2849     LogProcessError(kTypeChildUpdateResponseOfChild, error);
2850 }
2851 
HandleDataRequest(RxInfo & aRxInfo)2852 void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
2853 {
2854     Error              error = kErrorNone;
2855     RequestedTlvs      requestedTlvs;
2856     MeshCoP::Timestamp timestamp;
2857     uint8_t            tlvs[4];
2858     uint8_t            numTlvs;
2859 
2860     Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2861 
2862     VerifyOrExit(aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid(), error = kErrorSecurity);
2863 
2864     // TLV Request
2865     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvs));
2866     VerifyOrExit(requestedTlvs.mNumTlvs <= sizeof(tlvs), error = kErrorParse);
2867 
2868     memset(tlvs, Tlv::kInvalid, sizeof(tlvs));
2869     memcpy(tlvs, requestedTlvs.mTlvs, requestedTlvs.mNumTlvs);
2870     numTlvs = requestedTlvs.mNumTlvs;
2871 
2872     // Active Timestamp
2873     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2874     {
2875     case kErrorNone:
2876         if (MeshCoP::Timestamp::Compare(&timestamp, Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()) == 0)
2877         {
2878             break;
2879         }
2880 
2881         OT_FALL_THROUGH;
2882 
2883     case kErrorNotFound:
2884         tlvs[numTlvs++] = Tlv::kActiveDataset;
2885         break;
2886 
2887     default:
2888         ExitNow(error = kErrorParse);
2889     }
2890 
2891     // Pending Timestamp
2892     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2893     {
2894     case kErrorNone:
2895         if (MeshCoP::Timestamp::Compare(&timestamp, Get<MeshCoP::PendingDatasetManager>().GetTimestamp()) == 0)
2896         {
2897             break;
2898         }
2899 
2900         OT_FALL_THROUGH;
2901 
2902     case kErrorNotFound:
2903         tlvs[numTlvs++] = Tlv::kPendingDataset;
2904         break;
2905 
2906     default:
2907         ExitNow(error = kErrorParse);
2908     }
2909 
2910     aRxInfo.mClass = RxInfo::kPeerMessage;
2911 
2912     SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvs, numTlvs, 0, &aRxInfo.mMessage);
2913 
2914 exit:
2915     LogProcessError(kTypeDataRequest, error);
2916 }
2917 
HandleNetworkDataUpdateRouter(void)2918 void MleRouter::HandleNetworkDataUpdateRouter(void)
2919 {
2920     static const uint8_t tlvs[] = {Tlv::kNetworkData};
2921     Ip6::Address         destination;
2922     uint16_t             delay;
2923 
2924     VerifyOrExit(IsRouterOrLeader());
2925 
2926     destination.SetToLinkLocalAllNodesMulticast();
2927 
2928     delay = IsLeader() ? 0 : Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter);
2929     SendDataResponse(destination, tlvs, sizeof(tlvs), delay);
2930 
2931     SynchronizeChildNetworkData();
2932 
2933 exit:
2934     return;
2935 }
2936 
SynchronizeChildNetworkData(void)2937 void MleRouter::SynchronizeChildNetworkData(void)
2938 {
2939     VerifyOrExit(IsRouterOrLeader());
2940 
2941     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
2942     {
2943         if (child.IsRxOnWhenIdle())
2944         {
2945             continue;
2946         }
2947 
2948         if (child.GetNetworkDataVersion() == Get<NetworkData::Leader>().GetVersion(child.GetNetworkDataType()))
2949         {
2950             continue;
2951         }
2952 
2953         SuccessOrExit(SendChildUpdateRequest(child));
2954     }
2955 
2956 exit:
2957     return;
2958 }
2959 
2960 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
SetSteeringData(const Mac::ExtAddress * aExtAddress)2961 void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress)
2962 {
2963     Mac::ExtAddress nullExtAddr;
2964     Mac::ExtAddress allowAnyExtAddr;
2965 
2966     nullExtAddr.Clear();
2967     allowAnyExtAddr.Fill(0xff);
2968 
2969     if ((aExtAddress == nullptr) || (*aExtAddress == nullExtAddr))
2970     {
2971         mSteeringData.Clear();
2972     }
2973     else if (*aExtAddress == allowAnyExtAddr)
2974     {
2975         mSteeringData.SetToPermitAllJoiners();
2976     }
2977     else
2978     {
2979         Mac::ExtAddress joinerId;
2980 
2981         mSteeringData.Init();
2982         MeshCoP::ComputeJoinerId(*aExtAddress, joinerId);
2983         mSteeringData.UpdateBloomFilter(joinerId);
2984     }
2985 }
2986 #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2987 
HandleDiscoveryRequest(RxInfo & aRxInfo)2988 void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
2989 {
2990     Error                        error = kErrorNone;
2991     Tlv                          tlv;
2992     MeshCoP::Tlv                 meshcopTlv;
2993     MeshCoP::DiscoveryRequestTlv discoveryRequest;
2994     MeshCoP::ExtendedPanId       extPanId;
2995     uint16_t                     offset;
2996     uint16_t                     end;
2997 
2998     Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2999 
3000     discoveryRequest.SetLength(0);
3001 
3002     // only Routers and REEDs respond
3003     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
3004 
3005     // find MLE Discovery TLV
3006     VerifyOrExit(Tlv::FindTlvOffset(aRxInfo.mMessage, Tlv::kDiscovery, offset) == kErrorNone, error = kErrorParse);
3007     IgnoreError(aRxInfo.mMessage.Read(offset, tlv));
3008 
3009     offset += sizeof(tlv);
3010     end = offset + sizeof(tlv) + tlv.GetLength();
3011 
3012     while (offset < end)
3013     {
3014         IgnoreError(aRxInfo.mMessage.Read(offset, meshcopTlv));
3015 
3016         switch (meshcopTlv.GetType())
3017         {
3018         case MeshCoP::Tlv::kDiscoveryRequest:
3019             IgnoreError(aRxInfo.mMessage.Read(offset, discoveryRequest));
3020             VerifyOrExit(discoveryRequest.IsValid(), error = kErrorParse);
3021 
3022             break;
3023 
3024         case MeshCoP::Tlv::kExtendedPanId:
3025             SuccessOrExit(error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offset, extPanId));
3026             VerifyOrExit(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId() != extPanId, error = kErrorDrop);
3027 
3028             break;
3029 
3030         default:
3031             break;
3032         }
3033 
3034         offset += sizeof(meshcopTlv) + meshcopTlv.GetLength();
3035     }
3036 
3037     if (discoveryRequest.IsValid())
3038     {
3039         if (mDiscoveryRequestCallback != nullptr)
3040         {
3041             otThreadDiscoveryRequestInfo info;
3042 
3043             aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&info.mExtAddress));
3044             info.mVersion  = discoveryRequest.GetVersion();
3045             info.mIsJoiner = discoveryRequest.IsJoiner();
3046 
3047             mDiscoveryRequestCallback(&info, mDiscoveryRequestCallbackContext);
3048         }
3049 
3050         if (discoveryRequest.IsJoiner())
3051         {
3052 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
3053             if (!mSteeringData.IsEmpty())
3054             {
3055             }
3056             else // if steering data is not set out of band, fall back to network data
3057 #endif
3058             {
3059                 VerifyOrExit(Get<NetworkData::Leader>().IsJoiningEnabled(), error = kErrorSecurity);
3060             }
3061         }
3062     }
3063 
3064     error = SendDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), aRxInfo.mMessage);
3065 
3066 exit:
3067     LogProcessError(kTypeDiscoveryRequest, error);
3068 }
3069 
SendDiscoveryResponse(const Ip6::Address & aDestination,const Message & aDiscoverRequestMessage)3070 Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage)
3071 {
3072     Error                         error = kErrorNone;
3073     TxMessage *                   message;
3074     uint16_t                      startOffset;
3075     Tlv                           tlv;
3076     MeshCoP::DiscoveryResponseTlv discoveryResponse;
3077     MeshCoP::NetworkNameTlv       networkName;
3078     uint16_t                      delay;
3079 
3080     VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
3081     message->SetPanId(aDiscoverRequestMessage.GetPanId());
3082 #if OPENTHREAD_CONFIG_MULTI_RADIO
3083     // Send the MLE Discovery Response message on same radio link
3084     // from which the "MLE Discover Request" message was received.
3085     message->SetRadioType(aDiscoverRequestMessage.GetRadioType());
3086 #endif
3087 
3088     // Discovery TLV
3089     tlv.SetType(Tlv::kDiscovery);
3090     SuccessOrExit(error = message->Append(tlv));
3091 
3092     startOffset = message->GetLength();
3093 
3094     // Discovery Response TLV
3095     discoveryResponse.Init();
3096     discoveryResponse.SetVersion(kThreadVersion);
3097 
3098 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
3099     if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled)
3100     {
3101         SuccessOrExit(
3102             error = Tlv::Append<MeshCoP::CommissionerUdpPortTlv>(*message, Get<MeshCoP::BorderAgent>().GetUdpPort()));
3103 
3104         discoveryResponse.SetNativeCommissioner(true);
3105     }
3106     else
3107 #endif
3108     {
3109         discoveryResponse.SetNativeCommissioner(false);
3110     }
3111 
3112     if (Get<KeyManager>().GetSecurityPolicy().mCommercialCommissioningEnabled)
3113     {
3114         discoveryResponse.SetCommercialCommissioningMode(true);
3115     }
3116 
3117     SuccessOrExit(error = discoveryResponse.AppendTo(*message));
3118 
3119     // Extended PAN ID TLV
3120     SuccessOrExit(
3121         error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
3122 
3123     // Network Name TLV
3124     networkName.Init();
3125     networkName.SetNetworkName(Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsData());
3126     SuccessOrExit(error = networkName.AppendTo(*message));
3127 
3128 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
3129     // If steering data is set out of band, use that value.
3130     // Otherwise use the one from commissioning data.
3131     if (!mSteeringData.IsEmpty())
3132     {
3133         SuccessOrExit(error = Tlv::Append<MeshCoP::SteeringDataTlv>(*message, mSteeringData.GetData(),
3134                                                                     mSteeringData.GetLength()));
3135     }
3136     else
3137 #endif
3138     {
3139         const MeshCoP::Tlv *steeringData;
3140 
3141         steeringData = Get<NetworkData::Leader>().GetCommissioningDataSubTlv(MeshCoP::Tlv::kSteeringData);
3142 
3143         if (steeringData != nullptr)
3144         {
3145             SuccessOrExit(error = steeringData->AppendTo(*message));
3146         }
3147     }
3148 
3149     SuccessOrExit(
3150         error = Tlv::Append<MeshCoP::JoinerUdpPortTlv>(*message, Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()));
3151 
3152     tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
3153     message->Write(startOffset - sizeof(tlv), tlv);
3154 
3155     delay = Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter + 1);
3156 
3157     SuccessOrExit(error = message->SendAfterDelay(aDestination, delay));
3158 
3159     Log(kMessageDelay, kTypeDiscoveryResponse, aDestination);
3160 
3161 exit:
3162     FreeMessageOnError(message, error);
3163     LogProcessError(kTypeDiscoveryResponse, error);
3164     return error;
3165 }
3166 
SendChildIdResponse(Child & aChild)3167 Error MleRouter::SendChildIdResponse(Child &aChild)
3168 {
3169     Error        error = kErrorNone;
3170     Ip6::Address destination;
3171     TxMessage *  message;
3172 
3173     VerifyOrExit((message = NewMleMessage(kCommandChildIdResponse)) != nullptr, error = kErrorNoBufs);
3174     SuccessOrExit(error = message->AppendSourceAddressTlv());
3175     SuccessOrExit(error = message->AppendLeaderDataTlv());
3176     SuccessOrExit(error = message->AppendActiveTimestampTlv());
3177     SuccessOrExit(error = message->AppendPendingTimestampTlv());
3178 
3179     if ((aChild.GetRloc16() == 0) || !RouterIdMatch(aChild.GetRloc16(), GetRloc16()))
3180     {
3181         uint16_t rloc16;
3182 
3183         // pick next Child ID that is not being used
3184         do
3185         {
3186             mNextChildId++;
3187 
3188             if (mNextChildId > kMaxChildId)
3189             {
3190                 mNextChildId = kMinChildId;
3191             }
3192 
3193             rloc16 = Get<Mac::Mac>().GetShortAddress() | mNextChildId;
3194 
3195         } while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
3196 
3197         // allocate Child ID
3198         aChild.SetRloc16(rloc16);
3199     }
3200 
3201     SuccessOrExit(error = message->AppendAddress16Tlv(aChild.GetRloc16()));
3202 
3203     for (uint8_t i = 0; i < Child::kMaxRequestTlvs; i++)
3204     {
3205         switch (aChild.GetRequestTlv(i))
3206         {
3207         case Tlv::kNetworkData:
3208             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
3209             break;
3210 
3211         case Tlv::kRoute:
3212             SuccessOrExit(error = message->AppendRouteTlv());
3213             break;
3214 
3215         case Tlv::kActiveDataset:
3216             SuccessOrExit(error = message->AppendActiveDatasetTlv());
3217             break;
3218 
3219         case Tlv::kPendingDataset:
3220             SuccessOrExit(error = message->AppendPendingDatasetTlv());
3221             break;
3222 
3223         default:
3224             break;
3225         }
3226     }
3227 
3228     if (!aChild.IsFullThreadDevice())
3229     {
3230         SuccessOrExit(error = message->AppendAddresseRegisterationTlv(aChild));
3231     }
3232 
3233     SetChildStateToValid(aChild);
3234 
3235     if (!aChild.IsRxOnWhenIdle())
3236     {
3237         Get<IndirectSender>().SetChildUseShortAddress(aChild, false);
3238     }
3239 
3240 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3241     if (aChild.IsTimeSyncEnabled())
3242     {
3243         message->SetTimeSync(true);
3244     }
3245 #endif
3246 
3247     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
3248     SuccessOrExit(error = message->SendTo(destination));
3249 
3250     Log(kMessageSend, kTypeChildIdResponse, destination, aChild.GetRloc16());
3251 
3252 exit:
3253     FreeMessageOnError(message, error);
3254     return error;
3255 }
3256 
SendChildUpdateRequest(Child & aChild)3257 Error MleRouter::SendChildUpdateRequest(Child &aChild)
3258 {
3259     static const uint8_t tlvs[] = {Tlv::kTimeout, Tlv::kAddressRegistration};
3260     Error                error  = kErrorNone;
3261     Ip6::Address         destination;
3262     TxMessage *          message = nullptr;
3263 
3264     if (!aChild.IsRxOnWhenIdle())
3265     {
3266         uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
3267 
3268         for (const Message &msg : Get<MeshForwarder>().GetSendQueue())
3269         {
3270             if (msg.GetChildMask(childIndex) && msg.GetSubType() == Message::kSubTypeMleChildUpdateRequest)
3271             {
3272                 // No need to send the resync "Child Update Request" to the sleepy child
3273                 // if there is one already queued.
3274                 if (aChild.IsStateRestoring())
3275                 {
3276                     ExitNow();
3277                 }
3278 
3279                 // Remove queued outdated "Child Update Request" when there is newer Network Data is to send.
3280                 Get<MeshForwarder>().RemoveMessages(aChild, Message::kSubTypeMleChildUpdateRequest);
3281                 break;
3282             }
3283         }
3284     }
3285 
3286     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
3287     SuccessOrExit(error = message->AppendSourceAddressTlv());
3288     SuccessOrExit(error = message->AppendLeaderDataTlv());
3289     SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
3290     SuccessOrExit(error = message->AppendActiveTimestampTlv());
3291     SuccessOrExit(error = message->AppendPendingTimestampTlv());
3292 
3293     if (!aChild.IsStateValid())
3294     {
3295         SuccessOrExit(error = message->AppendTlvRequestTlv(tlvs, sizeof(tlvs)));
3296         aChild.GenerateChallenge();
3297         SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge(), aChild.GetChallengeSize()));
3298     }
3299 
3300     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
3301     SuccessOrExit(error = message->SendTo(destination));
3302 
3303     if (aChild.IsRxOnWhenIdle())
3304     {
3305         // only try to send a single Child Update Request message to an rx-on-when-idle child
3306         aChild.SetState(Child::kStateChildUpdateRequest);
3307     }
3308 
3309     Log(kMessageSend, kTypeChildUpdateRequestOfChild, destination, aChild.GetRloc16());
3310 
3311 exit:
3312     FreeMessageOnError(message, error);
3313     return error;
3314 }
3315 
SendChildUpdateResponse(Child * aChild,const Ip6::MessageInfo & aMessageInfo,const uint8_t * aTlvs,uint8_t aTlvsLength,const Challenge & aChallenge)3316 void MleRouter::SendChildUpdateResponse(Child *                 aChild,
3317                                         const Ip6::MessageInfo &aMessageInfo,
3318                                         const uint8_t *         aTlvs,
3319                                         uint8_t                 aTlvsLength,
3320                                         const Challenge &       aChallenge)
3321 {
3322     Error      error = kErrorNone;
3323     TxMessage *message;
3324 
3325     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs);
3326 
3327     for (int i = 0; i < aTlvsLength; i++)
3328     {
3329         switch (aTlvs[i])
3330         {
3331         case Tlv::kStatus:
3332             SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError));
3333             break;
3334 
3335         case Tlv::kAddressRegistration:
3336             SuccessOrExit(error = message->AppendAddresseRegisterationTlv(*aChild));
3337             break;
3338 
3339         case Tlv::kLeaderData:
3340             SuccessOrExit(error = message->AppendLeaderDataTlv());
3341             break;
3342 
3343         case Tlv::kMode:
3344             SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode()));
3345             break;
3346 
3347         case Tlv::kNetworkData:
3348             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild->GetNetworkDataType()));
3349             SuccessOrExit(error = message->AppendActiveTimestampTlv());
3350             SuccessOrExit(error = message->AppendPendingTimestampTlv());
3351             break;
3352 
3353         case Tlv::kResponse:
3354             SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
3355             break;
3356 
3357         case Tlv::kSourceAddress:
3358             SuccessOrExit(error = message->AppendSourceAddressTlv());
3359             break;
3360 
3361         case Tlv::kTimeout:
3362             SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
3363             break;
3364 
3365         case Tlv::kMleFrameCounter:
3366             SuccessOrExit(error = message->AppendMleFrameCounterTlv());
3367             break;
3368 
3369         case Tlv::kLinkFrameCounter:
3370             SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
3371             break;
3372 
3373 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
3374         case Tlv::kCslClockAccuracy:
3375             if (!aChild->IsRxOnWhenIdle())
3376             {
3377                 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
3378             }
3379             break;
3380 #endif
3381         }
3382     }
3383 
3384     SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
3385 
3386     if (aChild == nullptr)
3387     {
3388         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr());
3389     }
3390     else
3391     {
3392         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr(), aChild->GetRloc16());
3393     }
3394 
3395 exit:
3396     FreeMessageOnError(message, error);
3397 }
3398 
SendDataResponse(const Ip6::Address & aDestination,const uint8_t * aTlvs,uint8_t aTlvsLength,uint16_t aDelay,const Message * aRequestMessage)3399 void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
3400                                  const uint8_t *     aTlvs,
3401                                  uint8_t             aTlvsLength,
3402                                  uint16_t            aDelay,
3403                                  const Message *     aRequestMessage)
3404 {
3405     OT_UNUSED_VARIABLE(aRequestMessage);
3406 
3407     Error      error   = kErrorNone;
3408     TxMessage *message = nullptr;
3409     Neighbor * neighbor;
3410 
3411     if (mRetrieveNewNetworkData)
3412     {
3413         LogInfo("Suppressing Data Response - waiting for new network data");
3414         ExitNow();
3415     }
3416 
3417     VerifyOrExit((message = NewMleMessage(kCommandDataResponse)) != nullptr, error = kErrorNoBufs);
3418     SuccessOrExit(error = message->AppendSourceAddressTlv());
3419     SuccessOrExit(error = message->AppendLeaderDataTlv());
3420     SuccessOrExit(error = message->AppendActiveTimestampTlv());
3421     SuccessOrExit(error = message->AppendPendingTimestampTlv());
3422 
3423     for (int i = 0; i < aTlvsLength; i++)
3424     {
3425         switch (aTlvs[i])
3426         {
3427         case Tlv::kNetworkData:
3428             neighbor = mNeighborTable.FindNeighbor(aDestination);
3429             SuccessOrExit(error = message->AppendNetworkDataTlv((neighbor != nullptr) ? neighbor->GetNetworkDataType()
3430                                                                                       : NetworkData::kFullSet));
3431             break;
3432 
3433         case Tlv::kActiveDataset:
3434             SuccessOrExit(error = message->AppendActiveDatasetTlv());
3435             break;
3436 
3437         case Tlv::kPendingDataset:
3438             SuccessOrExit(error = message->AppendPendingDatasetTlv());
3439             break;
3440 
3441 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3442         case Tlv::kLinkMetricsReport:
3443             OT_ASSERT(aRequestMessage != nullptr);
3444             neighbor = mNeighborTable.FindNeighbor(aDestination);
3445             VerifyOrExit(neighbor != nullptr, error = kErrorInvalidState);
3446             SuccessOrExit(error = Get<LinkMetrics::LinkMetrics>().AppendReport(*message, *aRequestMessage, *neighbor));
3447             break;
3448 #endif
3449         }
3450     }
3451 
3452     if (aDelay)
3453     {
3454         // Remove MLE Data Responses from Send Message Queue.
3455         Get<MeshForwarder>().RemoveDataResponseMessages();
3456 
3457         // Remove multicast MLE Data Response from Delayed Message Queue.
3458         RemoveDelayedDataResponseMessage();
3459 
3460         SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay));
3461         Log(kMessageDelay, kTypeDataResponse, aDestination);
3462     }
3463     else
3464     {
3465         SuccessOrExit(error = message->SendTo(aDestination));
3466         Log(kMessageSend, kTypeDataResponse, aDestination);
3467     }
3468 
3469 exit:
3470     FreeMessageOnError(message, error);
3471     LogSendError(kTypeDataResponse, error);
3472 }
3473 
IsMinimalChild(uint16_t aRloc16)3474 bool MleRouter::IsMinimalChild(uint16_t aRloc16)
3475 {
3476     bool rval = false;
3477 
3478     if (RouterIdFromRloc16(aRloc16) == RouterIdFromRloc16(Get<Mac::Mac>().GetShortAddress()))
3479     {
3480         Neighbor *neighbor;
3481 
3482         neighbor = mNeighborTable.FindNeighbor(aRloc16);
3483 
3484         rval = (neighbor != nullptr) && (!neighbor->IsFullThreadDevice());
3485     }
3486 
3487     return rval;
3488 }
3489 
RemoveRouterLink(Router & aRouter)3490 void MleRouter::RemoveRouterLink(Router &aRouter)
3491 {
3492     switch (mRole)
3493     {
3494     case kRoleChild:
3495         if (&aRouter == &mParent)
3496         {
3497             IgnoreError(BecomeDetached());
3498         }
3499         break;
3500 
3501 #if OPENTHREAD_FTD
3502     case kRoleRouter:
3503     case kRoleLeader:
3504         mRouterTable.RemoveRouterLink(aRouter);
3505         break;
3506 #endif
3507 
3508     default:
3509         break;
3510     }
3511 }
3512 
RemoveNeighbor(Neighbor & aNeighbor)3513 void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
3514 {
3515     VerifyOrExit(!aNeighbor.IsStateInvalid());
3516 
3517     if (&aNeighbor == &mParent)
3518     {
3519         if (IsChild())
3520         {
3521             IgnoreError(BecomeDetached());
3522         }
3523     }
3524     else if (&aNeighbor == &mParentCandidate)
3525     {
3526         mParentCandidate.Clear();
3527     }
3528     else if (!IsActiveRouter(aNeighbor.GetRloc16()))
3529     {
3530         OT_ASSERT(mChildTable.GetChildIndex(static_cast<Child &>(aNeighbor)) < kMaxChildren);
3531 
3532         if (aNeighbor.IsStateValidOrRestoring())
3533         {
3534             mNeighborTable.Signal(NeighborTable::kChildRemoved, aNeighbor);
3535         }
3536 
3537         Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
3538 
3539         if (aNeighbor.IsFullThreadDevice())
3540         {
3541             // Clear all EID-to-RLOC entries associated with the child.
3542             Get<AddressResolver>().Remove(aNeighbor.GetRloc16());
3543         }
3544 
3545         mChildTable.RemoveStoredChild(static_cast<Child &>(aNeighbor));
3546     }
3547     else if (aNeighbor.IsStateValid())
3548     {
3549         OT_ASSERT(mRouterTable.Contains(aNeighbor));
3550 
3551         mNeighborTable.Signal(NeighborTable::kRouterRemoved, aNeighbor);
3552         mRouterTable.RemoveRouterLink(static_cast<Router &>(aNeighbor));
3553     }
3554 
3555     aNeighbor.GetLinkInfo().Clear();
3556     aNeighbor.SetState(Neighbor::kStateInvalid);
3557 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3558     aNeighbor.RemoveAllForwardTrackingSeriesInfo();
3559 #endif
3560 
3561 exit:
3562     return;
3563 }
3564 
GetNextHop(uint16_t aDestination)3565 uint16_t MleRouter::GetNextHop(uint16_t aDestination)
3566 {
3567     uint8_t       destinationId = RouterIdFromRloc16(aDestination);
3568     uint8_t       routeCost;
3569     uint8_t       linkCost;
3570     uint16_t      rval = Mac::kShortAddrInvalid;
3571     const Router *router;
3572     const Router *nextHop;
3573 
3574     if (IsChild())
3575     {
3576         ExitNow(rval = Mle::GetNextHop(aDestination));
3577     }
3578 
3579     // The frame is destined to a child
3580     if (destinationId == mRouterId)
3581     {
3582         ExitNow(rval = aDestination);
3583     }
3584 
3585     router = mRouterTable.GetRouter(destinationId);
3586     VerifyOrExit(router != nullptr);
3587 
3588     linkCost  = GetLinkCost(destinationId);
3589     routeCost = GetRouteCost(aDestination);
3590 
3591     if ((routeCost + GetLinkCost(router->GetNextHop())) < linkCost)
3592     {
3593         nextHop = mRouterTable.GetRouter(router->GetNextHop());
3594         VerifyOrExit(nextHop != nullptr && !nextHop->IsStateInvalid());
3595 
3596         rval = Rloc16FromRouterId(router->GetNextHop());
3597     }
3598     else if (linkCost < kMaxRouteCost)
3599     {
3600         rval = Rloc16FromRouterId(destinationId);
3601     }
3602 
3603 exit:
3604     return rval;
3605 }
3606 
GetCost(uint16_t aRloc16)3607 uint8_t MleRouter::GetCost(uint16_t aRloc16)
3608 {
3609     uint8_t routerId = RouterIdFromRloc16(aRloc16);
3610     uint8_t cost     = GetLinkCost(routerId);
3611     Router *router   = mRouterTable.GetRouter(routerId);
3612     uint8_t routeCost;
3613 
3614     VerifyOrExit(router != nullptr && mRouterTable.GetRouter(router->GetNextHop()) != nullptr);
3615 
3616     routeCost = GetRouteCost(aRloc16) + GetLinkCost(router->GetNextHop());
3617 
3618     if (cost > routeCost)
3619     {
3620         cost = routeCost;
3621     }
3622 
3623 exit:
3624     return cost;
3625 }
3626 
GetRouteCost(uint16_t aRloc16) const3627 uint8_t MleRouter::GetRouteCost(uint16_t aRloc16) const
3628 {
3629     uint8_t       rval = kMaxRouteCost;
3630     const Router *router;
3631 
3632     router = mRouterTable.GetRouter(RouterIdFromRloc16(aRloc16));
3633     VerifyOrExit(router != nullptr && mRouterTable.GetRouter(router->GetNextHop()) != nullptr);
3634 
3635     rval = router->GetCost();
3636 
3637 exit:
3638     return rval;
3639 }
3640 
SetPreferredRouterId(uint8_t aRouterId)3641 Error MleRouter::SetPreferredRouterId(uint8_t aRouterId)
3642 {
3643     Error error = kErrorNone;
3644 
3645     VerifyOrExit(IsDetached() || IsDisabled(), error = kErrorInvalidState);
3646 
3647     mPreviousRouterId = aRouterId;
3648 
3649 exit:
3650     return error;
3651 }
3652 
SetRouterId(uint8_t aRouterId)3653 void MleRouter::SetRouterId(uint8_t aRouterId)
3654 {
3655     mRouterId         = aRouterId;
3656     mPreviousRouterId = mRouterId;
3657 }
3658 
ResolveRoutingLoops(uint16_t aSourceMac,uint16_t aDestRloc16)3659 void MleRouter::ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16)
3660 {
3661     Router *router;
3662 
3663     if (aSourceMac != GetNextHop(aDestRloc16))
3664     {
3665         ExitNow();
3666     }
3667 
3668     // loop exists
3669     router = mRouterTable.GetRouter(RouterIdFromRloc16(aDestRloc16));
3670     VerifyOrExit(router != nullptr);
3671 
3672     // invalidate next hop
3673     router->SetNextHop(kInvalidRouterId);
3674     ResetAdvertiseInterval();
3675 
3676 exit:
3677     return;
3678 }
3679 
CheckReachability(uint16_t aMeshDest,const Ip6::Header & aIp6Header)3680 Error MleRouter::CheckReachability(uint16_t aMeshDest, const Ip6::Header &aIp6Header)
3681 {
3682     Error error = kErrorNone;
3683 
3684     if (IsChild())
3685     {
3686         error = Mle::CheckReachability(aMeshDest, aIp6Header);
3687         ExitNow();
3688     }
3689 
3690     if (aMeshDest == Get<Mac::Mac>().GetShortAddress())
3691     {
3692         // mesh destination is this device
3693         if (Get<ThreadNetif>().HasUnicastAddress(aIp6Header.GetDestination()))
3694         {
3695             // IPv6 destination is this device
3696             ExitNow();
3697         }
3698         else if (mNeighborTable.FindNeighbor(aIp6Header.GetDestination()) != nullptr)
3699         {
3700             // IPv6 destination is an RFD child
3701             ExitNow();
3702         }
3703     }
3704     else if (RouterIdFromRloc16(aMeshDest) == mRouterId)
3705     {
3706         // mesh destination is a child of this device
3707         if (mChildTable.FindChild(aMeshDest, Child::kInStateValidOrRestoring))
3708         {
3709             ExitNow();
3710         }
3711     }
3712     else if (GetNextHop(aMeshDest) != Mac::kShortAddrInvalid)
3713     {
3714         // forwarding to another router and route is known
3715         ExitNow();
3716     }
3717 
3718     error = kErrorNoRoute;
3719 
3720 exit:
3721     return error;
3722 }
3723 
SendAddressSolicit(ThreadStatusTlv::Status aStatus)3724 Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
3725 {
3726     Error            error = kErrorNone;
3727     Tmf::MessageInfo messageInfo(GetInstance());
3728     Coap::Message *  message = nullptr;
3729 
3730     VerifyOrExit(!mAddressSolicitPending);
3731 
3732     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kAddressSolicit);
3733     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3734 
3735     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3736 
3737     if (IsRouterIdValid(mPreviousRouterId))
3738     {
3739         SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mPreviousRouterId)));
3740     }
3741 
3742     SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
3743 
3744 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3745     SuccessOrExit(error = Tlv::Append<XtalAccuracyTlv>(*message, otPlatTimeGetXtalAccuracy()));
3746 #endif
3747 
3748     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc());
3749 
3750     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this));
3751     mAddressSolicitPending = true;
3752 
3753     Log(kMessageSend, kTypeAddressSolicit, messageInfo.GetPeerAddr());
3754 
3755 exit:
3756     FreeMessageOnError(message, error);
3757     return error;
3758 }
3759 
SendAddressRelease(Coap::ResponseHandler aResponseHandler,void * aResponseHandlerContext)3760 void MleRouter::SendAddressRelease(Coap::ResponseHandler aResponseHandler, void *aResponseHandlerContext)
3761 {
3762     Error            error = kErrorNone;
3763     Tmf::MessageInfo messageInfo(GetInstance());
3764     Coap::Message *  message;
3765 
3766     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(UriPath::kAddressRelease);
3767     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3768 
3769     SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mRouterId)));
3770     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3771 
3772     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc());
3773 
3774     SuccessOrExit(error =
3775                       Get<Tmf::Agent>().SendMessage(*message, messageInfo, aResponseHandler, aResponseHandlerContext));
3776 
3777     Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr());
3778 
3779 exit:
3780     FreeMessageOnError(message, error);
3781     LogSendError(kTypeAddressRelease, error);
3782 }
3783 
HandleAddressSolicitResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)3784 void MleRouter::HandleAddressSolicitResponse(void *               aContext,
3785                                              otMessage *          aMessage,
3786                                              const otMessageInfo *aMessageInfo,
3787                                              Error                aResult)
3788 {
3789     static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(AsCoapMessagePtr(aMessage),
3790                                                                      AsCoreTypePtr(aMessageInfo), aResult);
3791 }
3792 
HandleAddressSolicitResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)3793 void MleRouter::HandleAddressSolicitResponse(Coap::Message *         aMessage,
3794                                              const Ip6::MessageInfo *aMessageInfo,
3795                                              Error                   aResult)
3796 {
3797     uint8_t             status;
3798     uint16_t            rloc16;
3799     ThreadRouterMaskTlv routerMaskTlv;
3800     uint8_t             routerId;
3801     Router *            router;
3802     Router *            leader;
3803 
3804     mAddressSolicitPending = false;
3805 
3806     VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
3807 
3808     VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
3809 
3810     Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
3811 
3812     SuccessOrExit(Tlv::Find<ThreadStatusTlv>(*aMessage, status));
3813 
3814     if (status != ThreadStatusTlv::kSuccess)
3815     {
3816         mAddressSolicitRejected = true;
3817 
3818         if (IsRouterIdValid(mPreviousRouterId))
3819         {
3820             if (HasChildren())
3821             {
3822                 RemoveChildren();
3823             }
3824 
3825             SetRouterId(kInvalidRouterId);
3826         }
3827 
3828         ExitNow();
3829     }
3830 
3831     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
3832     routerId = RouterIdFromRloc16(rloc16);
3833 
3834     SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
3835     VerifyOrExit(routerMaskTlv.IsValid());
3836 
3837     // assign short address
3838     SetRouterId(routerId);
3839 
3840     SetStateRouter(Rloc16FromRouterId(mRouterId));
3841     mRouterTable.Clear();
3842     mRouterTable.UpdateRouterIdSet(routerMaskTlv.GetIdSequence(), routerMaskTlv.GetAssignedRouterIdMask());
3843 
3844     router = mRouterTable.GetRouter(routerId);
3845     VerifyOrExit(router != nullptr);
3846 
3847     router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
3848     router->SetCost(0);
3849 
3850     router = mRouterTable.GetRouter(mParent.GetRouterId());
3851     VerifyOrExit(router != nullptr);
3852 
3853     // Keep link to the parent in order to respond to Parent Requests before new link is established.
3854     *router = mParent;
3855     router->SetState(Neighbor::kStateValid);
3856     router->SetNextHop(kInvalidRouterId);
3857     router->SetCost(0);
3858 
3859     leader = mRouterTable.GetLeader();
3860     OT_ASSERT(leader != nullptr);
3861 
3862     if (leader != router)
3863     {
3864         // Keep route path to the Leader reported by the parent before it is updated.
3865         leader->SetCost(mParentLeaderCost);
3866         leader->SetNextHop(RouterIdFromRloc16(mParent.GetRloc16()));
3867     }
3868 
3869     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
3870     {
3871         IgnoreError(SendChildIdResponse(child));
3872     }
3873 
3874     mLinkRequestDelay = kMulticastLinkRequestDelay;
3875 
3876 exit:
3877     // Send announce after received address solicit reply if needed
3878     InformPreviousChannel();
3879 }
3880 
IsExpectedToBecomeRouterSoon(void) const3881 bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
3882 {
3883     static constexpr uint8_t kMaxDelay = 10;
3884 
3885     return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
3886            ((GetRouterSelectionJitterTimeout() != 0 && GetRouterSelectionJitterTimeout() <= kMaxDelay) ||
3887             mAddressSolicitPending);
3888 }
3889 
HandleAddressSolicit(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)3890 void MleRouter::HandleAddressSolicit(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
3891 {
3892     static_cast<MleRouter *>(aContext)->HandleAddressSolicit(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
3893 }
3894 
HandleAddressSolicit(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3895 void MleRouter::HandleAddressSolicit(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3896 {
3897     Error                   error          = kErrorNone;
3898     ThreadStatusTlv::Status responseStatus = ThreadStatusTlv::kNoAddressAvailable;
3899     Router *                router         = nullptr;
3900     Mac::ExtAddress         extAddress;
3901     uint16_t                rloc16;
3902     uint8_t                 status;
3903 
3904     VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
3905 
3906     Log(kMessageReceive, kTypeAddressSolicit, aMessageInfo.GetPeerAddr());
3907 
3908     SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3909     SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
3910 
3911     switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
3912     {
3913     case kErrorNone:
3914         break;
3915     case kErrorNotFound:
3916         rloc16 = Mac::kShortAddrInvalid;
3917         break;
3918     default:
3919         ExitNow(error = kErrorParse);
3920     }
3921 
3922 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3923     {
3924         uint16_t xtalAccuracy;
3925 
3926         SuccessOrExit(Tlv::Find<XtalAccuracyTlv>(aMessage, xtalAccuracy));
3927         VerifyOrExit(xtalAccuracy <= Get<TimeSync>().GetXtalThreshold());
3928     }
3929 #endif
3930 
3931     // Check if allocation already exists
3932     router = mRouterTable.GetRouter(extAddress);
3933 
3934     if (router != nullptr)
3935     {
3936         responseStatus = ThreadStatusTlv::kSuccess;
3937         ExitNow();
3938     }
3939 
3940     switch (status)
3941     {
3942     case ThreadStatusTlv::kTooFewRouters:
3943         VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
3944         break;
3945 
3946     case ThreadStatusTlv::kHaveChildIdRequest:
3947     case ThreadStatusTlv::kParentPartitionChange:
3948         break;
3949 
3950     case ThreadStatusTlv::kBorderRouterRequest:
3951         if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
3952             (Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
3953              kRouterUpgradeBorderRouterRequestThreshold))
3954         {
3955             LogInfo("Rejecting BR %s router role req - have %d BR routers", extAddress.ToString().AsCString(),
3956                     kRouterUpgradeBorderRouterRequestThreshold);
3957             ExitNow();
3958         }
3959         break;
3960 
3961     default:
3962         responseStatus = ThreadStatusTlv::kUnrecognizedStatus;
3963         ExitNow();
3964     }
3965 
3966     if (rloc16 != Mac::kShortAddrInvalid)
3967     {
3968         router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16));
3969 
3970         if (router != nullptr)
3971         {
3972             LogInfo("Router id %d requested and provided!", RouterIdFromRloc16(rloc16));
3973         }
3974     }
3975 
3976     if (router == nullptr)
3977     {
3978         router = mRouterTable.Allocate();
3979         VerifyOrExit(router != nullptr);
3980     }
3981 
3982     router->SetExtAddress(extAddress);
3983     responseStatus = ThreadStatusTlv::kSuccess;
3984 
3985 exit:
3986     if (error == kErrorNone)
3987     {
3988         SendAddressSolicitResponse(aMessage, responseStatus, router, aMessageInfo);
3989     }
3990 }
3991 
SendAddressSolicitResponse(const Coap::Message & aRequest,ThreadStatusTlv::Status aResponseStatus,const Router * aRouter,const Ip6::MessageInfo & aMessageInfo)3992 void MleRouter::SendAddressSolicitResponse(const Coap::Message &   aRequest,
3993                                            ThreadStatusTlv::Status aResponseStatus,
3994                                            const Router *          aRouter,
3995                                            const Ip6::MessageInfo &aMessageInfo)
3996 {
3997     Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
3998 
3999     VerifyOrExit(message != nullptr);
4000 
4001     SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aResponseStatus));
4002 
4003     if (aRouter != nullptr)
4004     {
4005         ThreadRouterMaskTlv routerMaskTlv;
4006 
4007         SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aRouter->GetRloc16()));
4008 
4009         routerMaskTlv.Init();
4010         routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
4011         routerMaskTlv.SetAssignedRouterIdMask(mRouterTable.GetRouterIdSet());
4012 
4013         SuccessOrExit(routerMaskTlv.AppendTo(*message));
4014     }
4015 
4016     SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
4017     message = nullptr;
4018 
4019     Log(kMessageSend, kTypeAddressReply, aMessageInfo.GetPeerAddr());
4020 
4021 exit:
4022     FreeMessage(message);
4023 }
4024 
HandleAddressRelease(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)4025 void MleRouter::HandleAddressRelease(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
4026 {
4027     static_cast<MleRouter *>(aContext)->HandleAddressRelease(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
4028 }
4029 
HandleAddressRelease(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)4030 void MleRouter::HandleAddressRelease(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
4031 {
4032     uint16_t        rloc16;
4033     Mac::ExtAddress extAddress;
4034     uint8_t         routerId;
4035     Router *        router;
4036 
4037     VerifyOrExit(aMessage.IsConfirmablePostRequest());
4038 
4039     Log(kMessageReceive, kTypeAddressRelease, aMessageInfo.GetPeerAddr());
4040 
4041     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16));
4042     SuccessOrExit(Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
4043 
4044     routerId = RouterIdFromRloc16(rloc16);
4045     router   = mRouterTable.GetRouter(routerId);
4046 
4047     VerifyOrExit((router != nullptr) && (router->GetExtAddress() == extAddress));
4048 
4049     IgnoreError(mRouterTable.Release(routerId));
4050 
4051     SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
4052 
4053     Log(kMessageSend, kTypeAddressReleaseReply, aMessageInfo.GetPeerAddr());
4054 
4055 exit:
4056     return;
4057 }
4058 
FillConnectivityTlv(ConnectivityTlv & aTlv)4059 void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
4060 {
4061     Router *leader;
4062     uint8_t cost;
4063     int8_t  parentPriority = kParentPriorityMedium;
4064 
4065     if (mParentPriority != kParentPriorityUnspecified)
4066     {
4067         parentPriority = mParentPriority;
4068     }
4069     else
4070     {
4071         uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
4072         uint16_t maxAllowed  = mChildTable.GetMaxChildrenAllowed();
4073 
4074         if ((maxAllowed - numChildren) < (maxAllowed / 3))
4075         {
4076             parentPriority = kParentPriorityLow;
4077         }
4078         else
4079         {
4080             parentPriority = kParentPriorityMedium;
4081         }
4082     }
4083 
4084     aTlv.SetParentPriority(parentPriority);
4085 
4086     // compute leader cost and link qualities
4087     aTlv.SetLinkQuality1(0);
4088     aTlv.SetLinkQuality2(0);
4089     aTlv.SetLinkQuality3(0);
4090 
4091     leader = mRouterTable.GetLeader();
4092     cost   = (leader != nullptr) ? leader->GetCost() : static_cast<uint8_t>(kMaxRouteCost);
4093 
4094     switch (mRole)
4095     {
4096     case kRoleDisabled:
4097     case kRoleDetached:
4098         cost = static_cast<uint8_t>(kMaxRouteCost);
4099         break;
4100 
4101     case kRoleChild:
4102         switch (mParent.GetLinkInfo().GetLinkQuality())
4103         {
4104         case kLinkQuality0:
4105             break;
4106 
4107         case kLinkQuality1:
4108             aTlv.SetLinkQuality1(aTlv.GetLinkQuality1() + 1);
4109             break;
4110 
4111         case kLinkQuality2:
4112             aTlv.SetLinkQuality2(aTlv.GetLinkQuality2() + 1);
4113             break;
4114 
4115         case kLinkQuality3:
4116             aTlv.SetLinkQuality3(aTlv.GetLinkQuality3() + 1);
4117             break;
4118         }
4119 
4120         cost += LinkQualityToCost(mParent.GetLinkInfo().GetLinkQuality());
4121         break;
4122 
4123     case kRoleRouter:
4124         if (leader != nullptr)
4125         {
4126             cost += GetLinkCost(leader->GetNextHop());
4127 
4128             if (!IsRouterIdValid(leader->GetNextHop()) || GetLinkCost(GetLeaderId()) < cost)
4129             {
4130                 cost = GetLinkCost(GetLeaderId());
4131             }
4132         }
4133 
4134         break;
4135 
4136     case kRoleLeader:
4137         cost = 0;
4138         break;
4139     }
4140 
4141     aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
4142 
4143     for (Router &router : Get<RouterTable>().Iterate())
4144     {
4145         LinkQuality linkQuality;
4146 
4147         if (router.GetRloc16() == GetRloc16())
4148         {
4149             // skip self
4150             continue;
4151         }
4152 
4153         if (!router.IsStateValid())
4154         {
4155             // skip non-neighbor routers
4156             continue;
4157         }
4158 
4159         linkQuality = router.GetLinkInfo().GetLinkQuality();
4160 
4161         if (linkQuality > router.GetLinkQualityOut())
4162         {
4163             linkQuality = router.GetLinkQualityOut();
4164         }
4165 
4166         switch (linkQuality)
4167         {
4168         case kLinkQuality0:
4169             break;
4170 
4171         case kLinkQuality1:
4172             aTlv.SetLinkQuality1(aTlv.GetLinkQuality1() + 1);
4173             break;
4174 
4175         case kLinkQuality2:
4176             aTlv.SetLinkQuality2(aTlv.GetLinkQuality2() + 1);
4177             break;
4178 
4179         case kLinkQuality3:
4180             aTlv.SetLinkQuality3(aTlv.GetLinkQuality3() + 1);
4181             break;
4182         }
4183     }
4184 
4185     aTlv.SetLeaderCost((cost < kMaxRouteCost) ? cost : static_cast<uint8_t>(kMaxRouteCost));
4186     aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
4187     aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
4188     aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
4189 }
4190 
FillRouteTlv(RouteTlv & aTlv,Neighbor * aNeighbor)4191 void MleRouter::FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor)
4192 {
4193     uint8_t     routerIdSequence = mRouterTable.GetRouterIdSequence();
4194     RouterIdSet routerIdSet      = mRouterTable.GetRouterIdSet();
4195     uint8_t     routerCount;
4196 
4197     if (aNeighbor && IsActiveRouter(aNeighbor->GetRloc16()))
4198     {
4199         // Sending a Link Accept message that may require truncation
4200         // of Route64 TLV
4201 
4202         routerCount = mRouterTable.GetActiveRouterCount();
4203 
4204         if (routerCount > kLinkAcceptMaxRouters)
4205         {
4206             for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++)
4207             {
4208                 if (routerCount <= kLinkAcceptMaxRouters)
4209                 {
4210                     break;
4211                 }
4212 
4213                 if ((routerId == RouterIdFromRloc16(GetRloc16())) || (routerId == aNeighbor->GetRouterId()) ||
4214                     (routerId == GetLeaderId()))
4215                 {
4216                     // Route64 TLV must contain this device and the
4217                     // neighboring router to ensure that at least this
4218                     // link can be established.
4219                     continue;
4220                 }
4221 
4222                 if (routerIdSet.Contains(routerId))
4223                 {
4224                     routerIdSet.Remove(routerId);
4225                     routerCount--;
4226                 }
4227             }
4228 
4229             // Ensure that the neighbor will process the current
4230             // Route64 TLV in a subsequent message exchange
4231             routerIdSequence -= kLinkAcceptSequenceRollback;
4232         }
4233     }
4234 
4235     aTlv.SetRouterIdSequence(routerIdSequence);
4236     aTlv.SetRouterIdMask(routerIdSet);
4237 
4238     routerCount = 0;
4239 
4240     for (Router &router : Get<RouterTable>().Iterate())
4241     {
4242         if (!routerIdSet.Contains(router.GetRouterId()))
4243         {
4244             continue;
4245         }
4246 
4247         if (router.GetRloc16() == GetRloc16())
4248         {
4249             aTlv.SetLinkQualityIn(routerCount, kLinkQuality0);
4250             aTlv.SetLinkQualityOut(routerCount, kLinkQuality0);
4251             aTlv.SetRouteCost(routerCount, 1);
4252         }
4253         else
4254         {
4255             Router *nextHop;
4256             uint8_t linkCost;
4257             uint8_t routeCost;
4258 
4259             linkCost = mRouterTable.GetLinkCost(router);
4260             nextHop  = mRouterTable.GetRouter(router.GetNextHop());
4261 
4262             if (nextHop == nullptr)
4263             {
4264                 routeCost = linkCost;
4265             }
4266             else
4267             {
4268                 routeCost = router.GetCost() + mRouterTable.GetLinkCost(*nextHop);
4269 
4270                 if (linkCost < routeCost)
4271                 {
4272                     routeCost = linkCost;
4273                 }
4274             }
4275 
4276             if (routeCost >= kMaxRouteCost)
4277             {
4278                 routeCost = 0;
4279             }
4280 
4281             aTlv.SetRouteCost(routerCount, routeCost);
4282             aTlv.SetLinkQualityOut(routerCount, router.GetLinkQualityOut());
4283             aTlv.SetLinkQualityIn(routerCount, router.GetLinkInfo().GetLinkQuality());
4284         }
4285 
4286         routerCount++;
4287     }
4288 
4289     aTlv.SetRouteDataLength(routerCount);
4290 }
4291 
HasMinDowngradeNeighborRouters(void)4292 bool MleRouter::HasMinDowngradeNeighborRouters(void)
4293 {
4294     uint8_t linkQuality;
4295     uint8_t routerCount = 0;
4296 
4297     for (Router &router : Get<RouterTable>().Iterate())
4298     {
4299         if (!router.IsStateValid())
4300         {
4301             continue;
4302         }
4303 
4304         linkQuality = router.GetLinkInfo().GetLinkQuality();
4305 
4306         if (linkQuality > router.GetLinkQualityOut())
4307         {
4308             linkQuality = router.GetLinkQualityOut();
4309         }
4310 
4311         if (linkQuality >= 2)
4312         {
4313             routerCount++;
4314         }
4315     }
4316 
4317     return routerCount >= kMinDowngradeNeighbors;
4318 }
4319 
HasOneNeighborWithComparableConnectivity(const RouteTlv & aRoute,uint8_t aRouterId)4320 bool MleRouter::HasOneNeighborWithComparableConnectivity(const RouteTlv &aRoute, uint8_t aRouterId)
4321 {
4322     uint8_t routerCount = 0;
4323     bool    rval        = true;
4324 
4325     // process local neighbor routers
4326     for (Router &router : Get<RouterTable>().Iterate())
4327     {
4328         uint8_t localLinkQuality;
4329         uint8_t peerLinkQuality;
4330 
4331         if (!router.IsStateValid() || router.GetRouterId() == mRouterId || router.GetRouterId() == aRouterId)
4332         {
4333             routerCount++;
4334             continue;
4335         }
4336 
4337         localLinkQuality = router.GetLinkInfo().GetLinkQuality();
4338 
4339         if (localLinkQuality > router.GetLinkQualityOut())
4340         {
4341             localLinkQuality = router.GetLinkQualityOut();
4342         }
4343 
4344         if (localLinkQuality < 2)
4345         {
4346             routerCount++;
4347             continue;
4348         }
4349 
4350         // check if this neighbor router is in peer Route64 TLV
4351         if (!aRoute.IsRouterIdSet(router.GetRouterId()))
4352         {
4353             ExitNow(rval = false);
4354         }
4355 
4356         // get the peer's two-way link quality to this router
4357         peerLinkQuality = aRoute.GetLinkQualityIn(routerCount);
4358 
4359         if (peerLinkQuality > aRoute.GetLinkQualityOut(routerCount))
4360         {
4361             peerLinkQuality = aRoute.GetLinkQualityOut(routerCount);
4362         }
4363 
4364         // compare local link quality to this router with peer's
4365         if (peerLinkQuality >= localLinkQuality)
4366         {
4367             routerCount++;
4368             continue;
4369         }
4370 
4371         ExitNow(rval = false);
4372     }
4373 
4374 exit:
4375     return rval;
4376 }
4377 
SetChildStateToValid(Child & aChild)4378 void MleRouter::SetChildStateToValid(Child &aChild)
4379 {
4380     VerifyOrExit(!aChild.IsStateValid());
4381 
4382     aChild.SetState(Neighbor::kStateValid);
4383     IgnoreError(mChildTable.StoreChild(aChild));
4384 
4385 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
4386     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, nullptr, 0);
4387 #endif
4388 
4389     mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
4390 
4391 exit:
4392     return;
4393 }
4394 
HasChildren(void)4395 bool MleRouter::HasChildren(void)
4396 {
4397     return mChildTable.HasChildren(Child::kInStateValidOrAttaching);
4398 }
4399 
RemoveChildren(void)4400 void MleRouter::RemoveChildren(void)
4401 {
4402     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
4403     {
4404         RemoveNeighbor(child);
4405     }
4406 }
4407 
HasSmallNumberOfChildren(void)4408 bool MleRouter::HasSmallNumberOfChildren(void)
4409 {
4410     uint16_t numChildren = 0;
4411     uint8_t  routerCount = mRouterTable.GetActiveRouterCount();
4412 
4413     VerifyOrExit(routerCount > mRouterDowngradeThreshold);
4414 
4415     numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
4416 
4417     return numChildren < (routerCount - mRouterDowngradeThreshold) * 3;
4418 
4419 exit:
4420     return false;
4421 }
4422 
SetAssignParentPriority(int8_t aParentPriority)4423 Error MleRouter::SetAssignParentPriority(int8_t aParentPriority)
4424 {
4425     Error error = kErrorNone;
4426 
4427     VerifyOrExit(aParentPriority <= kParentPriorityHigh && aParentPriority >= kParentPriorityUnspecified,
4428                  error = kErrorInvalidArgs);
4429 
4430     mParentPriority = aParentPriority;
4431 
4432 exit:
4433     return error;
4434 }
4435 
GetMaxChildTimeout(uint32_t & aTimeout) const4436 Error MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
4437 {
4438     Error error = kErrorNotFound;
4439 
4440     aTimeout = 0;
4441 
4442     VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
4443 
4444     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
4445     {
4446         if (child.IsFullThreadDevice())
4447         {
4448             continue;
4449         }
4450 
4451         if (child.GetTimeout() > aTimeout)
4452         {
4453             aTimeout = child.GetTimeout();
4454         }
4455 
4456         error = kErrorNone;
4457     }
4458 
4459 exit:
4460     return error;
4461 }
4462 
4463 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
HandleTimeSync(RxInfo & aRxInfo)4464 void MleRouter::HandleTimeSync(RxInfo &aRxInfo)
4465 {
4466     Log(kMessageReceive, kTypeTimeSync, aRxInfo.mMessageInfo.GetPeerAddr());
4467 
4468     VerifyOrExit(aRxInfo.mNeighbor && aRxInfo.mNeighbor->IsStateValid());
4469 
4470     aRxInfo.mClass = RxInfo::kPeerMessage;
4471 
4472     Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
4473 
4474 exit:
4475     return;
4476 }
4477 
SendTimeSync(void)4478 Error MleRouter::SendTimeSync(void)
4479 {
4480     Error        error = kErrorNone;
4481     Ip6::Address destination;
4482     TxMessage *  message = nullptr;
4483 
4484     VerifyOrExit((message = NewMleMessage(kCommandTimeSync)) != nullptr, error = kErrorNoBufs);
4485 
4486     message->SetTimeSync(true);
4487 
4488     destination.SetToLinkLocalAllNodesMulticast();
4489     SuccessOrExit(error = message->SendTo(destination));
4490 
4491     Log(kMessageSend, kTypeTimeSync, destination);
4492 
4493 exit:
4494     FreeMessageOnError(message, error);
4495     return error;
4496 }
4497 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4498 
4499 } // namespace Mle
4500 } // namespace ot
4501 
4502 #endif // OPENTHREAD_FTD
4503