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/locator_getters.hpp"
42 #include "common/num_utils.hpp"
43 #include "common/random.hpp"
44 #include "common/serial_number.hpp"
45 #include "common/settings.hpp"
46 #include "instance/instance.hpp"
47 #include "mac/mac_types.hpp"
48 #include "meshcop/meshcop.hpp"
49 #include "net/icmp6.hpp"
50 #include "thread/key_manager.hpp"
51 #include "thread/thread_netif.hpp"
52 #include "thread/thread_tlvs.hpp"
53 #include "thread/time_sync_service.hpp"
54 #include "thread/uri_paths.hpp"
55 #include "thread/version.hpp"
56 #include "utils/otns.hpp"
57 
58 namespace ot {
59 namespace Mle {
60 
61 RegisterLogModule("Mle");
62 
MleRouter(Instance & aInstance)63 MleRouter::MleRouter(Instance &aInstance)
64     : Mle(aInstance)
65     , mAdvertiseTrickleTimer(aInstance, MleRouter::HandleAdvertiseTrickleTimer)
66     , mChildTable(aInstance)
67     , mRouterTable(aInstance)
68     , mChallengeTimeout(0)
69     , mNextChildId(kMaxChildId)
70     , mNetworkIdTimeout(kNetworkIdTimeout)
71     , mRouterUpgradeThreshold(kRouterUpgradeThreshold)
72     , mRouterDowngradeThreshold(kRouterDowngradeThreshold)
73 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
74     , mPreferredLeaderPartitionId(0)
75     , mCcmEnabled(false)
76     , mThreadVersionCheckEnabled(true)
77 #endif
78     , mRouterEligible(true)
79     , mAddressSolicitPending(false)
80     , mAddressSolicitRejected(false)
81     , mPreviousPartitionIdRouter(0)
82     , mPreviousPartitionId(0)
83     , mPreviousPartitionRouterIdSequence(0)
84     , mPreviousPartitionIdTimeout(0)
85     , mChildRouterLinks(kChildRouterLinks)
86     , mParentPriority(kParentPriorityUnspecified)
87 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
88     , mMaxChildIpAddresses(0)
89 #endif
90 {
91     mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData);
92 
93 #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
94     mLeaderWeight = mDeviceProperties.CalculateLeaderWeight();
95 #else
96     mLeaderWeight = kDefaultLeaderWeight;
97 #endif
98 
99     mLeaderAloc.InitAsThreadOriginMeshLocal();
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     if (!IsFullThreadDevice())
161     {
162         VerifyOrExit(!aEligible, error = kErrorNotCapable);
163     }
164 
165     VerifyOrExit(aEligible != mRouterEligible);
166 
167     mRouterEligible = aEligible;
168 
169     switch (mRole)
170     {
171     case kRoleDisabled:
172     case kRoleDetached:
173         break;
174 
175     case kRoleChild:
176         if (mRouterEligible)
177         {
178             mRouterRoleTransition.StartTimeout();
179         }
180 
181         Get<Mac::Mac>().SetBeaconEnabled(mRouterEligible);
182         break;
183 
184     case kRoleRouter:
185     case kRoleLeader:
186         if (!mRouterEligible)
187         {
188             IgnoreError(BecomeDetached());
189         }
190 
191         break;
192     }
193 
194 exit:
195     return error;
196 }
197 
HandleSecurityPolicyChanged(void)198 void MleRouter::HandleSecurityPolicyChanged(void)
199 {
200     // If we are currently router or leader and no longer eligible to
201     // be a router (due to security policy change), we start jitter
202     // timeout to downgrade.
203 
204     VerifyOrExit(IsRouterOrLeader() && !IsRouterEligible());
205 
206     VerifyOrExit(!mRouterRoleTransition.IsPending());
207 
208     mRouterRoleTransition.StartTimeout();
209 
210     if (IsLeader())
211     {
212         mRouterRoleTransition.IncreaseTimeout(kLeaderDowngradeExtraDelay);
213     }
214 
215 exit:
216     return;
217 }
218 
219 #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
SetDeviceProperties(const DeviceProperties & aDeviceProperties)220 void MleRouter::SetDeviceProperties(const DeviceProperties &aDeviceProperties)
221 {
222     mDeviceProperties = aDeviceProperties;
223     mDeviceProperties.ClampWeightAdjustment();
224     SetLeaderWeight(mDeviceProperties.CalculateLeaderWeight());
225 }
226 #endif
227 
BecomeRouter(ThreadStatusTlv::Status aStatus)228 Error MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
229 {
230     Error error = kErrorNone;
231 
232     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
233     VerifyOrExit(!IsRouter(), error = kErrorNone);
234     VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
235 
236     LogInfo("Attempt to become router");
237 
238     Get<MeshForwarder>().SetRxOnWhenIdle(true);
239     mRouterRoleTransition.StopTimeout();
240 
241     switch (mRole)
242     {
243     case kRoleDetached:
244         // If router had more than `kMinCriticalChildrenCount` children
245         // or was a leader prior to reset we treat the multicast Link
246         // Request as a critical message.
247         mLinkRequestAttempts =
248             (mWasLeader || mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) >= kMinCriticalChildrenCount)
249                 ? kMaxCriticalTxCount
250                 : kMaxTxCount;
251 
252         SuccessOrExit(error = SendLinkRequest(nullptr));
253         mLinkRequestAttempts--;
254         ScheduleMessageTransmissionTimer();
255         Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
256         break;
257 
258     case kRoleChild:
259         SuccessOrExit(error = SendAddressSolicit(aStatus));
260         break;
261 
262     default:
263         OT_ASSERT(false);
264     }
265 
266 exit:
267     return error;
268 }
269 
BecomeLeader(bool aCheckWeight)270 Error MleRouter::BecomeLeader(bool aCheckWeight)
271 {
272     Error    error = kErrorNone;
273     Router  *router;
274     uint32_t partitionId;
275     uint8_t  leaderId;
276 
277 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
278     VerifyOrExit(!Get<MeshCoP::ActiveDatasetManager>().IsPartiallyComplete(), error = kErrorInvalidState);
279 #else
280     VerifyOrExit(Get<MeshCoP::ActiveDatasetManager>().IsComplete(), error = kErrorInvalidState);
281 #endif
282     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
283     VerifyOrExit(!IsLeader(), error = kErrorNone);
284     VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
285 
286     if (aCheckWeight && IsAttached())
287     {
288         VerifyOrExit(mLeaderWeight > mLeaderData.GetWeighting(), error = kErrorNotCapable);
289     }
290 
291     mRouterTable.Clear();
292 
293 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
294     {
295         uint8_t minId;
296         uint8_t maxId;
297 
298         mRouterTable.GetRouterIdRange(minId, maxId);
299         partitionId = mPreferredLeaderPartitionId ? mPreferredLeaderPartitionId : Random::NonCrypto::GetUint32();
300         leaderId    = (IsRouterIdValid(mPreviousRouterId) && minId <= mPreviousRouterId && mPreviousRouterId <= maxId)
301                           ? mPreviousRouterId
302                           : Random::NonCrypto::GetUint8InRange(minId, maxId + 1);
303     }
304 #else
305     partitionId = Random::NonCrypto::GetUint32();
306     leaderId    = IsRouterIdValid(mPreviousRouterId) ? mPreviousRouterId
307                                                      : Random::NonCrypto::GetUint8InRange(0, kMaxRouterId + 1);
308 #endif
309 
310     SetLeaderData(partitionId, mLeaderWeight, leaderId);
311 
312     router = mRouterTable.Allocate(leaderId);
313     OT_ASSERT(router != nullptr);
314 
315     SetRouterId(leaderId);
316     router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
317 
318     Get<NetworkData::Leader>().Reset();
319     Get<MeshCoP::Leader>().SetEmptyCommissionerData();
320 
321     SetStateLeader(Rloc16FromRouterId(leaderId), kStartingAsLeader);
322 
323 exit:
324     return error;
325 }
326 
StopLeader(void)327 void MleRouter::StopLeader(void)
328 {
329     StopAdvertiseTrickleTimer();
330     Get<ThreadNetif>().UnsubscribeAllRoutersMulticast();
331 }
332 
HandleDetachStart(void)333 void MleRouter::HandleDetachStart(void)
334 {
335     mRouterTable.ClearNeighbors();
336     StopLeader();
337     Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter);
338 }
339 
HandleChildStart(AttachMode aMode)340 void MleRouter::HandleChildStart(AttachMode aMode)
341 {
342     mAddressSolicitRejected = false;
343 
344     mRouterRoleTransition.StartTimeout();
345 
346     StopLeader();
347     Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
348 
349     if (mRouterEligible)
350     {
351         Get<Mac::Mac>().SetBeaconEnabled(true);
352     }
353 
354     Get<ThreadNetif>().SubscribeAllRoutersMulticast();
355 
356     VerifyOrExit(IsRouterIdValid(mPreviousRouterId));
357 
358     switch (aMode)
359     {
360     case kDowngradeToReed:
361         SendAddressRelease();
362 
363         if (HasChildren())
364         {
365             RemoveChildren();
366         }
367 
368         SetRouterId(kInvalidRouterId);
369         break;
370 
371     case kSamePartition:
372         if (HasChildren())
373         {
374             IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
375         }
376 
377         break;
378 
379     case kAnyPartition:
380     case kBetterParent:
381 
382         // If attach was initiated due to receiving an MLE Announce
383         // message, all rx-on-when-idle devices will immediately
384         // attempt to attach as well. This aligns with the Thread 1.1
385         // specification (Section 4.8.1):
386         //
387         // "If the received value is newer and the channel and/or PAN
388         //  ID in the Announce message differ from those currently in
389         //  use, the receiving device attempts to attach using the
390         //  channel and PAN ID received from the Announce message."
391         //
392         // Since parent-child relationships are unlikely to persist in
393         // the new partition, we remove all children here. The
394         // decision to become router is determined based on the new
395         // partition's status.
396 
397         if (IsAnnounceAttach() && HasChildren())
398         {
399             RemoveChildren();
400         }
401 
402         OT_FALL_THROUGH;
403 
404     case kBetterPartition:
405         if (HasChildren() && mPreviousPartitionIdRouter != mLeaderData.GetPartitionId())
406         {
407             IgnoreError(BecomeRouter(ThreadStatusTlv::kParentPartitionChange));
408         }
409 
410         break;
411     }
412 
413 exit:
414 
415     if (mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold &&
416         (!IsRouterIdValid(mPreviousRouterId) || !HasChildren()))
417     {
418         SetRouterId(kInvalidRouterId);
419     }
420 }
421 
SetStateRouter(uint16_t aRloc16)422 void MleRouter::SetStateRouter(uint16_t aRloc16)
423 {
424     // The `aStartMode` is ignored when used with `kRoleRouter`
425     SetStateRouterOrLeader(kRoleRouter, aRloc16, /* aStartMode */ kStartingAsLeader);
426 }
427 
SetStateLeader(uint16_t aRloc16,LeaderStartMode aStartMode)428 void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
429 {
430     SetStateRouterOrLeader(kRoleLeader, aRloc16, aStartMode);
431 }
432 
SetStateRouterOrLeader(DeviceRole aRole,uint16_t aRloc16,LeaderStartMode aStartMode)433 void MleRouter::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStartMode aStartMode)
434 {
435     if (aRole == kRoleLeader)
436     {
437         IgnoreError(Get<MeshCoP::ActiveDatasetManager>().Restore());
438         IgnoreError(Get<MeshCoP::PendingDatasetManager>().Restore());
439     }
440 
441     SetRloc16(aRloc16);
442 
443     SetRole(aRole);
444 
445     SetAttachState(kAttachStateIdle);
446     mAttachCounter = 0;
447     mAttachTimer.Stop();
448     mMessageTransmissionTimer.Stop();
449     StopAdvertiseTrickleTimer();
450     ResetAdvertiseInterval();
451 
452     Get<ThreadNetif>().SubscribeAllRoutersMulticast();
453     mPreviousPartitionIdRouter = mLeaderData.GetPartitionId();
454     Get<Mac::Mac>().SetBeaconEnabled(true);
455 
456     if (aRole == kRoleLeader)
457     {
458         GetLeaderAloc(mLeaderAloc.GetAddress());
459         Get<ThreadNetif>().AddUnicastAddress(mLeaderAloc);
460         Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
461         Get<NetworkData::Leader>().Start(aStartMode);
462         Get<MeshCoP::ActiveDatasetManager>().StartLeader();
463         Get<MeshCoP::PendingDatasetManager>().StartLeader();
464         Get<AddressResolver>().Clear();
465     }
466 
467     // Remove children that do not have a matching RLOC16
468     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
469     {
470         if (RouterIdFromRloc16(child.GetRloc16()) != mRouterId)
471         {
472             RemoveNeighbor(child);
473         }
474     }
475 
476 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
477     Get<Mac::Mac>().UpdateCsl();
478 #endif
479 
480     LogNote("Partition ID 0x%lx", ToUlong(mLeaderData.GetPartitionId()));
481 }
482 
HandleAdvertiseTrickleTimer(TrickleTimer & aTimer)483 void MleRouter::HandleAdvertiseTrickleTimer(TrickleTimer &aTimer)
484 {
485     aTimer.Get<MleRouter>().HandleAdvertiseTrickleTimer();
486 }
487 
HandleAdvertiseTrickleTimer(void)488 void MleRouter::HandleAdvertiseTrickleTimer(void)
489 {
490     VerifyOrExit(IsRouterEligible(), mAdvertiseTrickleTimer.Stop());
491 
492     SendAdvertisement();
493 
494 exit:
495     return;
496 }
497 
StopAdvertiseTrickleTimer(void)498 void MleRouter::StopAdvertiseTrickleTimer(void) { mAdvertiseTrickleTimer.Stop(); }
499 
DetermineAdvertiseIntervalMax(void) const500 uint32_t MleRouter::DetermineAdvertiseIntervalMax(void) const
501 {
502     uint32_t interval;
503 
504 #if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
505     interval = kAdvIntervalMaxLogRoutes;
506 #else
507     // Determine the interval based on the number of router neighbors
508     // with link quality 2 or higher.
509 
510     interval = (Get<RouterTable>().GetNeighborCount(kLinkQuality2) + 1) * kAdvIntervalNeighborMultiplier;
511     interval = Clamp(interval, kAdvIntervalMaxLowerBound, kAdvIntervalMaxUpperBound);
512 #endif
513 
514     return interval;
515 }
516 
UpdateAdvertiseInterval(void)517 void MleRouter::UpdateAdvertiseInterval(void)
518 {
519     if (IsRouterOrLeader() && mAdvertiseTrickleTimer.IsRunning())
520     {
521         mAdvertiseTrickleTimer.SetIntervalMax(DetermineAdvertiseIntervalMax());
522     }
523 }
524 
ResetAdvertiseInterval(void)525 void MleRouter::ResetAdvertiseInterval(void)
526 {
527     VerifyOrExit(IsRouterOrLeader());
528 
529     if (!mAdvertiseTrickleTimer.IsRunning())
530     {
531         mAdvertiseTrickleTimer.Start(TrickleTimer::kModeTrickle, kAdvIntervalMin, DetermineAdvertiseIntervalMax());
532     }
533 
534     mAdvertiseTrickleTimer.IndicateInconsistent();
535 
536 exit:
537     return;
538 }
539 
SendAdvertisement(void)540 void MleRouter::SendAdvertisement(void)
541 {
542     Error        error = kErrorNone;
543     Ip6::Address destination;
544     TxMessage   *message = nullptr;
545 
546     // Suppress MLE Advertisements when trying to attach to a better
547     // partition. Without this, a candidate parent might incorrectly
548     // interpret this advertisement (Source Address TLV containing an
549     // RLOC16 indicating device is acting as router) and reject the
550     // attaching device.
551 
552     VerifyOrExit(!IsAttaching());
553 
554     // Suppress MLE Advertisements when attempting to transition to
555     // router role. Advertisements as a REED while attaching to a new
556     // partition can cause existing children to detach
557     // unnecessarily.
558 
559     VerifyOrExit(!mAddressSolicitPending);
560 
561     VerifyOrExit((message = NewMleMessage(kCommandAdvertisement)) != nullptr, error = kErrorNoBufs);
562     SuccessOrExit(error = message->AppendSourceAddressTlv());
563     SuccessOrExit(error = message->AppendLeaderDataTlv());
564 
565     switch (mRole)
566     {
567     case kRoleChild:
568         break;
569 
570     case kRoleRouter:
571     case kRoleLeader:
572         SuccessOrExit(error = message->AppendRouteTlv());
573         break;
574 
575     case kRoleDisabled:
576     case kRoleDetached:
577         OT_ASSERT(false);
578     }
579 
580     destination.SetToLinkLocalAllNodesMulticast();
581     SuccessOrExit(error = message->SendTo(destination));
582 
583     Log(kMessageSend, kTypeAdvertisement, destination);
584 
585 exit:
586     FreeMessageOnError(message, error);
587     LogSendError(kTypeAdvertisement, error);
588 }
589 
SendLinkRequest(Neighbor * aNeighbor)590 Error MleRouter::SendLinkRequest(Neighbor *aNeighbor)
591 {
592     static const uint8_t kDetachedTlvs[]      = {Tlv::kAddress16, Tlv::kRoute};
593     static const uint8_t kRouterTlvs[]        = {Tlv::kLinkMargin};
594     static const uint8_t kValidNeighborTlvs[] = {Tlv::kLinkMargin, Tlv::kRoute};
595 
596     Error        error   = kErrorNone;
597     TxMessage   *message = nullptr;
598     Ip6::Address destination;
599 
600     VerifyOrExit(mChallengeTimeout == 0);
601 
602     destination.Clear();
603 
604     VerifyOrExit((message = NewMleMessage(kCommandLinkRequest)) != nullptr, error = kErrorNoBufs);
605     SuccessOrExit(error = message->AppendVersionTlv());
606 
607     switch (mRole)
608     {
609     case kRoleDetached:
610         SuccessOrExit(error = message->AppendTlvRequestTlv(kDetachedTlvs));
611         break;
612 
613     case kRoleChild:
614         SuccessOrExit(error = message->AppendSourceAddressTlv());
615         SuccessOrExit(error = message->AppendLeaderDataTlv());
616         break;
617 
618     case kRoleRouter:
619     case kRoleLeader:
620         if (aNeighbor == nullptr || !aNeighbor->IsStateValid())
621         {
622             SuccessOrExit(error = message->AppendTlvRequestTlv(kRouterTlvs));
623         }
624         else
625         {
626             SuccessOrExit(error = message->AppendTlvRequestTlv(kValidNeighborTlvs));
627         }
628 
629         SuccessOrExit(error = message->AppendSourceAddressTlv());
630         SuccessOrExit(error = message->AppendLeaderDataTlv());
631         break;
632 
633     case kRoleDisabled:
634         OT_ASSERT(false);
635     }
636 
637 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
638     SuccessOrExit(error = message->AppendTimeRequestTlv());
639 #endif
640 
641     if (aNeighbor == nullptr)
642     {
643         mChallenge.GenerateRandom();
644         mChallengeTimeout = kChallengeTimeout;
645 
646         SuccessOrExit(error = message->AppendChallengeTlv(mChallenge));
647         destination.SetToLinkLocalAllRoutersMulticast();
648     }
649     else
650     {
651         if (!aNeighbor->IsStateValid())
652         {
653             aNeighbor->GenerateChallenge();
654             SuccessOrExit(error = message->AppendChallengeTlv(aNeighbor->GetChallenge()));
655         }
656         else
657         {
658             TxChallenge challenge;
659 
660             challenge.GenerateRandom();
661             SuccessOrExit(error = message->AppendChallengeTlv(challenge));
662         }
663 
664         destination.SetToLinkLocalAddress(aNeighbor->GetExtAddress());
665     }
666 
667     SuccessOrExit(error = message->SendTo(destination));
668 
669     Log(kMessageSend, kTypeLinkRequest, destination);
670 
671 exit:
672     FreeMessageOnError(message, error);
673     return error;
674 }
675 
HandleLinkRequest(RxInfo & aRxInfo)676 void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
677 {
678     Error       error    = kErrorNone;
679     Neighbor   *neighbor = nullptr;
680     RxChallenge challenge;
681     uint16_t    version;
682     LeaderData  leaderData;
683     uint16_t    sourceAddress;
684     TlvList     requestedTlvList;
685 
686     Log(kMessageReceive, kTypeLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr());
687 
688     VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
689 
690     VerifyOrExit(!IsAttaching(), error = kErrorInvalidState);
691 
692     SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
693 
694     SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
695 
696     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
697     {
698     case kErrorNone:
699         VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId(), error = kErrorInvalidState);
700         break;
701     case kErrorNotFound:
702         break;
703     default:
704         ExitNow(error = kErrorParse);
705     }
706 
707     switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
708     {
709     case kErrorNone:
710         if (IsRouterRloc16(sourceAddress))
711         {
712             neighbor = mRouterTable.FindRouterByRloc16(sourceAddress);
713             VerifyOrExit(neighbor != nullptr, error = kErrorParse);
714             VerifyOrExit(!neighbor->IsStateLinkRequest(), error = kErrorAlready);
715 
716             if (!neighbor->IsStateValid())
717             {
718                 InitNeighbor(*neighbor, aRxInfo);
719                 neighbor->SetState(Neighbor::kStateLinkRequest);
720             }
721             else
722             {
723                 Mac::ExtAddress extAddr;
724 
725                 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
726                 VerifyOrExit(neighbor->GetExtAddress() == extAddr);
727             }
728         }
729 
730         break;
731 
732     case kErrorNotFound:
733         // A missing source address indicates that the router was
734         // recently reset.
735         VerifyOrExit(aRxInfo.IsNeighborStateValid() && IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()),
736                      error = kErrorDrop);
737         neighbor = aRxInfo.mNeighbor;
738         break;
739 
740     default:
741         ExitNow(error = kErrorParse);
742     }
743 
744     switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
745     {
746     case kErrorNone:
747     case kErrorNotFound:
748         break;
749     default:
750         ExitNow(error = kErrorParse);
751     }
752 
753 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
754     if (neighbor != nullptr)
755     {
756         neighbor->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
757     }
758 #endif
759 
760 #if OPENTHREAD_CONFIG_MULTI_RADIO
761     if (neighbor != nullptr)
762     {
763         neighbor->ClearLastRxFragmentTag();
764     }
765 #endif
766 
767     aRxInfo.mClass = RxInfo::kPeerMessage;
768     ProcessKeySequence(aRxInfo);
769 
770     SuccessOrExit(error = SendLinkAccept(aRxInfo, neighbor, requestedTlvList, challenge));
771 
772 exit:
773     LogProcessError(kTypeLinkRequest, error);
774 }
775 
SendLinkAccept(const RxInfo & aRxInfo,Neighbor * aNeighbor,const TlvList & aRequestedTlvList,const RxChallenge & aChallenge)776 Error MleRouter::SendLinkAccept(const RxInfo      &aRxInfo,
777                                 Neighbor          *aNeighbor,
778                                 const TlvList     &aRequestedTlvList,
779                                 const RxChallenge &aChallenge)
780 {
781     static const uint8_t kRouterTlvs[] = {Tlv::kLinkMargin};
782 
783     Error      error = kErrorNone;
784     TxMessage *message;
785     Command    command;
786     uint8_t    linkMargin;
787 
788     command = (aNeighbor == nullptr || aNeighbor->IsStateValid()) ? kCommandLinkAccept : kCommandLinkAcceptAndRequest;
789 
790     VerifyOrExit((message = NewMleMessage(command)) != nullptr, error = kErrorNoBufs);
791     SuccessOrExit(error = message->AppendVersionTlv());
792     SuccessOrExit(error = message->AppendSourceAddressTlv());
793     SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
794     SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
795 
796     linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
797     SuccessOrExit(error = message->AppendLinkMarginTlv(linkMargin));
798 
799     if (aNeighbor != nullptr && IsRouterRloc16(aNeighbor->GetRloc16()))
800     {
801         SuccessOrExit(error = message->AppendLeaderDataTlv());
802     }
803 
804     for (uint8_t tlvType : aRequestedTlvList)
805     {
806         switch (tlvType)
807         {
808         case Tlv::kRoute:
809             SuccessOrExit(error = message->AppendRouteTlv(aNeighbor));
810             break;
811 
812         case Tlv::kAddress16:
813             VerifyOrExit(aNeighbor != nullptr, error = kErrorDrop);
814             SuccessOrExit(error = message->AppendAddress16Tlv(aNeighbor->GetRloc16()));
815             break;
816 
817         case Tlv::kLinkMargin:
818             break;
819 
820         default:
821             ExitNow(error = kErrorDrop);
822         }
823     }
824 
825     if (aNeighbor != nullptr && !aNeighbor->IsStateValid())
826     {
827         aNeighbor->GenerateChallenge();
828 
829         SuccessOrExit(error = message->AppendChallengeTlv(aNeighbor->GetChallenge()));
830         SuccessOrExit(error = message->AppendTlvRequestTlv(kRouterTlvs));
831         aNeighbor->SetLastHeard(TimerMilli::GetNow());
832         aNeighbor->SetState(Neighbor::kStateLinkRequest);
833     }
834 
835 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
836     if (aNeighbor != nullptr && aNeighbor->IsTimeSyncEnabled())
837     {
838         message->SetTimeSync(true);
839     }
840 #endif
841 
842     if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast())
843     {
844         SuccessOrExit(error = message->SendAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(),
845                                                       1 + Random::NonCrypto::GetUint16InRange(0, kMaxLinkAcceptDelay)));
846 
847         Log(kMessageDelay, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest,
848             aRxInfo.mMessageInfo.GetPeerAddr());
849     }
850     else
851     {
852         SuccessOrExit(error = message->SendTo(aRxInfo.mMessageInfo.GetPeerAddr()));
853 
854         Log(kMessageSend, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest,
855             aRxInfo.mMessageInfo.GetPeerAddr());
856     }
857 
858 exit:
859     FreeMessageOnError(message, error);
860     return error;
861 }
862 
HandleLinkAccept(RxInfo & aRxInfo)863 void MleRouter::HandleLinkAccept(RxInfo &aRxInfo)
864 {
865     Error error = HandleLinkAccept(aRxInfo, false);
866 
867     LogProcessError(kTypeLinkAccept, error);
868 }
869 
HandleLinkAcceptAndRequest(RxInfo & aRxInfo)870 void MleRouter::HandleLinkAcceptAndRequest(RxInfo &aRxInfo)
871 {
872     Error error = HandleLinkAccept(aRxInfo, true);
873 
874     LogProcessError(kTypeLinkAcceptAndRequest, error);
875 }
876 
HandleLinkAccept(RxInfo & aRxInfo,bool aRequest)877 Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
878 {
879     Error           error = kErrorNone;
880     Router         *router;
881     Neighbor::State neighborState;
882     uint16_t        version;
883     RxChallenge     response;
884     uint16_t        sourceAddress;
885     uint32_t        linkFrameCounter;
886     uint32_t        mleFrameCounter;
887     uint8_t         routerId;
888     uint16_t        address16;
889     RouteTlv        routeTlv;
890     LeaderData      leaderData;
891     uint8_t         linkMargin;
892     bool            shouldUpdateRoutes = false;
893 
894     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
895 
896     Log(kMessageReceive, aRequest ? kTypeLinkAcceptAndRequest : kTypeLinkAccept, aRxInfo.mMessageInfo.GetPeerAddr(),
897         sourceAddress);
898 
899     VerifyOrExit(IsRouterRloc16(sourceAddress), error = kErrorParse);
900 
901     routerId      = RouterIdFromRloc16(sourceAddress);
902     router        = mRouterTable.FindRouterById(routerId);
903     neighborState = (router != nullptr) ? router->GetState() : Neighbor::kStateInvalid;
904 
905     SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
906 
907     switch (neighborState)
908     {
909     case Neighbor::kStateLinkRequest:
910         VerifyOrExit(response == router->GetChallenge(), error = kErrorSecurity);
911         break;
912 
913     case Neighbor::kStateInvalid:
914         VerifyOrExit((mLinkRequestAttempts > 0 || mChallengeTimeout > 0) && (response == mChallenge),
915                      error = kErrorSecurity);
916 
917         OT_FALL_THROUGH;
918 
919     case Neighbor::kStateValid:
920         break;
921 
922     default:
923         ExitNow(error = kErrorSecurity);
924     }
925 
926     // Remove stale neighbors
927     if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != sourceAddress)
928     {
929         RemoveNeighbor(*aRxInfo.mNeighbor);
930     }
931 
932     SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
933 
934     SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
935 
936     switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMargin))
937     {
938     case kErrorNone:
939         break;
940     case kErrorNotFound:
941         // The Link Margin TLV may be omitted after a reset. We wait
942         // for MLE Advertisements to establish the routing cost to
943         // the neighbor
944         VerifyOrExit(IsDetached(), error = kErrorNotFound);
945         linkMargin = 0;
946         break;
947     default:
948         ExitNow(error = kErrorParse);
949     }
950 
951     switch (mRole)
952     {
953     case kRoleDetached:
954         SuccessOrExit(error = Tlv::Find<Address16Tlv>(aRxInfo.mMessage, address16));
955         VerifyOrExit(GetRloc16() == address16, error = kErrorDrop);
956 
957         SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
958         SetLeaderData(leaderData);
959 
960         mRouterTable.Clear();
961         SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv));
962         SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
963         router = mRouterTable.FindRouterById(routerId);
964         VerifyOrExit(router != nullptr);
965 
966         if (GetLeaderRloc16() == GetRloc16())
967         {
968             SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset);
969         }
970         else
971         {
972             SetStateRouter(GetRloc16());
973         }
974 
975         mLinkRequestAttempts    = 0;
976         mRetrieveNewNetworkData = true;
977         IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
978         shouldUpdateRoutes = true;
979 
980 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
981         Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
982 #endif
983         break;
984 
985     case kRoleChild:
986         VerifyOrExit(router != nullptr);
987         break;
988 
989     case kRoleRouter:
990     case kRoleLeader:
991         VerifyOrExit(router != nullptr);
992 
993         SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
994         VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
995 
996         if (mRetrieveNewNetworkData ||
997             SerialNumber::IsGreater(leaderData.GetDataVersion(NetworkData::kFullSet),
998                                     Get<NetworkData::Leader>().GetVersion(NetworkData::kFullSet)))
999         {
1000             IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
1001         }
1002 
1003         switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1004         {
1005         case kErrorNone:
1006             VerifyOrExit(routeTlv.IsRouterIdSet(routerId), error = kErrorParse);
1007 
1008             if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
1009             {
1010                 SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1011                 router = mRouterTable.FindRouterById(routerId);
1012                 OT_ASSERT(router != nullptr);
1013             }
1014             shouldUpdateRoutes = true;
1015             break;
1016 
1017         case kErrorNotFound:
1018             break;
1019 
1020         default:
1021             ExitNow(error = kErrorParse);
1022         }
1023 
1024         if (routerId != mRouterId && !IsRouterIdValid(router->GetNextHop()))
1025         {
1026             ResetAdvertiseInterval();
1027         }
1028 
1029         break;
1030 
1031     case kRoleDisabled:
1032         OT_ASSERT(false);
1033     }
1034 
1035     InitNeighbor(*router, aRxInfo);
1036     router->SetRloc16(sourceAddress);
1037     router->GetLinkFrameCounters().SetAll(linkFrameCounter);
1038     router->SetLinkAckFrameCounter(linkFrameCounter);
1039     router->SetMleFrameCounter(mleFrameCounter);
1040     router->SetVersion(version);
1041     router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
1042                                      DeviceMode::kModeFullNetworkData));
1043     router->SetLinkQualityOut(LinkQualityForLinkMargin(linkMargin));
1044     router->SetState(Neighbor::kStateValid);
1045     router->SetKeySequence(aRxInfo.mKeySequence);
1046 
1047     mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
1048 
1049     if (shouldUpdateRoutes)
1050     {
1051         mRouterTable.UpdateRoutes(routeTlv, routerId);
1052     }
1053 
1054     aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
1055     ProcessKeySequence(aRxInfo);
1056 
1057     if (aRequest)
1058     {
1059         RxChallenge challenge;
1060         TlvList     requestedTlvList;
1061 
1062         SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
1063 
1064         switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
1065         {
1066         case kErrorNone:
1067         case kErrorNotFound:
1068             break;
1069         default:
1070             ExitNow(error = kErrorParse);
1071         }
1072 
1073         SuccessOrExit(error = SendLinkAccept(aRxInfo, router, requestedTlvList, challenge));
1074     }
1075 
1076 exit:
1077     return error;
1078 }
1079 
ProcessRouteTlv(const RouteTlv & aRouteTlv,RxInfo & aRxInfo)1080 Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo)
1081 {
1082     // This method processes `aRouteTlv` read from an MLE message.
1083     //
1084     // During processing of Route TLV, the entries in the router table
1085     // may shuffle. This method ensures that the `aRxInfo.mNeighbor`
1086     // (which indicates the neighbor from which the MLE message was
1087     // received) is correctly updated to point to the same neighbor
1088     // (in case `mNeighbor` was pointing to a router entry from the
1089     // `RouterTable`).
1090 
1091     Error    error          = kErrorNone;
1092     uint16_t neighborRloc16 = kInvalidRloc16;
1093 
1094     if ((aRxInfo.mNeighbor != nullptr) && Get<RouterTable>().Contains(*aRxInfo.mNeighbor))
1095     {
1096         neighborRloc16 = aRxInfo.mNeighbor->GetRloc16();
1097     }
1098 
1099     mRouterTable.UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask());
1100 
1101     if (IsRouter() && !mRouterTable.IsAllocated(mRouterId))
1102     {
1103         IgnoreError(BecomeDetached());
1104         error = kErrorNoRoute;
1105     }
1106 
1107     if (neighborRloc16 != kInvalidRloc16)
1108     {
1109         aRxInfo.mNeighbor = Get<NeighborTable>().FindNeighbor(neighborRloc16);
1110     }
1111 
1112     return error;
1113 }
1114 
ReadAndProcessRouteTlvOnFed(RxInfo & aRxInfo,uint8_t aParentId)1115 Error MleRouter::ReadAndProcessRouteTlvOnFed(RxInfo &aRxInfo, uint8_t aParentId)
1116 {
1117     // This method reads and processes Route TLV from message on an
1118     // FED if message contains one. It returns `kErrorNone` when
1119     // successfully processed or if there is no Route TLV in the
1120     // message.
1121     //
1122     // It MUST be used only when device is acting as a child and
1123     // for a message received from device's current parent.
1124 
1125     Error    error = kErrorNone;
1126     RouteTlv routeTlv;
1127 
1128     VerifyOrExit(IsFullThreadDevice());
1129 
1130     switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1131     {
1132     case kErrorNone:
1133         SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1134         mRouterTable.UpdateRoutesOnFed(routeTlv, aParentId);
1135         mRequestRouteTlv = false;
1136         break;
1137     case kErrorNotFound:
1138         break;
1139     default:
1140         ExitNow(error = kErrorParse);
1141     }
1142 
1143 exit:
1144     return error;
1145 }
1146 
IsSingleton(void) const1147 bool MleRouter::IsSingleton(void) const
1148 {
1149     bool isSingleton = true;
1150 
1151     VerifyOrExit(IsAttached() && IsRouterEligible());
1152     isSingleton = (mRouterTable.GetActiveRouterCount() <= 1);
1153 
1154 exit:
1155     return isSingleton;
1156 }
1157 
ComparePartitions(bool aSingletonA,const LeaderData & aLeaderDataA,bool aSingletonB,const LeaderData & aLeaderDataB)1158 int MleRouter::ComparePartitions(bool              aSingletonA,
1159                                  const LeaderData &aLeaderDataA,
1160                                  bool              aSingletonB,
1161                                  const LeaderData &aLeaderDataB)
1162 {
1163     int rval = 0;
1164 
1165     rval = ThreeWayCompare(aLeaderDataA.GetWeighting(), aLeaderDataB.GetWeighting());
1166     VerifyOrExit(rval == 0);
1167 
1168     // Not being a singleton is better.
1169     rval = ThreeWayCompare(!aSingletonA, !aSingletonB);
1170     VerifyOrExit(rval == 0);
1171 
1172     rval = ThreeWayCompare(aLeaderDataA.GetPartitionId(), aLeaderDataB.GetPartitionId());
1173 
1174 exit:
1175     return rval;
1176 }
1177 
HandleAdvertisement(RxInfo & aRxInfo,uint16_t aSourceAddress,const LeaderData & aLeaderData)1178 Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, const LeaderData &aLeaderData)
1179 {
1180     // This method processes a received MLE Advertisement message on
1181     // an FTD device. It is called from `Mle::HandleAdvertisement()`
1182     // only when device is attached (in child, router, or leader roles)
1183     // and `IsFullThreadDevice()`.
1184     //
1185     // - `aSourceAddress` is the read value from `SourceAddressTlv`.
1186     // - `aLeaderData` is the read value from `LeaderDataTlv`.
1187 
1188     Error    error      = kErrorNone;
1189     uint8_t  linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
1190     RouteTlv routeTlv;
1191     Router  *router;
1192     uint8_t  routerId;
1193 
1194     switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1195     {
1196     case kErrorNone:
1197         break;
1198     case kErrorNotFound:
1199         routeTlv.SetLength(0); // Mark that a Route TLV was not included.
1200         break;
1201     default:
1202         ExitNow(error = kErrorParse);
1203     }
1204 
1205     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1206     // Handle Partition ID mismatch
1207 
1208     if (aLeaderData.GetPartitionId() != mLeaderData.GetPartitionId())
1209     {
1210         LogNote("Different partition (peer:%lu, local:%lu)", ToUlong(aLeaderData.GetPartitionId()),
1211                 ToUlong(mLeaderData.GetPartitionId()));
1212 
1213         VerifyOrExit(linkMargin >= kPartitionMergeMinMargin, error = kErrorLinkMarginLow);
1214 
1215         if (routeTlv.IsValid() && (mPreviousPartitionIdTimeout > 0) &&
1216             (aLeaderData.GetPartitionId() == mPreviousPartitionId))
1217         {
1218             VerifyOrExit(SerialNumber::IsGreater(routeTlv.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence),
1219                          error = kErrorDrop);
1220         }
1221 
1222         if (IsChild() && (aRxInfo.mNeighbor == &mParent))
1223         {
1224             ExitNow();
1225         }
1226 
1227         if (ComparePartitions(routeTlv.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0
1228 #if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
1229             // Allow a better partition if it also enables time sync.
1230             && aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
1231 #endif
1232         )
1233         {
1234             Attach(kBetterPartition);
1235         }
1236 
1237         ExitNow(error = kErrorDrop);
1238     }
1239 
1240     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1241     // Handle Leader Router ID mismatch
1242 
1243     if (aLeaderData.GetLeaderRouterId() != GetLeaderId())
1244     {
1245         VerifyOrExit(aRxInfo.IsNeighborStateValid());
1246 
1247         if (!IsChild())
1248         {
1249             LogInfo("Leader ID mismatch");
1250             IgnoreError(BecomeDetached());
1251             error = kErrorDrop;
1252         }
1253 
1254         ExitNow();
1255     }
1256 
1257     VerifyOrExit(IsRouterRloc16(aSourceAddress) && routeTlv.IsValid());
1258     routerId = RouterIdFromRloc16(aSourceAddress);
1259 
1260 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1261     Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
1262 #endif
1263 
1264     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1265     // Process `RouteTlv`
1266 
1267     if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
1268     {
1269         SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1270     }
1271 
1272     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1273     // Update routers as a child
1274 
1275     if (IsChild())
1276     {
1277         if (aRxInfo.mNeighbor == &mParent)
1278         {
1279             // MLE Advertisement from parent
1280             router = &mParent;
1281 
1282             if (mParent.GetRloc16() != aSourceAddress)
1283             {
1284                 IgnoreError(BecomeDetached());
1285                 ExitNow(error = kErrorDetached);
1286             }
1287 
1288             if (!mRouterRoleTransition.IsPending() && (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
1289             {
1290                 mRouterRoleTransition.StartTimeout();
1291             }
1292 
1293             mRouterTable.UpdateRoutesOnFed(routeTlv, routerId);
1294         }
1295         else
1296         {
1297             // MLE Advertisement not from parent, but from some other neighboring router
1298             router = mRouterTable.FindRouterById(routerId);
1299             VerifyOrExit(router != nullptr);
1300 
1301             if (!router->IsStateValid() && !router->IsStateLinkRequest() &&
1302                 (mRouterTable.GetNeighborCount(kLinkQuality1) < mChildRouterLinks))
1303             {
1304                 InitNeighbor(*router, aRxInfo);
1305                 router->SetState(Neighbor::kStateLinkRequest);
1306                 IgnoreError(SendLinkRequest(router));
1307                 ExitNow(error = kErrorNoRoute);
1308             }
1309         }
1310 
1311         router->SetLastHeard(TimerMilli::GetNow());
1312 
1313         ExitNow();
1314     }
1315 
1316     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1317     // Update routers as a router or leader.
1318 
1319     if (IsRouter() && ShouldDowngrade(routerId, routeTlv))
1320     {
1321         mRouterRoleTransition.StartTimeout();
1322     }
1323 
1324     router = mRouterTable.FindRouterById(routerId);
1325     VerifyOrExit(router != nullptr);
1326 
1327     if (!router->IsStateValid() && aRxInfo.IsNeighborStateValid() && Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
1328     {
1329         // The Adv is from a former child that is now acting as a router,
1330         // we copy the info from child entry and update the RLOC16.
1331 
1332         *static_cast<Neighbor *>(router) = *aRxInfo.mNeighbor;
1333         router->SetRloc16(Rloc16FromRouterId(routerId));
1334         router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
1335                                          DeviceMode::kModeFullNetworkData));
1336 
1337         mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
1338 
1339         // Change the cache entries associated with the former child
1340         // from using the old RLOC16 to its new RLOC16.
1341         Get<AddressResolver>().ReplaceEntriesForRloc16(aRxInfo.mNeighbor->GetRloc16(), router->GetRloc16());
1342     }
1343 
1344     // Send unicast link request if no link to router and no
1345     // unicast/multicast link request in progress
1346 
1347     if (!router->IsStateValid() && !router->IsStateLinkRequest() && (mChallengeTimeout == 0) &&
1348         (linkMargin >= kLinkRequestMinMargin))
1349     {
1350         InitNeighbor(*router, aRxInfo);
1351         router->SetState(Neighbor::kStateLinkRequest);
1352         IgnoreError(SendLinkRequest(router));
1353         ExitNow(error = kErrorNoRoute);
1354     }
1355 
1356     router->SetLastHeard(TimerMilli::GetNow());
1357 
1358     mRouterTable.UpdateRoutes(routeTlv, routerId);
1359 
1360 exit:
1361     if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != aSourceAddress)
1362     {
1363         RemoveNeighbor(*aRxInfo.mNeighbor);
1364     }
1365 
1366     return error;
1367 }
1368 
HandleParentRequest(RxInfo & aRxInfo)1369 void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
1370 {
1371     Error           error = kErrorNone;
1372     Mac::ExtAddress extAddr;
1373     uint16_t        version;
1374     uint8_t         scanMask;
1375     RxChallenge     challenge;
1376     Child          *child;
1377     DeviceMode      mode;
1378 
1379     Log(kMessageReceive, kTypeParentRequest, aRxInfo.mMessageInfo.GetPeerAddr());
1380 
1381     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
1382 
1383     // A Router/REED MUST NOT send an MLE Parent Response if:
1384 
1385     // 0. It is detached or attempting to another partition
1386     VerifyOrExit(!IsDetached() && !IsAttaching(), error = kErrorDrop);
1387 
1388     // 1. It has no available Child capacity (if Max Child Count minus
1389     // Child Count would be equal to zero)
1390     // ==> verified below when allocating a child entry
1391 
1392     // 2. It is disconnected from its Partition (that is, it has not
1393     // received an updated ID sequence number within LEADER_TIMEOUT
1394     // seconds)
1395     VerifyOrExit(mRouterTable.GetLeaderAge() < mNetworkIdTimeout, error = kErrorDrop);
1396 
1397     // 3. Its current routing path cost to the Leader is infinite.
1398     VerifyOrExit(mRouterTable.GetPathCostToLeader() < kMaxRouteCost, error = kErrorDrop);
1399 
1400     // 4. It is a REED and there are already `kMaxRouters` active routers in
1401     // the network (because Leader would reject any further address solicit).
1402     // ==> Verified below when checking the scan mask.
1403 
1404     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
1405 
1406     SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
1407 
1408     SuccessOrExit(error = Tlv::Find<ScanMaskTlv>(aRxInfo.mMessage, scanMask));
1409 
1410     switch (mRole)
1411     {
1412     case kRoleDisabled:
1413     case kRoleDetached:
1414         ExitNow();
1415 
1416     case kRoleChild:
1417         VerifyOrExit(ScanMaskTlv::IsEndDeviceFlagSet(scanMask));
1418         VerifyOrExit(mRouterTable.GetActiveRouterCount() < kMaxRouters, error = kErrorDrop);
1419         break;
1420 
1421     case kRoleRouter:
1422     case kRoleLeader:
1423         VerifyOrExit(ScanMaskTlv::IsRouterFlagSet(scanMask));
1424         break;
1425     }
1426 
1427     SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(challenge));
1428 
1429     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
1430 
1431     if (child == nullptr)
1432     {
1433         VerifyOrExit((child = mChildTable.GetNewChild()) != nullptr, error = kErrorNoBufs);
1434 
1435         InitNeighbor(*child, aRxInfo);
1436         child->SetState(Neighbor::kStateParentRequest);
1437 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1438         child->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
1439 #endif
1440         if (aRxInfo.mMessage.ReadModeTlv(mode) == kErrorNone)
1441         {
1442             child->SetDeviceMode(mode);
1443             child->SetVersion(version);
1444         }
1445     }
1446     else if (TimerMilli::GetNow() - child->GetLastHeard() < kParentRequestRouterTimeout - kParentRequestDuplicateMargin)
1447     {
1448         ExitNow(error = kErrorDuplicated);
1449     }
1450 
1451     if (!child->IsStateValidOrRestoring())
1452     {
1453         child->SetLastHeard(TimerMilli::GetNow());
1454         child->SetTimeout(Time::MsecToSec(kChildIdRequestTimeout));
1455     }
1456 
1457     aRxInfo.mClass = RxInfo::kPeerMessage;
1458     ProcessKeySequence(aRxInfo);
1459 
1460     SendParentResponse(child, challenge, !ScanMaskTlv::IsEndDeviceFlagSet(scanMask));
1461 
1462 exit:
1463     LogProcessError(kTypeParentRequest, error);
1464 }
1465 
HasNeighborWithGoodLinkQuality(void) const1466 bool MleRouter::HasNeighborWithGoodLinkQuality(void) const
1467 {
1468     bool    haveNeighbor = true;
1469     uint8_t linkMargin;
1470 
1471     linkMargin = Get<Mac::Mac>().ComputeLinkMargin(mParent.GetLinkInfo().GetLastRss());
1472 
1473     if (linkMargin >= kLinkRequestMinMargin)
1474     {
1475         ExitNow();
1476     }
1477 
1478     for (const Router &router : Get<RouterTable>())
1479     {
1480         if (!router.IsStateValid())
1481         {
1482             continue;
1483         }
1484 
1485         linkMargin = Get<Mac::Mac>().ComputeLinkMargin(router.GetLinkInfo().GetLastRss());
1486 
1487         if (linkMargin >= kLinkRequestMinMargin)
1488         {
1489             ExitNow();
1490         }
1491     }
1492 
1493     haveNeighbor = false;
1494 
1495 exit:
1496     return haveNeighbor;
1497 }
1498 
HandleTimeTick(void)1499 void MleRouter::HandleTimeTick(void)
1500 {
1501     bool roleTransitionTimeoutExpired = false;
1502 
1503     VerifyOrExit(IsFullThreadDevice(), Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter));
1504 
1505     if (mChallengeTimeout > 0)
1506     {
1507         mChallengeTimeout--;
1508     }
1509 
1510     if (mPreviousPartitionIdTimeout > 0)
1511     {
1512         mPreviousPartitionIdTimeout--;
1513     }
1514 
1515     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1516     // Role transitions
1517 
1518     roleTransitionTimeoutExpired = mRouterRoleTransition.HandleTimeTick();
1519 
1520     switch (mRole)
1521     {
1522     case kRoleDetached:
1523         if (mChallengeTimeout == 0 && mLinkRequestAttempts == 0)
1524         {
1525             IgnoreError(BecomeDetached());
1526             ExitNow();
1527         }
1528 
1529         break;
1530 
1531     case kRoleChild:
1532         if (roleTransitionTimeoutExpired)
1533         {
1534             if (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality())
1535             {
1536                 IgnoreError(BecomeRouter(ThreadStatusTlv::kTooFewRouters));
1537             }
1538             else
1539             {
1540                 InformPreviousChannel();
1541             }
1542 
1543             if (!mAdvertiseTrickleTimer.IsRunning())
1544             {
1545                 SendAdvertisement();
1546 
1547                 mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, kReedAdvIntervalMin, kReedAdvIntervalMax);
1548             }
1549 
1550             ExitNow();
1551         }
1552 
1553         OT_FALL_THROUGH;
1554 
1555     case kRoleRouter:
1556         LogDebg("Leader age %lu", ToUlong(mRouterTable.GetLeaderAge()));
1557 
1558         if ((mRouterTable.GetActiveRouterCount() > 0) && (mRouterTable.GetLeaderAge() >= mNetworkIdTimeout))
1559         {
1560             LogInfo("Leader age timeout");
1561             Attach(kSamePartition);
1562         }
1563 
1564         if (roleTransitionTimeoutExpired && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
1565         {
1566             LogNote("Downgrade to REED");
1567             Attach(kDowngradeToReed);
1568         }
1569 
1570         OT_FALL_THROUGH;
1571 
1572     case kRoleLeader:
1573         if (roleTransitionTimeoutExpired && !IsRouterEligible())
1574         {
1575             LogInfo("No longer router eligible");
1576             IgnoreError(BecomeDetached());
1577         }
1578 
1579         break;
1580 
1581     case kRoleDisabled:
1582         OT_ASSERT(false);
1583     }
1584 
1585     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1586     // Update `ChildTable`
1587 
1588     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
1589     {
1590         uint32_t timeout = 0;
1591 
1592         switch (child.GetState())
1593         {
1594         case Neighbor::kStateInvalid:
1595         case Neighbor::kStateChildIdRequest:
1596             continue;
1597 
1598         case Neighbor::kStateParentRequest:
1599         case Neighbor::kStateValid:
1600         case Neighbor::kStateRestored:
1601         case Neighbor::kStateChildUpdateRequest:
1602             timeout = Time::SecToMsec(child.GetTimeout());
1603             break;
1604 
1605         case Neighbor::kStateParentResponse:
1606         case Neighbor::kStateLinkRequest:
1607             OT_ASSERT(false);
1608         }
1609 
1610 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1611         if (child.IsCslSynchronized() &&
1612             TimerMilli::GetNow() - child.GetCslLastHeard() >= Time::SecToMsec(child.GetCslTimeout()))
1613         {
1614             LogInfo("Child 0x%04x CSL synchronization expired", child.GetRloc16());
1615             child.SetCslSynchronized(false);
1616             Get<CslTxScheduler>().Update();
1617         }
1618 #endif
1619 
1620         if (TimerMilli::GetNow() - child.GetLastHeard() >= timeout)
1621         {
1622             LogInfo("Child 0x%04x timeout expired", child.GetRloc16());
1623             RemoveNeighbor(child);
1624         }
1625         else if (IsRouterOrLeader() && child.IsStateRestored())
1626         {
1627             IgnoreError(SendChildUpdateRequest(child));
1628         }
1629     }
1630 
1631     //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1632     // Update `RouterTable`
1633 
1634     for (Router &router : Get<RouterTable>())
1635     {
1636         uint32_t age;
1637 
1638         if (router.GetRloc16() == GetRloc16())
1639         {
1640             router.SetLastHeard(TimerMilli::GetNow());
1641             continue;
1642         }
1643 
1644         age = TimerMilli::GetNow() - router.GetLastHeard();
1645 
1646         if (router.IsStateValid() && (age >= kMaxNeighborAge))
1647         {
1648 #if OPENTHREAD_CONFIG_MLE_SEND_LINK_REQUEST_ON_ADV_TIMEOUT
1649             if (age < kMaxNeighborAge + kMaxTxCount * kUnicastRetxDelay)
1650             {
1651                 LogInfo("No Adv from router 0x%04x - sending Link Request", router.GetRloc16());
1652                 IgnoreError(SendLinkRequest(&router));
1653             }
1654             else
1655 #endif
1656             {
1657                 LogInfo("Router 0x%04x timeout expired", router.GetRloc16());
1658                 RemoveNeighbor(router);
1659                 continue;
1660             }
1661         }
1662 
1663         if (router.IsStateLinkRequest() && (age >= kLinkRequestTimeout))
1664         {
1665             LogInfo("Router 0x%04x - Link Request timeout expired", router.GetRloc16());
1666             RemoveNeighbor(router);
1667             continue;
1668         }
1669 
1670         if (IsLeader() && (mRouterTable.FindNextHopOf(router) == nullptr) &&
1671             (mRouterTable.GetLinkCost(router) >= kMaxRouteCost) && (age >= kMaxLeaderToRouterTimeout))
1672         {
1673             LogInfo("Router 0x%04x ID timeout expired (no route)", router.GetRloc16());
1674             IgnoreError(mRouterTable.Release(router.GetRouterId()));
1675         }
1676     }
1677 
1678     mRouterTable.HandleTimeTick();
1679 
1680     SynchronizeChildNetworkData();
1681 
1682 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1683     if (IsRouterOrLeader())
1684     {
1685         Get<TimeSync>().ProcessTimeSync();
1686     }
1687 #endif
1688 
1689 exit:
1690     return;
1691 }
1692 
SendParentResponse(Child * aChild,const RxChallenge & aChallenge,bool aRoutersOnlyRequest)1693 void MleRouter::SendParentResponse(Child *aChild, const RxChallenge &aChallenge, bool aRoutersOnlyRequest)
1694 {
1695     Error        error = kErrorNone;
1696     Ip6::Address destination;
1697     TxMessage   *message;
1698     uint16_t     delay;
1699 
1700     VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs);
1701     message->SetDirectTransmission();
1702 
1703     SuccessOrExit(error = message->AppendSourceAddressTlv());
1704     SuccessOrExit(error = message->AppendLeaderDataTlv());
1705     SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
1706     SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
1707 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1708     if (aChild->IsTimeSyncEnabled())
1709     {
1710         SuccessOrExit(error = message->AppendTimeParameterTlv());
1711     }
1712 #endif
1713 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1714     if (aChild->IsThreadVersionCslCapable())
1715     {
1716         SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
1717     }
1718 #endif
1719     aChild->GenerateChallenge();
1720     SuccessOrExit(error = message->AppendChallengeTlv(aChild->GetChallenge()));
1721     SuccessOrExit(error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin()));
1722     SuccessOrExit(error = message->AppendConnectivityTlv());
1723     SuccessOrExit(error = message->AppendVersionTlv());
1724 
1725     destination.SetToLinkLocalAddress(aChild->GetExtAddress());
1726 
1727     delay = 1 + Random::NonCrypto::GetUint16InRange(0, aRoutersOnlyRequest ? kParentResponseMaxDelayRouters
1728                                                                            : kParentResponseMaxDelayAll);
1729 
1730     SuccessOrExit(error = message->SendAfterDelay(destination, delay));
1731 
1732     Log(kMessageDelay, kTypeParentResponse, destination);
1733 
1734 exit:
1735     FreeMessageOnError(message, error);
1736     LogSendError(kTypeParentResponse, error);
1737 }
1738 
GetMaxChildIpAddresses(void) const1739 uint8_t MleRouter::GetMaxChildIpAddresses(void) const
1740 {
1741     uint8_t num = kMaxChildIpAddresses;
1742 
1743 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1744     if (mMaxChildIpAddresses != 0)
1745     {
1746         num = mMaxChildIpAddresses;
1747     }
1748 #endif
1749 
1750     return num;
1751 }
1752 
1753 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)1754 Error MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)
1755 {
1756     Error error = kErrorNone;
1757 
1758     VerifyOrExit(aMaxIpAddresses <= kMaxChildIpAddresses, error = kErrorInvalidArgs);
1759 
1760     mMaxChildIpAddresses = aMaxIpAddresses;
1761 
1762 exit:
1763     return error;
1764 }
1765 #endif
1766 
ProcessAddressRegistrationTlv(RxInfo & aRxInfo,Child & aChild)1767 Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
1768 {
1769     Error       error;
1770     OffsetRange offsetRange;
1771     uint8_t     count       = 0;
1772     uint8_t     storedCount = 0;
1773 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1774     Ip6::Address oldDua;
1775 #endif
1776 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1777     MlrManager::MlrAddressArray oldMlrRegisteredAddresses;
1778 #endif
1779 
1780     OT_UNUSED_VARIABLE(storedCount);
1781 
1782     SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kAddressRegistration, offsetRange));
1783 
1784 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1785     if (aChild.GetDomainUnicastAddress(oldDua) != kErrorNone)
1786     {
1787         oldDua.Clear();
1788     }
1789 #endif
1790 
1791 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1792     if (aChild.HasAnyMlrRegisteredAddress())
1793     {
1794         OT_ASSERT(aChild.IsStateValid());
1795 
1796         for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
1797         {
1798             if (!addrEntry.IsMulticastLargerThanRealmLocal())
1799             {
1800                 continue;
1801             }
1802 
1803             if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered)
1804             {
1805                 IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry));
1806             }
1807         }
1808     }
1809 #endif
1810 
1811     aChild.ClearIp6Addresses();
1812 
1813     while (!offsetRange.IsEmpty())
1814     {
1815         uint8_t      controlByte;
1816         Ip6::Address address;
1817 
1818         // Read out the control byte (first byte in entry)
1819         SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, controlByte));
1820         offsetRange.AdvanceOffset(sizeof(uint8_t));
1821         count++;
1822 
1823         address.Clear();
1824 
1825         if (AddressRegistrationTlv::IsEntryCompressed(controlByte))
1826         {
1827             // Compressed entry contains IID with the 64-bit prefix
1828             // determined from 6LoWPAN context identifier (from
1829             // the control byte).
1830 
1831             uint8_t         contextId = AddressRegistrationTlv::GetContextId(controlByte);
1832             Lowpan::Context context;
1833 
1834             IgnoreError(aRxInfo.mMessage.Read(offsetRange, address.GetIid()));
1835             offsetRange.AdvanceOffset(sizeof(Ip6::InterfaceIdentifier));
1836 
1837             if (Get<NetworkData::Leader>().GetContext(contextId, context) != kErrorNone)
1838             {
1839                 LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId,
1840                         aChild.GetRloc16());
1841                 continue;
1842             }
1843 
1844             address.SetPrefix(context.mPrefix);
1845         }
1846         else
1847         {
1848             // Uncompressed entry contains the full IPv6 address.
1849 
1850             IgnoreError(aRxInfo.mMessage.Read(offsetRange, address));
1851             offsetRange.AdvanceOffset(sizeof(Ip6::Address));
1852         }
1853 
1854 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1855         if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
1856         {
1857             // Skip remaining address registration entries but keep logging
1858             // skipped addresses.
1859             error = kErrorNoBufs;
1860         }
1861         else
1862 #endif
1863         {
1864             // We try to accept/add as many IPv6 addresses as possible.
1865             // "Child ID/Update Response" will indicate the accepted
1866             // addresses.
1867             error = aChild.AddIp6Address(address);
1868         }
1869 
1870         if (error == kErrorNone)
1871         {
1872             storedCount++;
1873             LogInfo("Child 0x%04x IPv6 address[%u]=%s", aChild.GetRloc16(), storedCount,
1874                     address.ToString().AsCString());
1875         }
1876         else
1877         {
1878             LogWarn("Error %s adding IPv6 address %s to child 0x%04x", ErrorToString(error),
1879                     address.ToString().AsCString(), aChild.GetRloc16());
1880         }
1881 
1882         if (address.IsMulticast())
1883         {
1884             continue;
1885         }
1886 
1887         // We check if the same address is in-use by another child, if so
1888         // remove it. This implements "last-in wins" duplicate address
1889         // resolution policy.
1890         //
1891         // Duplicate addresses can occur if a previously attached child
1892         // attaches to same parent again (after a reset, memory wipe) using
1893         // a new random extended address before the old entry in the child
1894         // table is timed out and then trying to register its globally unique
1895         // IPv6 address as the new child.
1896 
1897         for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
1898         {
1899             if (&child == &aChild)
1900             {
1901                 continue;
1902             }
1903 
1904             IgnoreError(child.RemoveIp6Address(address));
1905         }
1906 
1907         // Clear EID-to-RLOC cache for the unicast address registered by the child.
1908         Get<AddressResolver>().RemoveEntryForAddress(address);
1909     }
1910 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1911     SignalDuaAddressEvent(aChild, oldDua);
1912 #endif
1913 
1914 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1915     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses);
1916 #endif
1917 
1918     if (count == 0)
1919     {
1920         LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
1921     }
1922     else
1923     {
1924         LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count,
1925                 (count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
1926     }
1927 
1928     error = kErrorNone;
1929 
1930 exit:
1931     return error;
1932 }
1933 
1934 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
SignalDuaAddressEvent(const Child & aChild,const Ip6::Address & aOldDua) const1935 void MleRouter::SignalDuaAddressEvent(const Child &aChild, const Ip6::Address &aOldDua) const
1936 {
1937     DuaManager::ChildDuaAddressEvent event = DuaManager::kAddressUnchanged;
1938     Ip6::Address                     newDua;
1939 
1940     if (aChild.GetDomainUnicastAddress(newDua) == kErrorNone)
1941     {
1942         if (aOldDua.IsUnspecified())
1943         {
1944             event = DuaManager::kAddressAdded;
1945         }
1946         else if (aOldDua != newDua)
1947         {
1948             event = DuaManager::kAddressChanged;
1949         }
1950     }
1951     else
1952     {
1953         // Child has no DUA address. If there was no old DUA, no need
1954         // to signal.
1955 
1956         VerifyOrExit(!aOldDua.IsUnspecified());
1957 
1958         event = DuaManager::kAddressRemoved;
1959     }
1960 
1961     Get<DuaManager>().HandleChildDuaAddressEvent(aChild, event);
1962 
1963 exit:
1964     return;
1965 }
1966 #endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1967 
IsMessageMleSubType(const Message & aMessage)1968 bool MleRouter::IsMessageMleSubType(const Message &aMessage)
1969 {
1970     bool isMle = false;
1971 
1972     switch (aMessage.GetSubType())
1973     {
1974     case Message::kSubTypeMleGeneral:
1975     case Message::kSubTypeMleChildIdRequest:
1976     case Message::kSubTypeMleChildUpdateRequest:
1977     case Message::kSubTypeMleDataResponse:
1978         isMle = true;
1979         break;
1980     default:
1981         break;
1982     }
1983 
1984     return isMle;
1985 }
1986 
IsMessageChildUpdateRequest(const Message & aMessage)1987 bool MleRouter::IsMessageChildUpdateRequest(const Message &aMessage)
1988 {
1989     return aMessage.GetSubType() == Message::kSubTypeMleChildUpdateRequest;
1990 }
1991 
HandleChildIdRequest(RxInfo & aRxInfo)1992 void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
1993 {
1994     Error              error = kErrorNone;
1995     Mac::ExtAddress    extAddr;
1996     uint16_t           version;
1997     uint32_t           linkFrameCounter;
1998     uint32_t           mleFrameCounter;
1999     DeviceMode         mode;
2000     uint32_t           timeout;
2001     TlvList            tlvList;
2002     MeshCoP::Timestamp timestamp;
2003     Child             *child;
2004     Router            *router;
2005     uint16_t           supervisionInterval;
2006 
2007     Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2008 
2009     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2010 
2011     VerifyOrExit(IsAttached(), error = kErrorInvalidState);
2012 
2013     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2014 
2015     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2016     VerifyOrExit(child != nullptr, error = kErrorAlready);
2017 
2018     SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
2019 
2020     SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge()));
2021 
2022     Get<MeshForwarder>().RemoveMessagesForChild(*child, IsMessageMleSubType);
2023 
2024     SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
2025 
2026     SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2027 
2028     SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
2029 
2030     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2031 
2032     switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2033     {
2034     case kErrorNone:
2035         tlvList.Add(Tlv::kSupervisionInterval);
2036         break;
2037     case kErrorNotFound:
2038         supervisionInterval = (version <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2039         break;
2040     default:
2041         ExitNow(error = kErrorParse);
2042     }
2043 
2044     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2045     {
2046     case kErrorNone:
2047         if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2048         {
2049             break;
2050         }
2051 
2052         OT_FALL_THROUGH;
2053 
2054     case kErrorNotFound:
2055         tlvList.Add(Tlv::kActiveDataset);
2056         break;
2057 
2058     default:
2059         ExitNow(error = kErrorParse);
2060     }
2061 
2062     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2063     {
2064     case kErrorNone:
2065         if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2066         {
2067             break;
2068         }
2069 
2070         OT_FALL_THROUGH;
2071 
2072     case kErrorNotFound:
2073         tlvList.Add(Tlv::kPendingDataset);
2074         break;
2075 
2076     default:
2077         ExitNow(error = kErrorParse);
2078     }
2079 
2080     VerifyOrExit(tlvList.GetLength() <= Child::kMaxRequestTlvs, error = kErrorParse);
2081 
2082     if (!mode.IsFullThreadDevice())
2083     {
2084         SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
2085     }
2086 
2087     router = mRouterTable.FindRouter(extAddr);
2088 
2089     if (router != nullptr)
2090     {
2091         RemoveNeighbor(*router);
2092     }
2093 
2094     if (!child->IsStateValid())
2095     {
2096         child->SetState(Neighbor::kStateChildIdRequest);
2097     }
2098     else
2099     {
2100         RemoveNeighbor(*child);
2101     }
2102 
2103     child->SetLastHeard(TimerMilli::GetNow());
2104     child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2105     child->SetLinkAckFrameCounter(linkFrameCounter);
2106     child->SetMleFrameCounter(mleFrameCounter);
2107     child->SetKeySequence(aRxInfo.mKeySequence);
2108     child->SetDeviceMode(mode);
2109     child->SetVersion(version);
2110     child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2111     child->SetTimeout(timeout);
2112     child->SetSupervisionInterval(supervisionInterval);
2113 #if OPENTHREAD_CONFIG_MULTI_RADIO
2114     child->ClearLastRxFragmentTag();
2115 #endif
2116 
2117     child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType()));
2118 
2119     // We already checked above that `tlvList` will fit in
2120     // `child` entry (with `Child::kMaxRequestTlvs` TLVs).
2121 
2122     child->ClearRequestTlvs();
2123 
2124     for (uint8_t index = 0; index < tlvList.GetLength(); index++)
2125     {
2126         child->SetRequestTlv(index, tlvList[index]);
2127     }
2128 
2129     aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
2130     ProcessKeySequence(aRxInfo);
2131 
2132     switch (mRole)
2133     {
2134     case kRoleChild:
2135         child->SetState(Neighbor::kStateChildIdRequest);
2136         IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
2137         break;
2138 
2139     case kRoleRouter:
2140     case kRoleLeader:
2141         SuccessOrExit(error = SendChildIdResponse(*child));
2142         break;
2143 
2144     case kRoleDisabled:
2145     case kRoleDetached:
2146         OT_ASSERT(false);
2147     }
2148 
2149 exit:
2150     LogProcessError(kTypeChildIdRequest, error);
2151 }
2152 
HandleChildUpdateRequest(RxInfo & aRxInfo)2153 void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
2154 {
2155     Error           error = kErrorNone;
2156     Mac::ExtAddress extAddr;
2157     DeviceMode      mode;
2158     RxChallenge     challenge;
2159     LeaderData      leaderData;
2160     uint32_t        timeout;
2161     uint16_t        supervisionInterval;
2162     Child          *child;
2163     DeviceMode      oldMode;
2164     TlvList         requestedTlvList;
2165     TlvList         tlvList;
2166     bool            childDidChange = false;
2167 
2168     Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
2169 
2170     SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2171 
2172     switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
2173     {
2174     case kErrorNone:
2175         tlvList.Add(Tlv::kResponse);
2176         break;
2177     case kErrorNotFound:
2178         challenge.Clear();
2179         break;
2180     default:
2181         ExitNow(error = kErrorParse);
2182     }
2183 
2184     tlvList.Add(Tlv::kSourceAddress);
2185 
2186     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2187     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2188 
2189     if (child == nullptr)
2190     {
2191         // For invalid non-sleepy child, send Child Update Response with
2192         // Status TLV (error).
2193         if (mode.IsRxOnWhenIdle())
2194         {
2195             tlvList.Add(Tlv::kStatus);
2196             SendChildUpdateResponse(nullptr, aRxInfo.mMessageInfo, tlvList, challenge);
2197         }
2198 
2199         ExitNow();
2200     }
2201 
2202     // Ignore "Child Update Request" from a child that is present in the
2203     // child table but it is not yet in valid state. For example, a
2204     // child which is being restored (due to parent reset) or is in the
2205     // middle of the attach process (in `kStateParentRequest` or
2206     // `kStateChildIdRequest`).
2207 
2208     VerifyOrExit(child->IsStateValid());
2209 
2210     oldMode = child->GetDeviceMode();
2211     child->SetDeviceMode(mode);
2212 
2213     tlvList.Add(Tlv::kMode);
2214     tlvList.Add(Tlv::kLinkMargin);
2215 
2216     // Parent MUST include Leader Data TLV in Child Update Response
2217     tlvList.Add(Tlv::kLeaderData);
2218 
2219     if (!challenge.IsEmpty())
2220     {
2221         tlvList.Add(Tlv::kMleFrameCounter);
2222         tlvList.Add(Tlv::kLinkFrameCounter);
2223     }
2224 
2225     switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2226     {
2227     case kErrorNone:
2228         tlvList.Add(Tlv::kAddressRegistration);
2229         break;
2230     case kErrorNotFound:
2231         break;
2232     default:
2233         ExitNow(error = kErrorParse);
2234     }
2235 
2236     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2237     {
2238     case kErrorNone:
2239         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2240         break;
2241     case kErrorNotFound:
2242         break;
2243     default:
2244         ExitNow(error = kErrorParse);
2245     }
2246 
2247     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2248     {
2249     case kErrorNone:
2250         if (child->GetTimeout() != timeout)
2251         {
2252             child->SetTimeout(timeout);
2253             childDidChange = true;
2254         }
2255 
2256         tlvList.Add(Tlv::kTimeout);
2257         break;
2258 
2259     case kErrorNotFound:
2260         break;
2261 
2262     default:
2263         ExitNow(error = kErrorParse);
2264     }
2265 
2266     switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2267     {
2268     case kErrorNone:
2269         tlvList.Add(Tlv::kSupervisionInterval);
2270         break;
2271 
2272     case kErrorNotFound:
2273         supervisionInterval =
2274             (child->GetVersion() <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2275         break;
2276 
2277     default:
2278         ExitNow(error = kErrorParse);
2279     }
2280 
2281     child->SetSupervisionInterval(supervisionInterval);
2282 
2283     switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
2284     {
2285     case kErrorNone:
2286         tlvList.AddElementsFrom(requestedTlvList);
2287         break;
2288     case kErrorNotFound:
2289         break;
2290     default:
2291         ExitNow(error = kErrorParse);
2292     }
2293 
2294 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2295     if (child->IsCslSynchronized())
2296     {
2297         ChannelTlvValue cslChannelTlvValue;
2298         uint32_t        cslTimeout;
2299 
2300         switch (Tlv::Find<CslTimeoutTlv>(aRxInfo.mMessage, cslTimeout))
2301         {
2302         case kErrorNone:
2303             child->SetCslTimeout(cslTimeout);
2304             // MUST include CSL accuracy TLV when request includes CSL timeout
2305             tlvList.Add(Tlv::kCslClockAccuracy);
2306             break;
2307         case kErrorNotFound:
2308             break;
2309         default:
2310             ExitNow(error = kErrorNone);
2311         }
2312 
2313         if (Tlv::Find<CslChannelTlv>(aRxInfo.mMessage, cslChannelTlvValue) == kErrorNone)
2314         {
2315             // Special value of zero is used to indicate that
2316             // CSL channel is not specified.
2317             child->SetCslChannel(static_cast<uint8_t>(cslChannelTlvValue.GetChannel()));
2318         }
2319     }
2320 #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2321 
2322     child->SetLastHeard(TimerMilli::GetNow());
2323 
2324     if (oldMode != child->GetDeviceMode())
2325     {
2326         LogNote("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
2327                 child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
2328 
2329         childDidChange = true;
2330 
2331 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2332         if (child->IsRxOnWhenIdle())
2333         {
2334             // Clear CSL synchronization state
2335             child->SetCslSynchronized(false);
2336         }
2337 #endif
2338 
2339         // The `IndirectSender::HandleChildModeChange()` needs to happen
2340         // after "Child Update" message is fully parsed to ensure that
2341         // any registered IPv6 addresses included in the "Child Update"
2342         // are added to the child.
2343 
2344         Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
2345     }
2346 
2347     if (childDidChange)
2348     {
2349         IgnoreError(mChildTable.StoreChild(*child));
2350     }
2351 
2352 #if OPENTHREAD_CONFIG_MULTI_RADIO
2353     // We clear the fragment tag only if the "Child Update Request" is
2354     // from a detached child trying to restore its link with its
2355     // parent which is indicated by the presence of Challenge TLV in
2356     // the message.
2357     if (!challenge.IsEmpty())
2358     {
2359         child->ClearLastRxFragmentTag();
2360     }
2361 #endif
2362 
2363     SendChildUpdateResponse(child, aRxInfo.mMessageInfo, tlvList, challenge);
2364 
2365     aRxInfo.mClass = RxInfo::kPeerMessage;
2366 
2367 exit:
2368     LogProcessError(kTypeChildUpdateRequestOfChild, error);
2369 }
2370 
HandleChildUpdateResponse(RxInfo & aRxInfo)2371 void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
2372 {
2373     Error       error = kErrorNone;
2374     uint16_t    sourceAddress;
2375     uint32_t    timeout;
2376     RxChallenge response;
2377     uint8_t     status;
2378     uint32_t    linkFrameCounter;
2379     uint32_t    mleFrameCounter;
2380     LeaderData  leaderData;
2381     Child      *child;
2382 
2383     if ((aRxInfo.mNeighbor == nullptr) || IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()) ||
2384         !Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
2385     {
2386         Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr());
2387         ExitNow(error = kErrorNotFound);
2388     }
2389 
2390     child = static_cast<Child *>(aRxInfo.mNeighbor);
2391 
2392     switch (aRxInfo.mMessage.ReadResponseTlv(response))
2393     {
2394     case kErrorNone:
2395         VerifyOrExit(response == child->GetChallenge(), error = kErrorSecurity);
2396         break;
2397     case kErrorNotFound:
2398         VerifyOrExit(child->IsStateValid(), error = kErrorSecurity);
2399         response.Clear();
2400         break;
2401     default:
2402         ExitNow(error = kErrorNone);
2403     }
2404 
2405     Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
2406 
2407     switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
2408     {
2409     case kErrorNone:
2410         if (child->GetRloc16() != sourceAddress)
2411         {
2412             RemoveNeighbor(*child);
2413             ExitNow();
2414         }
2415 
2416         break;
2417 
2418     case kErrorNotFound:
2419         break;
2420 
2421     default:
2422         ExitNow(error = kErrorParse);
2423     }
2424 
2425     switch (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status))
2426     {
2427     case kErrorNone:
2428         VerifyOrExit(status != StatusTlv::kError, RemoveNeighbor(*child));
2429         break;
2430     case kErrorNotFound:
2431         break;
2432     default:
2433         ExitNow(error = kErrorParse);
2434     }
2435 
2436     switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
2437     {
2438     case kErrorNone:
2439         child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2440         child->SetLinkAckFrameCounter(linkFrameCounter);
2441         break;
2442     case kErrorNotFound:
2443         break;
2444     default:
2445         ExitNow(error = kErrorParse);
2446     }
2447 
2448     switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
2449     {
2450     case kErrorNone:
2451         child->SetMleFrameCounter(mleFrameCounter);
2452         break;
2453     case kErrorNotFound:
2454         break;
2455     default:
2456         ExitNow(error = kErrorNone);
2457     }
2458 
2459     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2460     {
2461     case kErrorNone:
2462         child->SetTimeout(timeout);
2463         break;
2464     case kErrorNotFound:
2465         break;
2466     default:
2467         ExitNow(error = kErrorParse);
2468     }
2469 
2470     {
2471         uint16_t supervisionInterval;
2472 
2473         switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2474         {
2475         case kErrorNone:
2476             child->SetSupervisionInterval(supervisionInterval);
2477             break;
2478         case kErrorNotFound:
2479             break;
2480         default:
2481             ExitNow(error = kErrorParse);
2482         }
2483     }
2484 
2485     switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2486     {
2487     case kErrorNone:
2488     case kErrorNotFound:
2489         break;
2490     default:
2491         ExitNow(error = kErrorParse);
2492     }
2493 
2494     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2495     {
2496     case kErrorNone:
2497         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2498         break;
2499     case kErrorNotFound:
2500         break;
2501     default:
2502         ExitNow(error = kErrorParse);
2503     }
2504 
2505     SetChildStateToValid(*child);
2506     child->SetLastHeard(TimerMilli::GetNow());
2507     child->SetKeySequence(aRxInfo.mKeySequence);
2508     child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2509 
2510     aRxInfo.mClass = response.IsEmpty() ? RxInfo::kPeerMessage : RxInfo::kAuthoritativeMessage;
2511 
2512 exit:
2513     LogProcessError(kTypeChildUpdateResponseOfChild, error);
2514 }
2515 
HandleDataRequest(RxInfo & aRxInfo)2516 void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
2517 {
2518     Error              error = kErrorNone;
2519     TlvList            tlvList;
2520     MeshCoP::Timestamp timestamp;
2521 
2522     Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2523 
2524     VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity);
2525 
2526     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2527 
2528     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2529     {
2530     case kErrorNone:
2531         if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2532         {
2533             break;
2534         }
2535 
2536         OT_FALL_THROUGH;
2537 
2538     case kErrorNotFound:
2539         tlvList.Add(Tlv::kActiveDataset);
2540         break;
2541 
2542     default:
2543         ExitNow(error = kErrorParse);
2544     }
2545 
2546     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2547     {
2548     case kErrorNone:
2549         if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2550         {
2551             break;
2552         }
2553 
2554         OT_FALL_THROUGH;
2555 
2556     case kErrorNotFound:
2557         tlvList.Add(Tlv::kPendingDataset);
2558         break;
2559 
2560     default:
2561         ExitNow(error = kErrorParse);
2562     }
2563 
2564     aRxInfo.mClass = RxInfo::kPeerMessage;
2565     ProcessKeySequence(aRxInfo);
2566 
2567     SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, /* aDelay */ 0, &aRxInfo.mMessage);
2568 
2569 exit:
2570     LogProcessError(kTypeDataRequest, error);
2571 }
2572 
HandleNetworkDataUpdateRouter(void)2573 void MleRouter::HandleNetworkDataUpdateRouter(void)
2574 {
2575     Ip6::Address destination;
2576     uint16_t     delay;
2577     TlvList      tlvList;
2578 
2579     VerifyOrExit(IsRouterOrLeader());
2580 
2581     destination.SetToLinkLocalAllNodesMulticast();
2582     tlvList.Add(Tlv::kNetworkData);
2583 
2584     delay = IsLeader() ? 0 : Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter);
2585     SendDataResponse(destination, tlvList, delay);
2586 
2587     SynchronizeChildNetworkData();
2588 
2589 exit:
2590     return;
2591 }
2592 
SynchronizeChildNetworkData(void)2593 void MleRouter::SynchronizeChildNetworkData(void)
2594 {
2595     VerifyOrExit(IsRouterOrLeader());
2596 
2597     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
2598     {
2599         if (child.IsRxOnWhenIdle())
2600         {
2601             continue;
2602         }
2603 
2604         if (child.GetNetworkDataVersion() == Get<NetworkData::Leader>().GetVersion(child.GetNetworkDataType()))
2605         {
2606             continue;
2607         }
2608 
2609         SuccessOrExit(SendChildUpdateRequest(child));
2610     }
2611 
2612 exit:
2613     return;
2614 }
2615 
2616 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
SetSteeringData(const Mac::ExtAddress * aExtAddress)2617 void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress)
2618 {
2619     Mac::ExtAddress nullExtAddr;
2620     Mac::ExtAddress allowAnyExtAddr;
2621 
2622     nullExtAddr.Clear();
2623     allowAnyExtAddr.Fill(0xff);
2624 
2625     if ((aExtAddress == nullptr) || (*aExtAddress == nullExtAddr))
2626     {
2627         mSteeringData.Clear();
2628     }
2629     else if (*aExtAddress == allowAnyExtAddr)
2630     {
2631         mSteeringData.SetToPermitAllJoiners();
2632     }
2633     else
2634     {
2635         Mac::ExtAddress joinerId;
2636 
2637         mSteeringData.Init();
2638         MeshCoP::ComputeJoinerId(*aExtAddress, joinerId);
2639         mSteeringData.UpdateBloomFilter(joinerId);
2640     }
2641 }
2642 #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2643 
HandleDiscoveryRequest(RxInfo & aRxInfo)2644 void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
2645 {
2646     Error                        error = kErrorNone;
2647     Tlv::ParsedInfo              tlvInfo;
2648     MeshCoP::DiscoveryRequestTlv discoveryRequestTlv;
2649     MeshCoP::ExtendedPanId       extPanId;
2650     OffsetRange                  offsetRange;
2651 
2652     Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2653 
2654     discoveryRequestTlv.SetLength(0);
2655 
2656     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2657 
2658     SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange));
2659 
2660     for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(tlvInfo.GetSize()))
2661     {
2662         SuccessOrExit(error = tlvInfo.ParseFrom(aRxInfo.mMessage, offsetRange));
2663 
2664         if (tlvInfo.mIsExtended)
2665         {
2666             continue;
2667         }
2668 
2669         switch (tlvInfo.mType)
2670         {
2671         case MeshCoP::Tlv::kDiscoveryRequest:
2672             SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryRequestTlv));
2673             VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse);
2674 
2675             break;
2676 
2677         case MeshCoP::Tlv::kExtendedPanId:
2678             SuccessOrExit(
2679                 error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offsetRange.GetOffset(), extPanId));
2680             VerifyOrExit(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId() != extPanId, error = kErrorDrop);
2681 
2682             break;
2683 
2684         default:
2685             break;
2686         }
2687     }
2688 
2689     if (discoveryRequestTlv.IsValid())
2690     {
2691         if (mDiscoveryRequestCallback.IsSet())
2692         {
2693             otThreadDiscoveryRequestInfo info;
2694 
2695             aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&info.mExtAddress));
2696             info.mVersion  = discoveryRequestTlv.GetVersion();
2697             info.mIsJoiner = discoveryRequestTlv.IsJoiner();
2698 
2699             mDiscoveryRequestCallback.Invoke(&info);
2700         }
2701 
2702         if (discoveryRequestTlv.IsJoiner())
2703         {
2704 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2705             if (!mSteeringData.IsEmpty())
2706             {
2707             }
2708             else // if steering data is not set out of band, fall back to network data
2709 #endif
2710             {
2711                 VerifyOrExit(Get<NetworkData::Leader>().IsJoiningAllowed(), error = kErrorSecurity);
2712             }
2713         }
2714     }
2715 
2716     error = SendDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), aRxInfo.mMessage);
2717 
2718 exit:
2719     LogProcessError(kTypeDiscoveryRequest, error);
2720 }
2721 
SendDiscoveryResponse(const Ip6::Address & aDestination,const Message & aDiscoverRequestMessage)2722 Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage)
2723 {
2724     Error                         error = kErrorNone;
2725     TxMessage                    *message;
2726     uint16_t                      startOffset;
2727     Tlv                           tlv;
2728     MeshCoP::DiscoveryResponseTlv discoveryResponseTlv;
2729     uint16_t                      delay;
2730 
2731     VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
2732     message->SetDirectTransmission();
2733     message->SetPanId(aDiscoverRequestMessage.GetPanId());
2734 #if OPENTHREAD_CONFIG_MULTI_RADIO
2735     // Send the MLE Discovery Response message on same radio link
2736     // from which the "MLE Discover Request" message was received.
2737     message->SetRadioType(aDiscoverRequestMessage.GetRadioType());
2738 #endif
2739 
2740     tlv.SetType(Tlv::kDiscovery);
2741     SuccessOrExit(error = message->Append(tlv));
2742 
2743     startOffset = message->GetLength();
2744 
2745     discoveryResponseTlv.Init();
2746     discoveryResponseTlv.SetVersion(kThreadVersion);
2747 
2748 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
2749     if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled)
2750     {
2751         SuccessOrExit(
2752             error = Tlv::Append<MeshCoP::CommissionerUdpPortTlv>(*message, Get<MeshCoP::BorderAgent>().GetUdpPort()));
2753 
2754         discoveryResponseTlv.SetNativeCommissioner(true);
2755     }
2756     else
2757 #endif
2758     {
2759         discoveryResponseTlv.SetNativeCommissioner(false);
2760     }
2761 
2762     if (Get<KeyManager>().GetSecurityPolicy().mCommercialCommissioningEnabled)
2763     {
2764         discoveryResponseTlv.SetCommercialCommissioningMode(true);
2765     }
2766 
2767     SuccessOrExit(error = discoveryResponseTlv.AppendTo(*message));
2768 
2769     SuccessOrExit(
2770         error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
2771 
2772     SuccessOrExit(error = Tlv::Append<MeshCoP::NetworkNameTlv>(
2773                       *message, Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsCString()));
2774 
2775     SuccessOrExit(error = message->AppendSteeringDataTlv());
2776 
2777     SuccessOrExit(
2778         error = Tlv::Append<MeshCoP::JoinerUdpPortTlv>(*message, Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()));
2779 
2780     tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
2781     message->Write(startOffset - sizeof(tlv), tlv);
2782 
2783     delay = Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter + 1);
2784 
2785     SuccessOrExit(error = message->SendAfterDelay(aDestination, delay));
2786 
2787     Log(kMessageDelay, kTypeDiscoveryResponse, aDestination);
2788 
2789 exit:
2790     FreeMessageOnError(message, error);
2791     LogProcessError(kTypeDiscoveryResponse, error);
2792     return error;
2793 }
2794 
SendChildIdResponse(Child & aChild)2795 Error MleRouter::SendChildIdResponse(Child &aChild)
2796 {
2797     Error        error = kErrorNone;
2798     Ip6::Address destination;
2799     TxMessage   *message;
2800 
2801     VerifyOrExit((message = NewMleMessage(kCommandChildIdResponse)) != nullptr, error = kErrorNoBufs);
2802     SuccessOrExit(error = message->AppendSourceAddressTlv());
2803     SuccessOrExit(error = message->AppendLeaderDataTlv());
2804     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
2805 
2806     if ((aChild.GetRloc16() == 0) || !HasMatchingRouterIdWith(aChild.GetRloc16()))
2807     {
2808         uint16_t rloc16;
2809 
2810         // Pick next Child ID that is not being used
2811         do
2812         {
2813             mNextChildId++;
2814 
2815             if (mNextChildId > kMaxChildId)
2816             {
2817                 mNextChildId = kMinChildId;
2818             }
2819 
2820             rloc16 = Get<Mac::Mac>().GetShortAddress() | mNextChildId;
2821 
2822         } while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
2823 
2824         aChild.SetRloc16(rloc16);
2825     }
2826 
2827     SuccessOrExit(error = message->AppendAddress16Tlv(aChild.GetRloc16()));
2828 
2829     for (uint8_t i = 0; i < Child::kMaxRequestTlvs; i++)
2830     {
2831         switch (aChild.GetRequestTlv(i))
2832         {
2833         case Tlv::kNetworkData:
2834             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
2835             break;
2836 
2837         case Tlv::kRoute:
2838             SuccessOrExit(error = message->AppendRouteTlv());
2839             break;
2840 
2841         case Tlv::kActiveDataset:
2842             SuccessOrExit(error = message->AppendActiveDatasetTlv());
2843             break;
2844 
2845         case Tlv::kPendingDataset:
2846             SuccessOrExit(error = message->AppendPendingDatasetTlv());
2847             break;
2848 
2849         case Tlv::kSupervisionInterval:
2850             SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild.GetSupervisionInterval()));
2851             break;
2852 
2853         default:
2854             break;
2855         }
2856     }
2857 
2858     if (!aChild.IsFullThreadDevice())
2859     {
2860         SuccessOrExit(error = message->AppendAddressRegistrationTlv(aChild));
2861     }
2862 
2863     SetChildStateToValid(aChild);
2864 
2865     if (!aChild.IsRxOnWhenIdle())
2866     {
2867         Get<IndirectSender>().SetChildUseShortAddress(aChild, false);
2868     }
2869 
2870 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2871     if (aChild.IsTimeSyncEnabled())
2872     {
2873         message->SetTimeSync(true);
2874     }
2875 #endif
2876 
2877     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
2878     SuccessOrExit(error = message->SendTo(destination));
2879 
2880     Log(kMessageSend, kTypeChildIdResponse, destination, aChild.GetRloc16());
2881 
2882 exit:
2883     FreeMessageOnError(message, error);
2884     return error;
2885 }
2886 
SendChildUpdateRequest(Child & aChild)2887 Error MleRouter::SendChildUpdateRequest(Child &aChild)
2888 {
2889     static const uint8_t kTlvs[] = {Tlv::kTimeout, Tlv::kAddressRegistration};
2890 
2891     Error        error = kErrorNone;
2892     Ip6::Address destination;
2893     TxMessage   *message = nullptr;
2894 
2895     if (!aChild.IsRxOnWhenIdle())
2896     {
2897         uint16_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
2898 
2899         for (const Message &msg : Get<MeshForwarder>().GetSendQueue())
2900         {
2901             if (msg.GetChildMask(childIndex) && msg.GetSubType() == Message::kSubTypeMleChildUpdateRequest)
2902             {
2903                 // No need to send the resync "Child Update Request"
2904                 // to the sleepy child if there is one already
2905                 // queued.
2906                 if (aChild.IsStateRestoring())
2907                 {
2908                     ExitNow();
2909                 }
2910 
2911                 // Remove queued outdated "Child Update Request" when
2912                 // there is newer Network Data is to send.
2913                 Get<MeshForwarder>().RemoveMessagesForChild(aChild, IsMessageChildUpdateRequest);
2914                 break;
2915             }
2916         }
2917     }
2918 
2919     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
2920     SuccessOrExit(error = message->AppendSourceAddressTlv());
2921     SuccessOrExit(error = message->AppendLeaderDataTlv());
2922     SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
2923     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
2924 
2925     if (aChild.IsStateValid())
2926     {
2927         SuccessOrExit(error = message->AppendLinkMarginTlv(aChild.GetLinkInfo().GetLinkMargin()));
2928     }
2929     else
2930     {
2931         SuccessOrExit(error = message->AppendTlvRequestTlv(kTlvs));
2932 
2933         if (!aChild.IsStateRestored())
2934         {
2935             // A random challenge is generated and saved when `aChild`
2936             // is first initialized in `kStateRestored`. We will use
2937             // the saved challenge here. This prevents overwriting
2938             // the saved challenge when the child is also detached
2939             // and happens to send a "Parent Request" in the window
2940             // where the parent transitions to the router/leader role
2941             // and before the parent sends the "Child Update Request".
2942             // This ensures that the same random challenge is
2943             // included in both "Parent Response" and "Child Update
2944             // Response," guaranteeing proper acceptance of the
2945             // child's "Child ID request".
2946 
2947             aChild.GenerateChallenge();
2948         }
2949 
2950         SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge()));
2951     }
2952 
2953     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
2954     SuccessOrExit(error = message->SendTo(destination));
2955 
2956     if (aChild.IsRxOnWhenIdle())
2957     {
2958         // only try to send a single Child Update Request message to an rx-on-when-idle child
2959         aChild.SetState(Child::kStateChildUpdateRequest);
2960     }
2961 
2962     Log(kMessageSend, kTypeChildUpdateRequestOfChild, destination, aChild.GetRloc16());
2963 
2964 exit:
2965     FreeMessageOnError(message, error);
2966     return error;
2967 }
2968 
SendChildUpdateResponse(Child * aChild,const Ip6::MessageInfo & aMessageInfo,const TlvList & aTlvList,const RxChallenge & aChallenge)2969 void MleRouter::SendChildUpdateResponse(Child                  *aChild,
2970                                         const Ip6::MessageInfo &aMessageInfo,
2971                                         const TlvList          &aTlvList,
2972                                         const RxChallenge      &aChallenge)
2973 {
2974     Error      error = kErrorNone;
2975     TxMessage *message;
2976 
2977     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs);
2978 
2979     for (uint8_t tlvType : aTlvList)
2980     {
2981         // Add all TLV types that do not depend on `child`
2982 
2983         switch (tlvType)
2984         {
2985         case Tlv::kStatus:
2986             SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError));
2987             break;
2988 
2989         case Tlv::kLeaderData:
2990             SuccessOrExit(error = message->AppendLeaderDataTlv());
2991             break;
2992 
2993         case Tlv::kResponse:
2994             SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
2995             break;
2996 
2997         case Tlv::kSourceAddress:
2998             SuccessOrExit(error = message->AppendSourceAddressTlv());
2999             break;
3000 
3001         case Tlv::kMleFrameCounter:
3002             SuccessOrExit(error = message->AppendMleFrameCounterTlv());
3003             break;
3004 
3005         case Tlv::kLinkFrameCounter:
3006             SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
3007             break;
3008         }
3009 
3010         // Make sure `child` is not null before adding TLV types
3011         // that can depend on it.
3012 
3013         if (aChild == nullptr)
3014         {
3015             continue;
3016         }
3017 
3018         switch (tlvType)
3019         {
3020         case Tlv::kAddressRegistration:
3021             SuccessOrExit(error = message->AppendAddressRegistrationTlv(*aChild));
3022             break;
3023 
3024         case Tlv::kMode:
3025             SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode()));
3026             break;
3027 
3028         case Tlv::kNetworkData:
3029             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild->GetNetworkDataType()));
3030             SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3031             break;
3032 
3033         case Tlv::kTimeout:
3034             SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
3035             break;
3036 
3037         case Tlv::kLinkMargin:
3038             SuccessOrExit(error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin()));
3039             break;
3040 
3041         case Tlv::kSupervisionInterval:
3042             SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild->GetSupervisionInterval()));
3043             break;
3044 
3045 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
3046         case Tlv::kCslClockAccuracy:
3047             if (!aChild->IsRxOnWhenIdle())
3048             {
3049                 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
3050             }
3051             break;
3052 #endif
3053         }
3054     }
3055 
3056     SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
3057 
3058     if (aChild == nullptr)
3059     {
3060         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr());
3061     }
3062     else
3063     {
3064         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr(), aChild->GetRloc16());
3065     }
3066 
3067 exit:
3068     FreeMessageOnError(message, error);
3069 }
3070 
SendDataResponse(const Ip6::Address & aDestination,const TlvList & aTlvList,uint16_t aDelay,const Message * aRequestMessage)3071 void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
3072                                  const TlvList      &aTlvList,
3073                                  uint16_t            aDelay,
3074                                  const Message      *aRequestMessage)
3075 {
3076     OT_UNUSED_VARIABLE(aRequestMessage);
3077 
3078     Error      error   = kErrorNone;
3079     TxMessage *message = nullptr;
3080     Neighbor  *neighbor;
3081 
3082     if (mRetrieveNewNetworkData)
3083     {
3084         LogInfo("Suppressing Data Response - waiting for new network data");
3085         ExitNow();
3086     }
3087 
3088     VerifyOrExit((message = NewMleMessage(kCommandDataResponse)) != nullptr, error = kErrorNoBufs);
3089     SuccessOrExit(error = message->AppendSourceAddressTlv());
3090     SuccessOrExit(error = message->AppendLeaderDataTlv());
3091     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3092 
3093     for (uint8_t tlvType : aTlvList)
3094     {
3095         switch (tlvType)
3096         {
3097         case Tlv::kNetworkData:
3098             neighbor = mNeighborTable.FindNeighbor(aDestination);
3099             SuccessOrExit(error = message->AppendNetworkDataTlv((neighbor != nullptr) ? neighbor->GetNetworkDataType()
3100                                                                                       : NetworkData::kFullSet));
3101             break;
3102 
3103         case Tlv::kActiveDataset:
3104             SuccessOrExit(error = message->AppendActiveDatasetTlv());
3105             break;
3106 
3107         case Tlv::kPendingDataset:
3108             SuccessOrExit(error = message->AppendPendingDatasetTlv());
3109             break;
3110 
3111         case Tlv::kRoute:
3112             SuccessOrExit(error = message->AppendRouteTlv());
3113             break;
3114 
3115 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3116         case Tlv::kLinkMetricsReport:
3117             OT_ASSERT(aRequestMessage != nullptr);
3118             neighbor = mNeighborTable.FindNeighbor(aDestination);
3119             VerifyOrExit(neighbor != nullptr, error = kErrorInvalidState);
3120             SuccessOrExit(error = Get<LinkMetrics::Subject>().AppendReport(*message, *aRequestMessage, *neighbor));
3121             break;
3122 #endif
3123         }
3124     }
3125 
3126     if (aDelay)
3127     {
3128         Get<MeshForwarder>().RemoveDataResponseMessages();
3129 
3130         RemoveDelayedDataResponseMessage();
3131 
3132         SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay));
3133         Log(kMessageDelay, kTypeDataResponse, aDestination);
3134     }
3135     else
3136     {
3137         SuccessOrExit(error = message->SendTo(aDestination));
3138         Log(kMessageSend, kTypeDataResponse, aDestination);
3139     }
3140 
3141 exit:
3142     FreeMessageOnError(message, error);
3143     LogSendError(kTypeDataResponse, error);
3144 }
3145 
RemoveRouterLink(Router & aRouter)3146 void MleRouter::RemoveRouterLink(Router &aRouter)
3147 {
3148     switch (mRole)
3149     {
3150     case kRoleChild:
3151         if (&aRouter == &mParent)
3152         {
3153             IgnoreError(BecomeDetached());
3154         }
3155         break;
3156 
3157     case kRoleRouter:
3158     case kRoleLeader:
3159         mRouterTable.RemoveRouterLink(aRouter);
3160         break;
3161 
3162     default:
3163         break;
3164     }
3165 }
3166 
RemoveNeighbor(Neighbor & aNeighbor)3167 void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
3168 {
3169     VerifyOrExit(!aNeighbor.IsStateInvalid());
3170 
3171     if (&aNeighbor == &mParent)
3172     {
3173         if (IsChild())
3174         {
3175             IgnoreError(BecomeDetached());
3176         }
3177     }
3178     else if (&aNeighbor == &GetParentCandidate())
3179     {
3180         ClearParentCandidate();
3181     }
3182     else if (IsChildRloc16(aNeighbor.GetRloc16()))
3183     {
3184         OT_ASSERT(mChildTable.Contains(aNeighbor));
3185 
3186         if (aNeighbor.IsStateValidOrRestoring())
3187         {
3188             mNeighborTable.Signal(NeighborTable::kChildRemoved, aNeighbor);
3189         }
3190 
3191         Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
3192 
3193         if (aNeighbor.IsFullThreadDevice())
3194         {
3195             Get<AddressResolver>().RemoveEntriesForRloc16(aNeighbor.GetRloc16());
3196         }
3197 
3198         mChildTable.RemoveStoredChild(static_cast<Child &>(aNeighbor));
3199     }
3200     else if (aNeighbor.IsStateValid())
3201     {
3202         OT_ASSERT(mRouterTable.Contains(aNeighbor));
3203 
3204         mNeighborTable.Signal(NeighborTable::kRouterRemoved, aNeighbor);
3205         mRouterTable.RemoveRouterLink(static_cast<Router &>(aNeighbor));
3206     }
3207 
3208     aNeighbor.GetLinkInfo().Clear();
3209     aNeighbor.SetState(Neighbor::kStateInvalid);
3210 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3211     aNeighbor.RemoveAllForwardTrackingSeriesInfo();
3212 #endif
3213 
3214 exit:
3215     return;
3216 }
3217 
SetPreferredRouterId(uint8_t aRouterId)3218 Error MleRouter::SetPreferredRouterId(uint8_t aRouterId)
3219 {
3220     Error error = kErrorNone;
3221 
3222     VerifyOrExit(IsDetached() || IsDisabled(), error = kErrorInvalidState);
3223 
3224     mPreviousRouterId = aRouterId;
3225 
3226 exit:
3227     return error;
3228 }
3229 
SetRouterId(uint8_t aRouterId)3230 void MleRouter::SetRouterId(uint8_t aRouterId)
3231 {
3232     mRouterId         = aRouterId;
3233     mPreviousRouterId = mRouterId;
3234 }
3235 
SendAddressSolicit(ThreadStatusTlv::Status aStatus)3236 Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
3237 {
3238     Error            error = kErrorNone;
3239     Tmf::MessageInfo messageInfo(GetInstance());
3240     Coap::Message   *message = nullptr;
3241 
3242     VerifyOrExit(!mAddressSolicitPending);
3243 
3244     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressSolicit);
3245     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3246 
3247     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3248 
3249     if (IsRouterIdValid(mPreviousRouterId))
3250     {
3251         SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mPreviousRouterId)));
3252     }
3253 
3254     SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
3255 
3256 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3257     SuccessOrExit(error = Tlv::Append<XtalAccuracyTlv>(*message, otPlatTimeGetXtalAccuracy()));
3258 #endif
3259 
3260     messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3261 
3262     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this));
3263     mAddressSolicitPending = true;
3264 
3265     Log(kMessageSend, kTypeAddressSolicit, messageInfo.GetPeerAddr());
3266 
3267 exit:
3268     FreeMessageOnError(message, error);
3269     return error;
3270 }
3271 
SendAddressRelease(void)3272 void MleRouter::SendAddressRelease(void)
3273 {
3274     Error            error = kErrorNone;
3275     Tmf::MessageInfo messageInfo(GetInstance());
3276     Coap::Message   *message;
3277 
3278     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressRelease);
3279     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3280 
3281     SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mRouterId)));
3282     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3283 
3284     messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3285 
3286     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
3287 
3288     Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr());
3289 
3290 exit:
3291     FreeMessageOnError(message, error);
3292     LogSendError(kTypeAddressRelease, error);
3293 }
3294 
HandleAddressSolicitResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)3295 void MleRouter::HandleAddressSolicitResponse(void                *aContext,
3296                                              otMessage           *aMessage,
3297                                              const otMessageInfo *aMessageInfo,
3298                                              Error                aResult)
3299 {
3300     static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(AsCoapMessagePtr(aMessage),
3301                                                                      AsCoreTypePtr(aMessageInfo), aResult);
3302 }
3303 
HandleAddressSolicitResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)3304 void MleRouter::HandleAddressSolicitResponse(Coap::Message          *aMessage,
3305                                              const Ip6::MessageInfo *aMessageInfo,
3306                                              Error                   aResult)
3307 {
3308     uint8_t             status;
3309     uint16_t            rloc16;
3310     ThreadRouterMaskTlv routerMaskTlv;
3311     uint8_t             routerId;
3312     Router             *router;
3313 
3314     mAddressSolicitPending = false;
3315 
3316     VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
3317 
3318     VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
3319 
3320     Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
3321 
3322     SuccessOrExit(Tlv::Find<ThreadStatusTlv>(*aMessage, status));
3323 
3324     if (status != ThreadStatusTlv::kSuccess)
3325     {
3326         mAddressSolicitRejected = true;
3327 
3328         if (IsRouterIdValid(mPreviousRouterId))
3329         {
3330             if (HasChildren())
3331             {
3332                 RemoveChildren();
3333             }
3334 
3335             SetRouterId(kInvalidRouterId);
3336         }
3337 
3338         ExitNow();
3339     }
3340 
3341     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
3342     routerId = RouterIdFromRloc16(rloc16);
3343 
3344     SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
3345     VerifyOrExit(routerMaskTlv.IsValid());
3346 
3347     SetRouterId(routerId);
3348 
3349     SetStateRouter(Rloc16FromRouterId(mRouterId));
3350 
3351     // We keep the router table next hop and cost as what we had as a
3352     // REED, i.e., our parent was the next hop towards all other
3353     // routers and we tracked its cost towards them. As FED, we may
3354     // have established links with a subset of neighboring routers.
3355     // We ensure to clear these links to avoid using them (since will
3356     // be rejected by the neighbor).
3357 
3358     mRouterTable.ClearNeighbors();
3359 
3360     mRouterTable.UpdateRouterIdSet(routerMaskTlv.GetIdSequence(), routerMaskTlv.GetAssignedRouterIdMask());
3361 
3362     router = mRouterTable.FindRouterById(routerId);
3363     VerifyOrExit(router != nullptr);
3364     router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
3365     router->SetNextHopToInvalid();
3366 
3367     // Ensure we have our parent as a neighboring router, copying the
3368     // `mParent` entry.
3369 
3370     router = mRouterTable.FindRouterById(mParent.GetRouterId());
3371     VerifyOrExit(router != nullptr);
3372     router->SetFrom(mParent);
3373     router->SetState(Neighbor::kStateValid);
3374     router->SetNextHopToInvalid();
3375 
3376     // Ensure we have a next hop and cost towards leader.
3377     if (mRouterTable.GetPathCostToLeader() >= kMaxRouteCost)
3378     {
3379         Router *leader = mRouterTable.GetLeader();
3380 
3381         OT_ASSERT(leader != nullptr);
3382         leader->SetNextHopAndCost(RouterIdFromRloc16(mParent.GetRloc16()), mParent.GetLeaderCost());
3383     }
3384 
3385     // We send a unicast Link Request to our former parent if its
3386     // version is earlier than 1.3. This is to address a potential
3387     // compatibility issue with some non-OpenThread stacks which may
3388     // ignore MLE Advertisements from a former/existing child.
3389 
3390     if (mParent.GetVersion() < kThreadVersion1p3)
3391     {
3392         IgnoreError(SendLinkRequest(&mParent));
3393     }
3394 
3395     // We send an Advertisement to inform our former parent of our
3396     // newly allocated Router ID. This will cause the parent to
3397     // reset its advertisement trickle timer which can help speed
3398     // up the dissemination of the new Router ID to other routers.
3399     // This can also help with quicker link establishment with our
3400     // former parent and other routers.
3401     SendAdvertisement();
3402 
3403     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
3404     {
3405         IgnoreError(SendChildIdResponse(child));
3406     }
3407 
3408 exit:
3409     InformPreviousChannel();
3410 }
3411 
SetChildRouterLinks(uint8_t aChildRouterLinks)3412 Error MleRouter::SetChildRouterLinks(uint8_t aChildRouterLinks)
3413 {
3414     Error error = kErrorNone;
3415 
3416     VerifyOrExit(IsDisabled(), error = kErrorInvalidState);
3417     mChildRouterLinks = aChildRouterLinks;
3418 exit:
3419     return error;
3420 }
3421 
IsExpectedToBecomeRouterSoon(void) const3422 bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
3423 {
3424     static constexpr uint8_t kMaxDelay = 10;
3425 
3426     return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
3427            ((mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay) ||
3428             mAddressSolicitPending);
3429 }
3430 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3431 template <> void MleRouter::HandleTmf<kUriAddressSolicit>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3432 {
3433     Error                   error          = kErrorNone;
3434     ThreadStatusTlv::Status responseStatus = ThreadStatusTlv::kNoAddressAvailable;
3435     Router                 *router         = nullptr;
3436     Mac::ExtAddress         extAddress;
3437     uint16_t                rloc16;
3438     uint8_t                 status;
3439 
3440     VerifyOrExit(mRole == kRoleLeader, error = kErrorInvalidState);
3441 
3442     VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
3443 
3444     Log(kMessageReceive, kTypeAddressSolicit, aMessageInfo.GetPeerAddr());
3445 
3446     SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3447     SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
3448 
3449     switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
3450     {
3451     case kErrorNone:
3452         break;
3453     case kErrorNotFound:
3454         rloc16 = kInvalidRloc16;
3455         break;
3456     default:
3457         ExitNow(error = kErrorParse);
3458     }
3459 
3460 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3461     {
3462         uint16_t xtalAccuracy;
3463 
3464         SuccessOrExit(Tlv::Find<XtalAccuracyTlv>(aMessage, xtalAccuracy));
3465         VerifyOrExit(xtalAccuracy <= Get<TimeSync>().GetXtalThreshold());
3466     }
3467 #endif
3468 
3469     router = mRouterTable.FindRouter(extAddress);
3470 
3471     if (router != nullptr)
3472     {
3473         responseStatus = ThreadStatusTlv::kSuccess;
3474         ExitNow();
3475     }
3476 
3477     switch (status)
3478     {
3479     case ThreadStatusTlv::kTooFewRouters:
3480         VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
3481         break;
3482 
3483     case ThreadStatusTlv::kHaveChildIdRequest:
3484     case ThreadStatusTlv::kParentPartitionChange:
3485         break;
3486 
3487     case ThreadStatusTlv::kBorderRouterRequest:
3488         if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
3489             (Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
3490              kRouterUpgradeBorderRouterRequestThreshold))
3491         {
3492             LogInfo("Rejecting BR %s router role req - have %u BR routers", extAddress.ToString().AsCString(),
3493                     kRouterUpgradeBorderRouterRequestThreshold);
3494             ExitNow();
3495         }
3496         break;
3497 
3498     default:
3499         responseStatus = ThreadStatusTlv::kUnrecognizedStatus;
3500         ExitNow();
3501     }
3502 
3503     if (rloc16 != kInvalidRloc16)
3504     {
3505         router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16));
3506 
3507         if (router != nullptr)
3508         {
3509             LogInfo("Router id %u requested and provided!", RouterIdFromRloc16(rloc16));
3510         }
3511     }
3512 
3513     if (router == nullptr)
3514     {
3515         router = mRouterTable.Allocate();
3516         VerifyOrExit(router != nullptr);
3517     }
3518 
3519     router->SetExtAddress(extAddress);
3520     responseStatus = ThreadStatusTlv::kSuccess;
3521 
3522 exit:
3523     if (error == kErrorNone)
3524     {
3525         SendAddressSolicitResponse(aMessage, responseStatus, router, aMessageInfo);
3526     }
3527 }
3528 
SendAddressSolicitResponse(const Coap::Message & aRequest,ThreadStatusTlv::Status aResponseStatus,const Router * aRouter,const Ip6::MessageInfo & aMessageInfo)3529 void MleRouter::SendAddressSolicitResponse(const Coap::Message    &aRequest,
3530                                            ThreadStatusTlv::Status aResponseStatus,
3531                                            const Router           *aRouter,
3532                                            const Ip6::MessageInfo &aMessageInfo)
3533 {
3534     Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
3535 
3536     VerifyOrExit(message != nullptr);
3537 
3538     SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aResponseStatus));
3539 
3540     if (aRouter != nullptr)
3541     {
3542         ThreadRouterMaskTlv routerMaskTlv;
3543 
3544         SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aRouter->GetRloc16()));
3545 
3546         routerMaskTlv.Init();
3547         routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3548         mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask());
3549 
3550         SuccessOrExit(routerMaskTlv.AppendTo(*message));
3551     }
3552 
3553     SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
3554     message = nullptr;
3555 
3556     Log(kMessageSend, kTypeAddressReply, aMessageInfo.GetPeerAddr());
3557 
3558     // If assigning a new RLOC16 (e.g., on promotion of a child to
3559     // router role) we clear any address cache entries associated
3560     // with the old RLOC16 unless the sender is a direct child. For
3561     // direct children, we retain the cache entries to allow
3562     // association with the promoted router's new RLOC16 upon
3563     // receiving its Link Advertisement.
3564 
3565     if ((aResponseStatus == ThreadStatusTlv::kSuccess) && (aRouter != nullptr))
3566     {
3567         uint16_t oldRloc16;
3568 
3569         VerifyOrExit(IsRoutingLocator(aMessageInfo.GetPeerAddr()));
3570         oldRloc16 = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
3571 
3572         VerifyOrExit(oldRloc16 != aRouter->GetRloc16());
3573         VerifyOrExit(!RouterIdMatch(oldRloc16, GetRloc16()));
3574         Get<AddressResolver>().RemoveEntriesForRloc16(oldRloc16);
3575     }
3576 
3577 exit:
3578     FreeMessage(message);
3579 }
3580 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3581 template <> void MleRouter::HandleTmf<kUriAddressRelease>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3582 {
3583     uint16_t        rloc16;
3584     Mac::ExtAddress extAddress;
3585     uint8_t         routerId;
3586     Router         *router;
3587 
3588     VerifyOrExit(mRole == kRoleLeader);
3589 
3590     VerifyOrExit(aMessage.IsConfirmablePostRequest());
3591 
3592     Log(kMessageReceive, kTypeAddressRelease, aMessageInfo.GetPeerAddr());
3593 
3594     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16));
3595     SuccessOrExit(Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3596 
3597     routerId = RouterIdFromRloc16(rloc16);
3598     router   = mRouterTable.FindRouterById(routerId);
3599 
3600     VerifyOrExit((router != nullptr) && (router->GetExtAddress() == extAddress));
3601 
3602     IgnoreError(mRouterTable.Release(routerId));
3603 
3604     SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
3605 
3606     Log(kMessageSend, kTypeAddressReleaseReply, aMessageInfo.GetPeerAddr());
3607 
3608 exit:
3609     return;
3610 }
3611 
FillConnectivityTlv(ConnectivityTlv & aTlv)3612 void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
3613 {
3614     int8_t parentPriority = kParentPriorityMedium;
3615 
3616     if (mParentPriority != kParentPriorityUnspecified)
3617     {
3618         parentPriority = mParentPriority;
3619     }
3620     else
3621     {
3622         uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
3623         uint16_t maxAllowed  = mChildTable.GetMaxChildrenAllowed();
3624 
3625         if ((maxAllowed - numChildren) < (maxAllowed / 3))
3626         {
3627             parentPriority = kParentPriorityLow;
3628         }
3629         else
3630         {
3631             parentPriority = kParentPriorityMedium;
3632         }
3633     }
3634 
3635     aTlv.SetParentPriority(parentPriority);
3636 
3637     aTlv.SetLinkQuality1(0);
3638     aTlv.SetLinkQuality2(0);
3639     aTlv.SetLinkQuality3(0);
3640 
3641     if (IsChild())
3642     {
3643         aTlv.IncrementLinkQuality(mParent.GetLinkQualityIn());
3644     }
3645 
3646     for (const Router &router : Get<RouterTable>())
3647     {
3648         if (router.GetRloc16() == GetRloc16())
3649         {
3650             continue;
3651         }
3652 
3653         if (!router.IsStateValid())
3654         {
3655             continue;
3656         }
3657 
3658         aTlv.IncrementLinkQuality(router.GetTwoWayLinkQuality());
3659     }
3660 
3661     aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
3662     aTlv.SetLeaderCost(Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost));
3663     aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3664     aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
3665     aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
3666 }
3667 
ShouldDowngrade(uint8_t aNeighborId,const RouteTlv & aRouteTlv) const3668 bool MleRouter::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
3669 {
3670     // Determine whether all conditions are satisfied for the router
3671     // to downgrade after receiving info for a neighboring router
3672     // with Router ID `aNeighborId` along with its `aRouteTlv`.
3673 
3674     bool    shouldDowngrade   = false;
3675     uint8_t activeRouterCount = mRouterTable.GetActiveRouterCount();
3676     uint8_t count;
3677 
3678     VerifyOrExit(IsRouter());
3679     VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
3680 
3681     VerifyOrExit(!mRouterRoleTransition.IsPending());
3682 
3683     VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
3684 
3685     // Check that we have at least `kMinDowngradeNeighbors`
3686     // neighboring routers with two-way link quality of 2 or better.
3687 
3688     count = 0;
3689 
3690     for (const Router &router : mRouterTable)
3691     {
3692         if (!router.IsStateValid() || (router.GetTwoWayLinkQuality() < kLinkQuality2))
3693         {
3694             continue;
3695         }
3696 
3697         count++;
3698 
3699         if (count >= kMinDowngradeNeighbors)
3700         {
3701             break;
3702         }
3703     }
3704 
3705     VerifyOrExit(count >= kMinDowngradeNeighbors);
3706 
3707     // Check that we have fewer children than three times the number
3708     // of excess routers (defined as the difference between number of
3709     // active routers and `mRouterDowngradeThreshold`).
3710 
3711     count = activeRouterCount - mRouterDowngradeThreshold;
3712     VerifyOrExit(mChildTable.GetNumChildren(Child::kInStateValid) < count * 3);
3713 
3714     // Check that the neighbor has as good or better-quality links to
3715     // same routers.
3716 
3717     VerifyOrExit(NeighborHasComparableConnectivity(aRouteTlv, aNeighborId));
3718 
3719 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3720     // Check if we are eligible to be router due to being a BR.
3721     VerifyOrExit(!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter());
3722 #endif
3723 
3724     shouldDowngrade = true;
3725 
3726 exit:
3727     return shouldDowngrade;
3728 }
3729 
NeighborHasComparableConnectivity(const RouteTlv & aRouteTlv,uint8_t aNeighborId) const3730 bool MleRouter::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const
3731 {
3732     // Check whether the neighboring router with Router ID `aNeighborId`
3733     // (along with its `aRouteTlv`) has as good or better-quality links
3734     // to all our neighboring routers which have a two-way link quality
3735     // of two or better.
3736 
3737     bool isComparable = true;
3738 
3739     for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId;
3740          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
3741     {
3742         const Router *router;
3743         LinkQuality   localLinkQuality;
3744         LinkQuality   peerLinkQuality;
3745 
3746         if ((routerId == mRouterId) || (routerId == aNeighborId))
3747         {
3748             continue;
3749         }
3750 
3751         router = mRouterTable.FindRouterById(routerId);
3752 
3753         if ((router == nullptr) || !router->IsStateValid())
3754         {
3755             continue;
3756         }
3757 
3758         localLinkQuality = router->GetTwoWayLinkQuality();
3759 
3760         if (localLinkQuality < kLinkQuality2)
3761         {
3762             continue;
3763         }
3764 
3765         // `router` is our neighbor with two-way link quality of
3766         // at least two. Check that `aRouteTlv` has as good or
3767         // better-quality link to it as well.
3768 
3769         if (!aRouteTlv.IsRouterIdSet(routerId))
3770         {
3771             ExitNow(isComparable = false);
3772         }
3773 
3774         peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index));
3775 
3776         if (peerLinkQuality < localLinkQuality)
3777         {
3778             ExitNow(isComparable = false);
3779         }
3780     }
3781 
3782 exit:
3783     return isComparable;
3784 }
3785 
SetChildStateToValid(Child & aChild)3786 void MleRouter::SetChildStateToValid(Child &aChild)
3787 {
3788     VerifyOrExit(!aChild.IsStateValid());
3789 
3790     aChild.SetState(Neighbor::kStateValid);
3791     IgnoreError(mChildTable.StoreChild(aChild));
3792 
3793 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
3794     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, MlrManager::MlrAddressArray());
3795 #endif
3796 
3797     mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
3798 
3799 exit:
3800     return;
3801 }
3802 
HasChildren(void)3803 bool MleRouter::HasChildren(void) { return mChildTable.HasChildren(Child::kInStateValidOrAttaching); }
3804 
RemoveChildren(void)3805 void MleRouter::RemoveChildren(void)
3806 {
3807     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
3808     {
3809         RemoveNeighbor(child);
3810     }
3811 }
3812 
SetAssignParentPriority(int8_t aParentPriority)3813 Error MleRouter::SetAssignParentPriority(int8_t aParentPriority)
3814 {
3815     Error error = kErrorNone;
3816 
3817     VerifyOrExit(aParentPriority <= kParentPriorityHigh && aParentPriority >= kParentPriorityUnspecified,
3818                  error = kErrorInvalidArgs);
3819 
3820     mParentPriority = aParentPriority;
3821 
3822 exit:
3823     return error;
3824 }
3825 
GetMaxChildTimeout(uint32_t & aTimeout) const3826 Error MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
3827 {
3828     Error error = kErrorNotFound;
3829 
3830     aTimeout = 0;
3831 
3832     VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
3833 
3834     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
3835     {
3836         if (child.IsFullThreadDevice())
3837         {
3838             continue;
3839         }
3840 
3841         if (child.GetTimeout() > aTimeout)
3842         {
3843             aTimeout = child.GetTimeout();
3844         }
3845 
3846         error = kErrorNone;
3847     }
3848 
3849 exit:
3850     return error;
3851 }
3852 
3853 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
SendTimeSync(void)3854 Error MleRouter::SendTimeSync(void)
3855 {
3856     Error        error = kErrorNone;
3857     Ip6::Address destination;
3858     TxMessage   *message = nullptr;
3859 
3860     VerifyOrExit((message = NewMleMessage(kCommandTimeSync)) != nullptr, error = kErrorNoBufs);
3861 
3862     message->SetTimeSync(true);
3863 
3864     destination.SetToLinkLocalAllNodesMulticast();
3865     SuccessOrExit(error = message->SendTo(destination));
3866 
3867     Log(kMessageSend, kTypeTimeSync, destination);
3868 
3869 exit:
3870     FreeMessageOnError(message, error);
3871     return error;
3872 }
3873 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3874 
3875 //----------------------------------------------------------------------------------------------------------------------
3876 // RouterRoleTransition
3877 
RouterRoleTransition(void)3878 MleRouter::RouterRoleTransition::RouterRoleTransition(void)
3879     : mTimeout(0)
3880     , mJitter(kRouterSelectionJitter)
3881 {
3882 }
3883 
StartTimeout(void)3884 void MleRouter::RouterRoleTransition::StartTimeout(void)
3885 {
3886     mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter);
3887 }
3888 
HandleTimeTick(void)3889 bool MleRouter::RouterRoleTransition::HandleTimeTick(void)
3890 {
3891     bool expired = false;
3892 
3893     VerifyOrExit(mTimeout > 0);
3894     mTimeout--;
3895     expired = (mTimeout == 0);
3896 
3897 exit:
3898     return expired;
3899 }
3900 
3901 } // namespace Mle
3902 } // namespace ot
3903 
3904 #endif // OPENTHREAD_FTD
3905