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