• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *  1. Redistributions of source code must retain the above copyright
7  *     notice, this list of conditions and the following disclaimer.
8  *  2. Redistributions in binary form must reproduce the above copyright
9  *     notice, this list of conditions and the following disclaimer in the
10  *     documentation and/or other materials provided with the distribution.
11  *  3. Neither the name of the copyright holder nor the
12  *     names of its contributors may be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * @file
30  *   This file implements MLE functionality required for the Thread Router and Leader roles.
31  */
32 
33 #include "mle_router.hpp"
34 
35 #if OPENTHREAD_FTD
36 
37 #include "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 OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
1724         router.DecrementParentReselectTimeout();
1725 
1726         if (age >= kMaxNeighborAge)
1727         {
1728             router.SetSelectableAsParent(false);
1729         }
1730 #endif
1731         if (router.IsStateValid())
1732         {
1733             // Neighbor router age and link recovery
1734             //
1735             // If the device is an FTD child and has more than
1736             // `mChildRouterLinks` neighbors, it uses a longer age,
1737             // `kMaxNeighborAgeOnChild`, and removes the neighboring
1738             // router upon expiration without trying to re-establish
1739             // its link with it.
1740             //
1741             // Otherwise, if the device itself is a router, or it is an
1742             // FTD child with `mChildRouterLinks` or fewer neighbors,
1743             // it uses a shorter `kMaxNeighborAge`. Upon expiration, it
1744             // tries to re-establish its link with the neighboring router.
1745 
1746             if (IsChild() && (mRouterTable.GetNeighborCount(kLinkQuality1) > mChildRouterLinks))
1747             {
1748                 if (age >= kMaxNeighborAgeOnChild)
1749                 {
1750                     LogInfo("No Adv from router 0x%04x - removing router", router.GetRloc16());
1751                     mDelayedSender.RemoveScheduledLinkRequest(router);
1752                     RemoveNeighbor(router);
1753                     continue;
1754                 }
1755             }
1756             else if (age >= kMaxNeighborAge)
1757             {
1758                 // We send a Link Request every time tick (second), up to
1759                 // max attempts. Each transmission is randomly delayed
1760                 // (one-second window). After the last attempt, we wait for
1761                 // the "Link Accept" timeout (~3 seconds) before removing the
1762                 // neighboring router.
1763 
1764                 if (!mDelayedSender.HasAnyScheduledLinkRequest(router) && !router.IsWaitingForLinkAccept())
1765                 {
1766                     LogInfo("No Adv from router 0x%04x - sending Link Request", router.GetRloc16());
1767                     router.SetLinkRequestAttemptsToMax();
1768                 }
1769 
1770                 if (router.HasRemainingLinkRequestAttempts())
1771                 {
1772                     router.DecrementLinkRequestAttempts();
1773                     mDelayedSender.ScheduleLinkRequest(
1774                         router, Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter));
1775                 }
1776             }
1777         }
1778 
1779         if (router.IsWaitingForLinkAccept() && (router.DecrementLinkAcceptTimeout() == 0))
1780         {
1781             LogInfo("Router 0x%04x - Link Accept timeout expired", router.GetRloc16());
1782             RemoveNeighbor(router);
1783             continue;
1784         }
1785 
1786         if (IsLeader() && (mRouterTable.FindNextHopOf(router) == nullptr) &&
1787             (mRouterTable.GetLinkCost(router) >= kMaxRouteCost) && (age >= kMaxLeaderToRouterTimeout))
1788         {
1789             LogInfo("Router 0x%04x ID timeout expired (no route)", router.GetRloc16());
1790             IgnoreError(mRouterTable.Release(router.GetRouterId()));
1791         }
1792     }
1793 
1794     mRouterTable.HandleTimeTick();
1795 
1796     SynchronizeChildNetworkData();
1797 
1798 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1799     if (IsRouterOrLeader())
1800     {
1801         Get<TimeSync>().ProcessTimeSync();
1802     }
1803 #endif
1804 
1805 exit:
1806     return;
1807 }
1808 
SendParentResponse(const ParentResponseInfo & aInfo)1809 void MleRouter::SendParentResponse(const ParentResponseInfo &aInfo)
1810 {
1811     Error        error   = kErrorNone;
1812     TxMessage   *message = nullptr;
1813     Child       *child;
1814     Ip6::Address destination;
1815 
1816     child = mChildTable.FindChild(aInfo.mChildExtAddress, Child::kInStateAnyExceptInvalid);
1817     VerifyOrExit(child != nullptr);
1818 
1819     VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs);
1820     message->SetDirectTransmission();
1821 
1822     SuccessOrExit(error = message->AppendSourceAddressTlv());
1823     SuccessOrExit(error = message->AppendLeaderDataTlv());
1824     SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
1825     SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge));
1826 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1827     if (child->IsTimeSyncEnabled())
1828     {
1829         SuccessOrExit(error = message->AppendTimeParameterTlv());
1830     }
1831 #endif
1832 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1833     if (child->IsThreadVersionCslCapable())
1834     {
1835         SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
1836     }
1837 #endif
1838     child->GenerateChallenge();
1839     SuccessOrExit(error = message->AppendChallengeTlv(child->GetChallenge()));
1840     SuccessOrExit(error = message->AppendLinkMarginTlv(child->GetLinkInfo().GetLinkMargin()));
1841     SuccessOrExit(error = message->AppendConnectivityTlv());
1842     SuccessOrExit(error = message->AppendVersionTlv());
1843 
1844     destination.SetToLinkLocalAddress(aInfo.mChildExtAddress);
1845 
1846     SuccessOrExit(error = message->SendTo(destination));
1847 
1848     Log(kMessageSend, kTypeParentResponse, destination);
1849 
1850 exit:
1851     FreeMessageOnError(message, error);
1852     LogSendError(kTypeParentResponse, error);
1853 }
1854 
GetMaxChildIpAddresses(void) const1855 uint8_t MleRouter::GetMaxChildIpAddresses(void) const
1856 {
1857     uint8_t num = kMaxChildIpAddresses;
1858 
1859 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1860     if (mMaxChildIpAddresses != 0)
1861     {
1862         num = mMaxChildIpAddresses;
1863     }
1864 #endif
1865 
1866     return num;
1867 }
1868 
1869 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)1870 Error MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)
1871 {
1872     Error error = kErrorNone;
1873 
1874     VerifyOrExit(aMaxIpAddresses <= kMaxChildIpAddresses, error = kErrorInvalidArgs);
1875 
1876     mMaxChildIpAddresses = aMaxIpAddresses;
1877 
1878 exit:
1879     return error;
1880 }
1881 #endif
1882 
ProcessAddressRegistrationTlv(RxInfo & aRxInfo,Child & aChild)1883 Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
1884 {
1885     Error       error;
1886     OffsetRange offsetRange;
1887     uint8_t     count       = 0;
1888     uint8_t     storedCount = 0;
1889 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1890     Ip6::Address oldDua;
1891 #endif
1892 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1893     MlrManager::MlrAddressArray oldMlrRegisteredAddresses;
1894 #endif
1895 
1896     OT_UNUSED_VARIABLE(storedCount);
1897 
1898     SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kAddressRegistration, offsetRange));
1899 
1900 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1901     if (aChild.GetDomainUnicastAddress(oldDua) != kErrorNone)
1902     {
1903         oldDua.Clear();
1904     }
1905 #endif
1906 
1907 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1908     if (aChild.HasAnyMlrRegisteredAddress())
1909     {
1910         OT_ASSERT(aChild.IsStateValid());
1911 
1912         for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
1913         {
1914             if (!addrEntry.IsMulticastLargerThanRealmLocal())
1915             {
1916                 continue;
1917             }
1918 
1919             if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered)
1920             {
1921                 IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry));
1922             }
1923         }
1924     }
1925 #endif
1926 
1927     aChild.ClearIp6Addresses();
1928 
1929     while (!offsetRange.IsEmpty())
1930     {
1931         uint8_t      controlByte;
1932         Ip6::Address address;
1933 
1934         // Read out the control byte (first byte in entry)
1935         SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, controlByte));
1936         offsetRange.AdvanceOffset(sizeof(uint8_t));
1937         count++;
1938 
1939         address.Clear();
1940 
1941         if (AddressRegistrationTlv::IsEntryCompressed(controlByte))
1942         {
1943             // Compressed entry contains IID with the 64-bit prefix
1944             // determined from 6LoWPAN context identifier (from
1945             // the control byte).
1946 
1947             uint8_t         contextId = AddressRegistrationTlv::GetContextId(controlByte);
1948             Lowpan::Context context;
1949 
1950             IgnoreError(aRxInfo.mMessage.Read(offsetRange, address.GetIid()));
1951             offsetRange.AdvanceOffset(sizeof(Ip6::InterfaceIdentifier));
1952 
1953             if (Get<NetworkData::Leader>().GetContext(contextId, context) != kErrorNone)
1954             {
1955                 LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId,
1956                         aChild.GetRloc16());
1957                 continue;
1958             }
1959 
1960             address.SetPrefix(context.mPrefix);
1961         }
1962         else
1963         {
1964             // Uncompressed entry contains the full IPv6 address.
1965 
1966             IgnoreError(aRxInfo.mMessage.Read(offsetRange, address));
1967             offsetRange.AdvanceOffset(sizeof(Ip6::Address));
1968         }
1969 
1970 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1971         if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
1972         {
1973             // Skip remaining address registration entries but keep logging
1974             // skipped addresses.
1975             error = kErrorNoBufs;
1976         }
1977         else
1978 #endif
1979         {
1980             // We try to accept/add as many IPv6 addresses as possible.
1981             // "Child ID/Update Response" will indicate the accepted
1982             // addresses.
1983             error = aChild.AddIp6Address(address);
1984         }
1985 
1986         if (error == kErrorNone)
1987         {
1988             storedCount++;
1989             LogInfo("Child 0x%04x IPv6 address[%u]=%s", aChild.GetRloc16(), storedCount,
1990                     address.ToString().AsCString());
1991         }
1992         else
1993         {
1994             LogWarn("Error %s adding IPv6 address %s to child 0x%04x", ErrorToString(error),
1995                     address.ToString().AsCString(), aChild.GetRloc16());
1996         }
1997 
1998         if (address.IsMulticast())
1999         {
2000             continue;
2001         }
2002 
2003         // We check if the same address is in-use by another child, if so
2004         // remove it. This implements "last-in wins" duplicate address
2005         // resolution policy.
2006         //
2007         // Duplicate addresses can occur if a previously attached child
2008         // attaches to same parent again (after a reset, memory wipe) using
2009         // a new random extended address before the old entry in the child
2010         // table is timed out and then trying to register its globally unique
2011         // IPv6 address as the new child.
2012 
2013         for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
2014         {
2015             if (&child == &aChild)
2016             {
2017                 continue;
2018             }
2019 
2020             IgnoreError(child.RemoveIp6Address(address));
2021         }
2022 
2023         // Clear EID-to-RLOC cache for the unicast address registered by the child.
2024         Get<AddressResolver>().RemoveEntryForAddress(address);
2025     }
2026 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2027     SignalDuaAddressEvent(aChild, oldDua);
2028 #endif
2029 
2030 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2031     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses);
2032 #endif
2033 
2034     if (count == 0)
2035     {
2036         LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
2037     }
2038     else
2039     {
2040         LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count,
2041                 (count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
2042     }
2043 
2044     error = kErrorNone;
2045 
2046 exit:
2047     return error;
2048 }
2049 
2050 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
SignalDuaAddressEvent(const Child & aChild,const Ip6::Address & aOldDua) const2051 void MleRouter::SignalDuaAddressEvent(const Child &aChild, const Ip6::Address &aOldDua) const
2052 {
2053     DuaManager::ChildDuaAddressEvent event = DuaManager::kAddressUnchanged;
2054     Ip6::Address                     newDua;
2055 
2056     if (aChild.GetDomainUnicastAddress(newDua) == kErrorNone)
2057     {
2058         if (aOldDua.IsUnspecified())
2059         {
2060             event = DuaManager::kAddressAdded;
2061         }
2062         else if (aOldDua != newDua)
2063         {
2064             event = DuaManager::kAddressChanged;
2065         }
2066     }
2067     else
2068     {
2069         // Child has no DUA address. If there was no old DUA, no need
2070         // to signal.
2071 
2072         VerifyOrExit(!aOldDua.IsUnspecified());
2073 
2074         event = DuaManager::kAddressRemoved;
2075     }
2076 
2077     Get<DuaManager>().HandleChildDuaAddressEvent(aChild, event);
2078 
2079 exit:
2080     return;
2081 }
2082 #endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2083 
IsMessageMleSubType(const Message & aMessage)2084 bool MleRouter::IsMessageMleSubType(const Message &aMessage) { return aMessage.IsSubTypeMle(); }
2085 
IsMessageChildUpdateRequest(const Message & aMessage)2086 bool MleRouter::IsMessageChildUpdateRequest(const Message &aMessage)
2087 {
2088     return aMessage.IsMleCommand(kCommandChildUpdateRequest);
2089 }
2090 
HandleChildIdRequest(RxInfo & aRxInfo)2091 void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
2092 {
2093     Error              error = kErrorNone;
2094     Mac::ExtAddress    extAddr;
2095     uint16_t           version;
2096     uint32_t           linkFrameCounter;
2097     uint32_t           mleFrameCounter;
2098     DeviceMode         mode;
2099     uint32_t           timeout;
2100     TlvList            tlvList;
2101     MeshCoP::Timestamp timestamp;
2102     Child             *child;
2103     Router            *router;
2104     uint16_t           supervisionInterval;
2105 
2106     Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2107 
2108     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2109 
2110     VerifyOrExit(IsAttached(), error = kErrorInvalidState);
2111 
2112     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2113 
2114     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2115     VerifyOrExit(child != nullptr, error = kErrorAlready);
2116 
2117     SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
2118 
2119     SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge()));
2120 
2121     Get<MeshForwarder>().RemoveMessagesForChild(*child, IsMessageMleSubType);
2122 
2123     SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
2124 
2125     SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2126 
2127     SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
2128 
2129     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2130 
2131     switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2132     {
2133     case kErrorNone:
2134         tlvList.Add(Tlv::kSupervisionInterval);
2135         break;
2136     case kErrorNotFound:
2137         supervisionInterval = (version <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2138         break;
2139     default:
2140         ExitNow(error = kErrorParse);
2141     }
2142 
2143     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2144     {
2145     case kErrorNone:
2146         if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2147         {
2148             break;
2149         }
2150 
2151         OT_FALL_THROUGH;
2152 
2153     case kErrorNotFound:
2154         tlvList.Add(Tlv::kActiveDataset);
2155         break;
2156 
2157     default:
2158         ExitNow(error = kErrorParse);
2159     }
2160 
2161     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2162     {
2163     case kErrorNone:
2164         if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2165         {
2166             break;
2167         }
2168 
2169         OT_FALL_THROUGH;
2170 
2171     case kErrorNotFound:
2172         tlvList.Add(Tlv::kPendingDataset);
2173         break;
2174 
2175     default:
2176         ExitNow(error = kErrorParse);
2177     }
2178 
2179     VerifyOrExit(tlvList.GetLength() <= Child::kMaxRequestTlvs, error = kErrorParse);
2180 
2181     if (!mode.IsFullThreadDevice())
2182     {
2183         SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
2184     }
2185 
2186     router = mRouterTable.FindRouter(extAddr);
2187 
2188     if (router != nullptr)
2189     {
2190         RemoveNeighbor(*router);
2191     }
2192 
2193     if (!child->IsStateValid())
2194     {
2195         child->SetState(Neighbor::kStateChildIdRequest);
2196     }
2197     else
2198     {
2199         RemoveNeighbor(*child);
2200     }
2201 
2202     child->SetLastHeard(TimerMilli::GetNow());
2203     child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2204     child->SetLinkAckFrameCounter(linkFrameCounter);
2205     child->SetMleFrameCounter(mleFrameCounter);
2206     child->SetKeySequence(aRxInfo.mKeySequence);
2207     child->SetDeviceMode(mode);
2208     child->SetVersion(version);
2209     child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2210     child->SetTimeout(timeout);
2211     child->SetSupervisionInterval(supervisionInterval);
2212 #if OPENTHREAD_CONFIG_MULTI_RADIO
2213     child->ClearLastRxFragmentTag();
2214 #endif
2215 
2216     child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType()));
2217 
2218     // We already checked above that `tlvList` will fit in
2219     // `child` entry (with `Child::kMaxRequestTlvs` TLVs).
2220 
2221     child->ClearRequestTlvs();
2222 
2223     for (uint8_t index = 0; index < tlvList.GetLength(); index++)
2224     {
2225         child->SetRequestTlv(index, tlvList[index]);
2226     }
2227 
2228     aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
2229     ProcessKeySequence(aRxInfo);
2230 
2231     switch (mRole)
2232     {
2233     case kRoleChild:
2234         child->SetState(Neighbor::kStateChildIdRequest);
2235         IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
2236         break;
2237 
2238     case kRoleRouter:
2239     case kRoleLeader:
2240         SuccessOrExit(error = SendChildIdResponse(*child));
2241         break;
2242 
2243     case kRoleDisabled:
2244     case kRoleDetached:
2245         OT_ASSERT(false);
2246     }
2247 
2248 exit:
2249     LogProcessError(kTypeChildIdRequest, error);
2250 }
2251 
HandleChildUpdateRequestOnParent(RxInfo & aRxInfo)2252 void MleRouter::HandleChildUpdateRequestOnParent(RxInfo &aRxInfo)
2253 {
2254     Error           error = kErrorNone;
2255     Mac::ExtAddress extAddr;
2256     DeviceMode      mode;
2257     RxChallenge     challenge;
2258     LeaderData      leaderData;
2259     uint32_t        timeout;
2260     uint16_t        supervisionInterval;
2261     Child          *child;
2262     DeviceMode      oldMode;
2263     TlvList         requestedTlvList;
2264     TlvList         tlvList;
2265     bool            childDidChange = false;
2266 
2267     Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
2268 
2269     SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2270 
2271     switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
2272     {
2273     case kErrorNone:
2274         tlvList.Add(Tlv::kResponse);
2275         break;
2276     case kErrorNotFound:
2277         challenge.Clear();
2278         break;
2279     default:
2280         ExitNow(error = kErrorParse);
2281     }
2282 
2283     tlvList.Add(Tlv::kSourceAddress);
2284 
2285     aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2286     child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2287 
2288     if (child == nullptr)
2289     {
2290         // For invalid non-sleepy child, send Child Update Response with
2291         // Status TLV (error).
2292         if (mode.IsRxOnWhenIdle())
2293         {
2294             tlvList.Add(Tlv::kStatus);
2295             SendChildUpdateResponseToChild(nullptr, aRxInfo.mMessageInfo, tlvList, challenge);
2296         }
2297 
2298         ExitNow();
2299     }
2300 
2301     // Ignore "Child Update Request" from a child that is present in the
2302     // child table but it is not yet in valid state. For example, a
2303     // child which is being restored (due to parent reset) or is in the
2304     // middle of the attach process (in `kStateParentRequest` or
2305     // `kStateChildIdRequest`).
2306 
2307     VerifyOrExit(child->IsStateValid());
2308 
2309     oldMode = child->GetDeviceMode();
2310     child->SetDeviceMode(mode);
2311 
2312     tlvList.Add(Tlv::kMode);
2313     tlvList.Add(Tlv::kLinkMargin);
2314 
2315     // Parent MUST include Leader Data TLV in Child Update Response
2316     tlvList.Add(Tlv::kLeaderData);
2317 
2318     if (!challenge.IsEmpty())
2319     {
2320         tlvList.Add(Tlv::kMleFrameCounter);
2321         tlvList.Add(Tlv::kLinkFrameCounter);
2322     }
2323 
2324     switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2325     {
2326     case kErrorNone:
2327         tlvList.Add(Tlv::kAddressRegistration);
2328         break;
2329     case kErrorNotFound:
2330         break;
2331     default:
2332         ExitNow(error = kErrorParse);
2333     }
2334 
2335     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2336     {
2337     case kErrorNone:
2338         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2339         break;
2340     case kErrorNotFound:
2341         break;
2342     default:
2343         ExitNow(error = kErrorParse);
2344     }
2345 
2346     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2347     {
2348     case kErrorNone:
2349         if (child->GetTimeout() != timeout)
2350         {
2351             child->SetTimeout(timeout);
2352             childDidChange = true;
2353         }
2354 
2355         tlvList.Add(Tlv::kTimeout);
2356         break;
2357 
2358     case kErrorNotFound:
2359         break;
2360 
2361     default:
2362         ExitNow(error = kErrorParse);
2363     }
2364 
2365     switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2366     {
2367     case kErrorNone:
2368         tlvList.Add(Tlv::kSupervisionInterval);
2369         break;
2370 
2371     case kErrorNotFound:
2372         supervisionInterval =
2373             (child->GetVersion() <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2374         break;
2375 
2376     default:
2377         ExitNow(error = kErrorParse);
2378     }
2379 
2380     child->SetSupervisionInterval(supervisionInterval);
2381 
2382     switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
2383     {
2384     case kErrorNone:
2385         tlvList.AddElementsFrom(requestedTlvList);
2386         break;
2387     case kErrorNotFound:
2388         break;
2389     default:
2390         ExitNow(error = kErrorParse);
2391     }
2392 
2393 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2394     if (child->IsCslSynchronized())
2395     {
2396         ChannelTlvValue cslChannelTlvValue;
2397         uint32_t        cslTimeout;
2398 
2399         switch (Tlv::Find<CslTimeoutTlv>(aRxInfo.mMessage, cslTimeout))
2400         {
2401         case kErrorNone:
2402             child->SetCslTimeout(cslTimeout);
2403             // MUST include CSL accuracy TLV when request includes CSL timeout
2404             tlvList.Add(Tlv::kCslClockAccuracy);
2405             break;
2406         case kErrorNotFound:
2407             break;
2408         default:
2409             ExitNow(error = kErrorNone);
2410         }
2411 
2412         if (Tlv::Find<CslChannelTlv>(aRxInfo.mMessage, cslChannelTlvValue) == kErrorNone)
2413         {
2414             // Special value of zero is used to indicate that
2415             // CSL channel is not specified.
2416             child->SetCslChannel(static_cast<uint8_t>(cslChannelTlvValue.GetChannel()));
2417         }
2418     }
2419 #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2420 
2421     child->SetLastHeard(TimerMilli::GetNow());
2422 
2423     if (oldMode != child->GetDeviceMode())
2424     {
2425         LogNote("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
2426                 child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
2427 
2428         childDidChange = true;
2429 
2430 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2431         if (child->IsRxOnWhenIdle())
2432         {
2433             // Clear CSL synchronization state
2434             child->SetCslSynchronized(false);
2435         }
2436 #endif
2437 
2438         // The `IndirectSender::HandleChildModeChange()` needs to happen
2439         // after "Child Update" message is fully parsed to ensure that
2440         // any registered IPv6 addresses included in the "Child Update"
2441         // are added to the child.
2442 
2443         Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
2444     }
2445 
2446     if (childDidChange)
2447     {
2448         IgnoreError(mChildTable.StoreChild(*child));
2449     }
2450 
2451 #if OPENTHREAD_CONFIG_MULTI_RADIO
2452     // We clear the fragment tag only if the "Child Update Request" is
2453     // from a detached child trying to restore its link with its
2454     // parent which is indicated by the presence of Challenge TLV in
2455     // the message.
2456     if (!challenge.IsEmpty())
2457     {
2458         child->ClearLastRxFragmentTag();
2459     }
2460 #endif
2461 
2462     SendChildUpdateResponseToChild(child, aRxInfo.mMessageInfo, tlvList, challenge);
2463 
2464     aRxInfo.mClass = RxInfo::kPeerMessage;
2465 
2466 exit:
2467     LogProcessError(kTypeChildUpdateRequestOfChild, error);
2468 }
2469 
HandleChildUpdateResponseOnParent(RxInfo & aRxInfo)2470 void MleRouter::HandleChildUpdateResponseOnParent(RxInfo &aRxInfo)
2471 {
2472     Error       error = kErrorNone;
2473     uint16_t    sourceAddress;
2474     uint32_t    timeout;
2475     RxChallenge response;
2476     uint8_t     status;
2477     uint32_t    linkFrameCounter;
2478     uint32_t    mleFrameCounter;
2479     LeaderData  leaderData;
2480     Child      *child;
2481 
2482     if ((aRxInfo.mNeighbor == nullptr) || IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()) ||
2483         !Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
2484     {
2485         Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr());
2486         ExitNow(error = kErrorNotFound);
2487     }
2488 
2489     child = static_cast<Child *>(aRxInfo.mNeighbor);
2490 
2491     switch (aRxInfo.mMessage.ReadResponseTlv(response))
2492     {
2493     case kErrorNone:
2494         VerifyOrExit(response == child->GetChallenge(), error = kErrorSecurity);
2495         break;
2496     case kErrorNotFound:
2497         VerifyOrExit(child->IsStateValid(), error = kErrorSecurity);
2498         response.Clear();
2499         break;
2500     default:
2501         ExitNow(error = kErrorNone);
2502     }
2503 
2504     Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
2505 
2506     switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
2507     {
2508     case kErrorNone:
2509         if (child->GetRloc16() != sourceAddress)
2510         {
2511             RemoveNeighbor(*child);
2512             ExitNow();
2513         }
2514 
2515         break;
2516 
2517     case kErrorNotFound:
2518         break;
2519 
2520     default:
2521         ExitNow(error = kErrorParse);
2522     }
2523 
2524     switch (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status))
2525     {
2526     case kErrorNone:
2527         VerifyOrExit(status != StatusTlv::kError, RemoveNeighbor(*child));
2528         break;
2529     case kErrorNotFound:
2530         break;
2531     default:
2532         ExitNow(error = kErrorParse);
2533     }
2534 
2535     switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
2536     {
2537     case kErrorNone:
2538         child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2539         child->SetLinkAckFrameCounter(linkFrameCounter);
2540         break;
2541     case kErrorNotFound:
2542         break;
2543     default:
2544         ExitNow(error = kErrorParse);
2545     }
2546 
2547     switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
2548     {
2549     case kErrorNone:
2550         child->SetMleFrameCounter(mleFrameCounter);
2551         break;
2552     case kErrorNotFound:
2553         break;
2554     default:
2555         ExitNow(error = kErrorNone);
2556     }
2557 
2558     switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2559     {
2560     case kErrorNone:
2561         child->SetTimeout(timeout);
2562         break;
2563     case kErrorNotFound:
2564         break;
2565     default:
2566         ExitNow(error = kErrorParse);
2567     }
2568 
2569     {
2570         uint16_t supervisionInterval;
2571 
2572         switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2573         {
2574         case kErrorNone:
2575             child->SetSupervisionInterval(supervisionInterval);
2576             break;
2577         case kErrorNotFound:
2578             break;
2579         default:
2580             ExitNow(error = kErrorParse);
2581         }
2582     }
2583 
2584     switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2585     {
2586     case kErrorNone:
2587     case kErrorNotFound:
2588         break;
2589     default:
2590         ExitNow(error = kErrorParse);
2591     }
2592 
2593     switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2594     {
2595     case kErrorNone:
2596         child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2597         break;
2598     case kErrorNotFound:
2599         break;
2600     default:
2601         ExitNow(error = kErrorParse);
2602     }
2603 
2604     SetChildStateToValid(*child);
2605     child->SetLastHeard(TimerMilli::GetNow());
2606     child->SetKeySequence(aRxInfo.mKeySequence);
2607     child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2608 
2609     aRxInfo.mClass = response.IsEmpty() ? RxInfo::kPeerMessage : RxInfo::kAuthoritativeMessage;
2610 
2611 exit:
2612     LogProcessError(kTypeChildUpdateResponseOfChild, error);
2613 }
2614 
HandleDataRequest(RxInfo & aRxInfo)2615 void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
2616 {
2617     Error              error = kErrorNone;
2618     TlvList            tlvList;
2619     MeshCoP::Timestamp timestamp;
2620 
2621     Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2622 
2623     VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity);
2624 
2625     SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2626 
2627     switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2628     {
2629     case kErrorNone:
2630         if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2631         {
2632             break;
2633         }
2634 
2635         OT_FALL_THROUGH;
2636 
2637     case kErrorNotFound:
2638         tlvList.Add(Tlv::kActiveDataset);
2639         break;
2640 
2641     default:
2642         ExitNow(error = kErrorParse);
2643     }
2644 
2645     switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2646     {
2647     case kErrorNone:
2648         if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2649         {
2650             break;
2651         }
2652 
2653         OT_FALL_THROUGH;
2654 
2655     case kErrorNotFound:
2656         tlvList.Add(Tlv::kPendingDataset);
2657         break;
2658 
2659     default:
2660         ExitNow(error = kErrorParse);
2661     }
2662 
2663     aRxInfo.mClass = RxInfo::kPeerMessage;
2664     ProcessKeySequence(aRxInfo);
2665 
2666     SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, &aRxInfo.mMessage);
2667 
2668 exit:
2669     LogProcessError(kTypeDataRequest, error);
2670 }
2671 
HandleNetworkDataUpdateRouter(void)2672 void MleRouter::HandleNetworkDataUpdateRouter(void)
2673 {
2674     uint16_t delay;
2675 
2676     VerifyOrExit(IsRouterOrLeader());
2677 
2678     if (IsLeader())
2679     {
2680         SendMulticastDataResponse();
2681     }
2682     else
2683     {
2684         delay = 1 + Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter);
2685         mDelayedSender.ScheduleMulticastDataResponse(delay);
2686     }
2687 
2688     SynchronizeChildNetworkData();
2689 
2690 exit:
2691     return;
2692 }
2693 
SynchronizeChildNetworkData(void)2694 void MleRouter::SynchronizeChildNetworkData(void)
2695 {
2696     VerifyOrExit(IsRouterOrLeader());
2697 
2698     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
2699     {
2700         if (child.IsRxOnWhenIdle())
2701         {
2702             continue;
2703         }
2704 
2705         if (child.GetNetworkDataVersion() == Get<NetworkData::Leader>().GetVersion(child.GetNetworkDataType()))
2706         {
2707             continue;
2708         }
2709 
2710         SuccessOrExit(SendChildUpdateRequestToChild(child));
2711     }
2712 
2713 exit:
2714     return;
2715 }
2716 
2717 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
SetSteeringData(const Mac::ExtAddress * aExtAddress)2718 void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress)
2719 {
2720     Mac::ExtAddress nullExtAddr;
2721     Mac::ExtAddress allowAnyExtAddr;
2722 
2723     nullExtAddr.Clear();
2724     allowAnyExtAddr.Fill(0xff);
2725 
2726     if ((aExtAddress == nullptr) || (*aExtAddress == nullExtAddr))
2727     {
2728         mSteeringData.Clear();
2729     }
2730     else if (*aExtAddress == allowAnyExtAddr)
2731     {
2732         mSteeringData.SetToPermitAllJoiners();
2733     }
2734     else
2735     {
2736         Mac::ExtAddress joinerId;
2737 
2738         mSteeringData.Init();
2739         MeshCoP::ComputeJoinerId(*aExtAddress, joinerId);
2740         mSteeringData.UpdateBloomFilter(joinerId);
2741     }
2742 }
2743 #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2744 
HandleDiscoveryRequest(RxInfo & aRxInfo)2745 void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
2746 {
2747     Error                        error = kErrorNone;
2748     Tlv::ParsedInfo              tlvInfo;
2749     MeshCoP::DiscoveryRequestTlv discoveryRequestTlv;
2750     MeshCoP::ExtendedPanId       extPanId;
2751     OffsetRange                  offsetRange;
2752     DiscoveryResponseInfo        responseInfo;
2753 
2754     Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2755 
2756     discoveryRequestTlv.SetLength(0);
2757 
2758     VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2759 
2760     SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange));
2761 
2762     for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(tlvInfo.GetSize()))
2763     {
2764         SuccessOrExit(error = tlvInfo.ParseFrom(aRxInfo.mMessage, offsetRange));
2765 
2766         if (tlvInfo.mIsExtended)
2767         {
2768             continue;
2769         }
2770 
2771         switch (tlvInfo.mType)
2772         {
2773         case MeshCoP::Tlv::kDiscoveryRequest:
2774             SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryRequestTlv));
2775             VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse);
2776 
2777             break;
2778 
2779         case MeshCoP::Tlv::kExtendedPanId:
2780             SuccessOrExit(
2781                 error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offsetRange.GetOffset(), extPanId));
2782             VerifyOrExit(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId() != extPanId, error = kErrorDrop);
2783 
2784             break;
2785 
2786         default:
2787             break;
2788         }
2789     }
2790 
2791     if (discoveryRequestTlv.IsValid())
2792     {
2793         if (mDiscoveryRequestCallback.IsSet())
2794         {
2795             otThreadDiscoveryRequestInfo info;
2796 
2797             aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&info.mExtAddress));
2798             info.mVersion  = discoveryRequestTlv.GetVersion();
2799             info.mIsJoiner = discoveryRequestTlv.IsJoiner();
2800 
2801             mDiscoveryRequestCallback.Invoke(&info);
2802         }
2803 
2804         if (discoveryRequestTlv.IsJoiner())
2805         {
2806 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2807             if (!mSteeringData.IsEmpty())
2808             {
2809             }
2810             else // if steering data is not set out of band, fall back to network data
2811 #endif
2812             {
2813                 VerifyOrExit(Get<NetworkData::Leader>().IsJoiningAllowed(), error = kErrorSecurity);
2814             }
2815         }
2816     }
2817 
2818     responseInfo.mPanId = aRxInfo.mMessage.GetPanId();
2819 
2820 #if OPENTHREAD_CONFIG_MULTI_RADIO
2821     // Send the MLE Discovery Response message on same radio link
2822     // from which the "MLE Discover Request" message was received.
2823     responseInfo.mRadioType = aRxInfo.mMessage.GetRadioType();
2824 #endif
2825 
2826     mDelayedSender.ScheduleDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), responseInfo,
2827                                              1 + Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter));
2828 
2829 exit:
2830     LogProcessError(kTypeDiscoveryRequest, error);
2831 }
2832 
SendDiscoveryResponse(const Ip6::Address & aDestination,const DiscoveryResponseInfo & aInfo)2833 Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const DiscoveryResponseInfo &aInfo)
2834 {
2835     Error                         error = kErrorNone;
2836     TxMessage                    *message;
2837     uint16_t                      startOffset;
2838     Tlv                           tlv;
2839     MeshCoP::DiscoveryResponseTlv discoveryResponseTlv;
2840 
2841     VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
2842     message->SetDirectTransmission();
2843     message->SetPanId(aInfo.mPanId);
2844 #if OPENTHREAD_CONFIG_MULTI_RADIO
2845     message->SetRadioType(aInfo.mRadioType);
2846 #endif
2847 
2848     tlv.SetType(Tlv::kDiscovery);
2849     SuccessOrExit(error = message->Append(tlv));
2850 
2851     startOffset = message->GetLength();
2852 
2853     discoveryResponseTlv.Init();
2854     discoveryResponseTlv.SetVersion(kThreadVersion);
2855 
2856 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
2857     if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled)
2858     {
2859         SuccessOrExit(
2860             error = Tlv::Append<MeshCoP::CommissionerUdpPortTlv>(*message, Get<MeshCoP::BorderAgent>().GetUdpPort()));
2861 
2862         discoveryResponseTlv.SetNativeCommissioner(true);
2863     }
2864     else
2865 #endif
2866     {
2867         discoveryResponseTlv.SetNativeCommissioner(false);
2868     }
2869 
2870     if (Get<KeyManager>().GetSecurityPolicy().mCommercialCommissioningEnabled)
2871     {
2872         discoveryResponseTlv.SetCommercialCommissioningMode(true);
2873     }
2874 
2875     SuccessOrExit(error = discoveryResponseTlv.AppendTo(*message));
2876 
2877     SuccessOrExit(
2878         error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
2879 
2880     SuccessOrExit(error = Tlv::Append<MeshCoP::NetworkNameTlv>(
2881                       *message, Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsCString()));
2882 
2883     SuccessOrExit(error = message->AppendSteeringDataTlv());
2884 
2885     SuccessOrExit(
2886         error = Tlv::Append<MeshCoP::JoinerUdpPortTlv>(*message, Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()));
2887 
2888 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)
2889     if (!Get<MeshCoP::NetworkNameManager>().IsDefaultDomainNameSet())
2890     {
2891         SuccessOrExit(error = Tlv::Append<MeshCoP::ThreadDomainNameTlv>(
2892                           *message, Get<MeshCoP::NetworkNameManager>().GetDomainName().GetAsCString()));
2893     }
2894 #endif
2895 
2896     tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
2897     message->Write(startOffset - sizeof(tlv), tlv);
2898 
2899     SuccessOrExit(error = message->SendTo(aDestination));
2900 
2901     Log(kMessageSend, kTypeDiscoveryResponse, aDestination);
2902 
2903 exit:
2904     FreeMessageOnError(message, error);
2905     LogProcessError(kTypeDiscoveryResponse, error);
2906     return error;
2907 }
2908 
SendChildIdResponse(Child & aChild)2909 Error MleRouter::SendChildIdResponse(Child &aChild)
2910 {
2911     Error        error = kErrorNone;
2912     Ip6::Address destination;
2913     TxMessage   *message;
2914 
2915     VerifyOrExit((message = NewMleMessage(kCommandChildIdResponse)) != nullptr, error = kErrorNoBufs);
2916     SuccessOrExit(error = message->AppendSourceAddressTlv());
2917     SuccessOrExit(error = message->AppendLeaderDataTlv());
2918     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
2919 
2920     if ((aChild.GetRloc16() == 0) || !HasMatchingRouterIdWith(aChild.GetRloc16()))
2921     {
2922         uint16_t rloc16;
2923 
2924         // Pick next Child ID that is not being used
2925         do
2926         {
2927             mNextChildId++;
2928 
2929             if (mNextChildId > kMaxChildId)
2930             {
2931                 mNextChildId = kMinChildId;
2932             }
2933 
2934             rloc16 = Get<Mac::Mac>().GetShortAddress() | mNextChildId;
2935 
2936         } while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
2937 
2938         aChild.SetRloc16(rloc16);
2939     }
2940 
2941     SuccessOrExit(error = message->AppendAddress16Tlv(aChild.GetRloc16()));
2942 
2943     for (uint8_t i = 0; i < Child::kMaxRequestTlvs; i++)
2944     {
2945         switch (aChild.GetRequestTlv(i))
2946         {
2947         case Tlv::kNetworkData:
2948             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
2949             break;
2950 
2951         case Tlv::kRoute:
2952             SuccessOrExit(error = message->AppendRouteTlv());
2953             break;
2954 
2955         case Tlv::kActiveDataset:
2956             SuccessOrExit(error = message->AppendActiveDatasetTlv());
2957             break;
2958 
2959         case Tlv::kPendingDataset:
2960             SuccessOrExit(error = message->AppendPendingDatasetTlv());
2961             break;
2962 
2963         case Tlv::kSupervisionInterval:
2964             SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild.GetSupervisionInterval()));
2965             break;
2966 
2967         default:
2968             break;
2969         }
2970     }
2971 
2972     if (!aChild.IsFullThreadDevice())
2973     {
2974         SuccessOrExit(error = message->AppendAddressRegistrationTlv(aChild));
2975     }
2976 
2977     SetChildStateToValid(aChild);
2978 
2979     if (!aChild.IsRxOnWhenIdle())
2980     {
2981         Get<IndirectSender>().SetChildUseShortAddress(aChild, false);
2982     }
2983 
2984 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2985     if (aChild.IsTimeSyncEnabled())
2986     {
2987         message->SetTimeSync(true);
2988     }
2989 #endif
2990 
2991     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
2992     SuccessOrExit(error = message->SendTo(destination));
2993 
2994     Log(kMessageSend, kTypeChildIdResponse, destination, aChild.GetRloc16());
2995 
2996 exit:
2997     FreeMessageOnError(message, error);
2998     return error;
2999 }
3000 
SendChildUpdateRequestToChild(Child & aChild)3001 Error MleRouter::SendChildUpdateRequestToChild(Child &aChild)
3002 {
3003     static const uint8_t kTlvs[] = {Tlv::kTimeout, Tlv::kAddressRegistration};
3004 
3005     Error        error = kErrorNone;
3006     Ip6::Address destination;
3007     TxMessage   *message = nullptr;
3008 
3009     if (!aChild.IsRxOnWhenIdle() && aChild.IsStateRestoring())
3010     {
3011         // No need to send the resync "Child Update Request"
3012         // to the sleepy child if there is one already
3013         // queued.
3014 
3015         VerifyOrExit(!Get<IndirectSender>().HasQueuedMessageForSleepyChild(aChild, IsMessageChildUpdateRequest));
3016     }
3017 
3018     Get<MeshForwarder>().RemoveMessagesForChild(aChild, IsMessageChildUpdateRequest);
3019 
3020     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
3021     SuccessOrExit(error = message->AppendSourceAddressTlv());
3022     SuccessOrExit(error = message->AppendLeaderDataTlv());
3023     SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
3024     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3025 
3026     if (aChild.IsStateValid())
3027     {
3028         SuccessOrExit(error = message->AppendLinkMarginTlv(aChild.GetLinkInfo().GetLinkMargin()));
3029     }
3030     else
3031     {
3032         SuccessOrExit(error = message->AppendTlvRequestTlv(kTlvs));
3033 
3034         if (!aChild.IsStateRestored())
3035         {
3036             // A random challenge is generated and saved when `aChild`
3037             // is first initialized in `kStateRestored`. We will use
3038             // the saved challenge here. This prevents overwriting
3039             // the saved challenge when the child is also detached
3040             // and happens to send a "Parent Request" in the window
3041             // where the parent transitions to the router/leader role
3042             // and before the parent sends the "Child Update Request".
3043             // This ensures that the same random challenge is
3044             // included in both "Parent Response" and "Child Update
3045             // Response," guaranteeing proper acceptance of the
3046             // child's "Child ID request".
3047 
3048             aChild.GenerateChallenge();
3049         }
3050 
3051         SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge()));
3052     }
3053 
3054     destination.SetToLinkLocalAddress(aChild.GetExtAddress());
3055     SuccessOrExit(error = message->SendTo(destination));
3056 
3057     if (aChild.IsRxOnWhenIdle())
3058     {
3059         // only try to send a single Child Update Request message to an rx-on-when-idle child
3060         aChild.SetState(Child::kStateChildUpdateRequest);
3061     }
3062 
3063     Log(kMessageSend, kTypeChildUpdateRequestOfChild, destination, aChild.GetRloc16());
3064 
3065 exit:
3066     FreeMessageOnError(message, error);
3067     return error;
3068 }
3069 
SendChildUpdateResponseToChild(Child * aChild,const Ip6::MessageInfo & aMessageInfo,const TlvList & aTlvList,const RxChallenge & aChallenge)3070 void MleRouter::SendChildUpdateResponseToChild(Child                  *aChild,
3071                                                const Ip6::MessageInfo &aMessageInfo,
3072                                                const TlvList          &aTlvList,
3073                                                const RxChallenge      &aChallenge)
3074 {
3075     Error      error = kErrorNone;
3076     TxMessage *message;
3077 
3078     VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs);
3079 
3080     for (uint8_t tlvType : aTlvList)
3081     {
3082         // Add all TLV types that do not depend on `child`
3083 
3084         switch (tlvType)
3085         {
3086         case Tlv::kStatus:
3087             SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError));
3088             break;
3089 
3090         case Tlv::kLeaderData:
3091             SuccessOrExit(error = message->AppendLeaderDataTlv());
3092             break;
3093 
3094         case Tlv::kResponse:
3095             SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
3096             break;
3097 
3098         case Tlv::kSourceAddress:
3099             SuccessOrExit(error = message->AppendSourceAddressTlv());
3100             break;
3101 
3102         case Tlv::kMleFrameCounter:
3103             SuccessOrExit(error = message->AppendMleFrameCounterTlv());
3104             break;
3105 
3106         case Tlv::kLinkFrameCounter:
3107             SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
3108             break;
3109         }
3110 
3111         // Make sure `child` is not null before adding TLV types
3112         // that can depend on it.
3113 
3114         if (aChild == nullptr)
3115         {
3116             continue;
3117         }
3118 
3119         switch (tlvType)
3120         {
3121         case Tlv::kAddressRegistration:
3122             SuccessOrExit(error = message->AppendAddressRegistrationTlv(*aChild));
3123             break;
3124 
3125         case Tlv::kMode:
3126             SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode()));
3127             break;
3128 
3129         case Tlv::kNetworkData:
3130             SuccessOrExit(error = message->AppendNetworkDataTlv(aChild->GetNetworkDataType()));
3131             SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3132             break;
3133 
3134         case Tlv::kTimeout:
3135             SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
3136             break;
3137 
3138         case Tlv::kLinkMargin:
3139             SuccessOrExit(error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin()));
3140             break;
3141 
3142         case Tlv::kSupervisionInterval:
3143             SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild->GetSupervisionInterval()));
3144             break;
3145 
3146 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
3147         case Tlv::kCslClockAccuracy:
3148             if (!aChild->IsRxOnWhenIdle())
3149             {
3150                 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
3151             }
3152             break;
3153 #endif
3154         }
3155     }
3156 
3157     SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
3158 
3159     if (aChild == nullptr)
3160     {
3161         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr());
3162     }
3163     else
3164     {
3165         Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr(), aChild->GetRloc16());
3166     }
3167 
3168 exit:
3169     FreeMessageOnError(message, error);
3170 }
3171 
SendMulticastDataResponse(void)3172 void MleRouter::SendMulticastDataResponse(void)
3173 {
3174     Ip6::Address destination;
3175     TlvList      tlvList;
3176 
3177     destination.SetToLinkLocalAllNodesMulticast();
3178     tlvList.Add(Tlv::kNetworkData);
3179     SendDataResponse(destination, tlvList);
3180 }
3181 
SendDataResponse(const Ip6::Address & aDestination,const TlvList & aTlvList,const Message * aRequestMessage)3182 void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
3183                                  const TlvList      &aTlvList,
3184                                  const Message      *aRequestMessage)
3185 {
3186     OT_UNUSED_VARIABLE(aRequestMessage);
3187 
3188     Error      error   = kErrorNone;
3189     TxMessage *message = nullptr;
3190     Neighbor  *neighbor;
3191 
3192     VerifyOrExit(IsAttached());
3193 
3194     if (mRetrieveNewNetworkData)
3195     {
3196         LogInfo("Suppressing Data Response - waiting for new network data");
3197         ExitNow();
3198     }
3199 
3200     VerifyOrExit((message = NewMleMessage(kCommandDataResponse)) != nullptr, error = kErrorNoBufs);
3201     SuccessOrExit(error = message->AppendSourceAddressTlv());
3202     SuccessOrExit(error = message->AppendLeaderDataTlv());
3203     SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3204 
3205     for (uint8_t tlvType : aTlvList)
3206     {
3207         switch (tlvType)
3208         {
3209         case Tlv::kNetworkData:
3210             neighbor = mNeighborTable.FindNeighbor(aDestination);
3211             SuccessOrExit(error = message->AppendNetworkDataTlv((neighbor != nullptr) ? neighbor->GetNetworkDataType()
3212                                                                                       : NetworkData::kFullSet));
3213             break;
3214 
3215         case Tlv::kActiveDataset:
3216             SuccessOrExit(error = message->AppendActiveDatasetTlv());
3217             break;
3218 
3219         case Tlv::kPendingDataset:
3220             SuccessOrExit(error = message->AppendPendingDatasetTlv());
3221             break;
3222 
3223         case Tlv::kRoute:
3224             SuccessOrExit(error = message->AppendRouteTlv());
3225             break;
3226 
3227 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3228         case Tlv::kLinkMetricsReport:
3229             OT_ASSERT(aRequestMessage != nullptr);
3230             neighbor = mNeighborTable.FindNeighbor(aDestination);
3231             VerifyOrExit(neighbor != nullptr, error = kErrorInvalidState);
3232             SuccessOrExit(error = Get<LinkMetrics::Subject>().AppendReport(*message, *aRequestMessage, *neighbor));
3233             break;
3234 #endif
3235         }
3236     }
3237 
3238     SuccessOrExit(error = message->SendTo(aDestination));
3239     Log(kMessageSend, kTypeDataResponse, aDestination);
3240 
3241 exit:
3242     FreeMessageOnError(message, error);
3243     LogSendError(kTypeDataResponse, error);
3244 }
3245 
RemoveRouterLink(Router & aRouter)3246 void MleRouter::RemoveRouterLink(Router &aRouter)
3247 {
3248     switch (mRole)
3249     {
3250     case kRoleChild:
3251         if (&aRouter == &mParent)
3252         {
3253             IgnoreError(BecomeDetached());
3254         }
3255         break;
3256 
3257     case kRoleRouter:
3258     case kRoleLeader:
3259         mRouterTable.RemoveRouterLink(aRouter);
3260         break;
3261 
3262     default:
3263         break;
3264     }
3265 }
3266 
RemoveNeighbor(Neighbor & aNeighbor)3267 void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
3268 {
3269     VerifyOrExit(!aNeighbor.IsStateInvalid());
3270 
3271     if (&aNeighbor == &mParent)
3272     {
3273         if (IsChild())
3274         {
3275             IgnoreError(BecomeDetached());
3276         }
3277     }
3278     else if (&aNeighbor == &GetParentCandidate())
3279     {
3280         ClearParentCandidate();
3281     }
3282     else if (IsChildRloc16(aNeighbor.GetRloc16()))
3283     {
3284         OT_ASSERT(mChildTable.Contains(aNeighbor));
3285 
3286         if (aNeighbor.IsStateValidOrRestoring())
3287         {
3288             mNeighborTable.Signal(NeighborTable::kChildRemoved, aNeighbor);
3289         }
3290 
3291         Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
3292 
3293         if (aNeighbor.IsFullThreadDevice())
3294         {
3295             Get<AddressResolver>().RemoveEntriesForRloc16(aNeighbor.GetRloc16());
3296         }
3297 
3298         mChildTable.RemoveStoredChild(static_cast<Child &>(aNeighbor));
3299     }
3300     else if (aNeighbor.IsStateValid())
3301     {
3302         OT_ASSERT(mRouterTable.Contains(aNeighbor));
3303 
3304         mNeighborTable.Signal(NeighborTable::kRouterRemoved, aNeighbor);
3305         mRouterTable.RemoveRouterLink(static_cast<Router &>(aNeighbor));
3306     }
3307 
3308     aNeighbor.GetLinkInfo().Clear();
3309     aNeighbor.SetState(Neighbor::kStateInvalid);
3310 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3311     aNeighbor.RemoveAllForwardTrackingSeriesInfo();
3312 #endif
3313 
3314 exit:
3315     return;
3316 }
3317 
SetPreferredRouterId(uint8_t aRouterId)3318 Error MleRouter::SetPreferredRouterId(uint8_t aRouterId)
3319 {
3320     Error error = kErrorNone;
3321 
3322     VerifyOrExit(IsDetached() || IsDisabled(), error = kErrorInvalidState);
3323 
3324     mPreviousRouterId = aRouterId;
3325 
3326 exit:
3327     return error;
3328 }
3329 
SetRouterId(uint8_t aRouterId)3330 void MleRouter::SetRouterId(uint8_t aRouterId)
3331 {
3332     mRouterId         = aRouterId;
3333     mPreviousRouterId = mRouterId;
3334 }
3335 
SendAddressSolicit(ThreadStatusTlv::Status aStatus)3336 Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
3337 {
3338     Error            error = kErrorNone;
3339     Tmf::MessageInfo messageInfo(GetInstance());
3340     Coap::Message   *message = nullptr;
3341 
3342     VerifyOrExit(!mAddressSolicitPending);
3343 
3344     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressSolicit);
3345     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3346 
3347     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3348 
3349     if (IsRouterIdValid(mPreviousRouterId))
3350     {
3351         SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mPreviousRouterId)));
3352     }
3353 
3354     SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
3355 
3356 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3357     SuccessOrExit(error = Tlv::Append<XtalAccuracyTlv>(*message, otPlatTimeGetXtalAccuracy()));
3358 #endif
3359 
3360     messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3361 
3362     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this));
3363     mAddressSolicitPending = true;
3364 
3365     Log(kMessageSend, kTypeAddressSolicit, messageInfo.GetPeerAddr());
3366 
3367 exit:
3368     FreeMessageOnError(message, error);
3369     return error;
3370 }
3371 
SendAddressRelease(void)3372 void MleRouter::SendAddressRelease(void)
3373 {
3374     Error            error = kErrorNone;
3375     Tmf::MessageInfo messageInfo(GetInstance());
3376     Coap::Message   *message;
3377 
3378     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressRelease);
3379     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3380 
3381     SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mRouterId)));
3382     SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3383 
3384     messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3385 
3386     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
3387 
3388     Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr());
3389 
3390 exit:
3391     FreeMessageOnError(message, error);
3392     LogSendError(kTypeAddressRelease, error);
3393 }
3394 
HandleAddressSolicitResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aResult)3395 void MleRouter::HandleAddressSolicitResponse(void                *aContext,
3396                                              otMessage           *aMessage,
3397                                              const otMessageInfo *aMessageInfo,
3398                                              otError              aResult)
3399 {
3400     static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(AsCoapMessagePtr(aMessage),
3401                                                                      AsCoreTypePtr(aMessageInfo), aResult);
3402 }
3403 
HandleAddressSolicitResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)3404 void MleRouter::HandleAddressSolicitResponse(Coap::Message          *aMessage,
3405                                              const Ip6::MessageInfo *aMessageInfo,
3406                                              Error                   aResult)
3407 {
3408     uint8_t             status;
3409     uint16_t            rloc16;
3410     ThreadRouterMaskTlv routerMaskTlv;
3411     uint8_t             routerId;
3412     Router             *router;
3413 
3414     mAddressSolicitPending = false;
3415 
3416     VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
3417 
3418     VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
3419 
3420     Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
3421 
3422     SuccessOrExit(Tlv::Find<ThreadStatusTlv>(*aMessage, status));
3423 
3424     if (status != ThreadStatusTlv::kSuccess)
3425     {
3426         mAddressSolicitRejected = true;
3427 
3428         if (IsRouterIdValid(mPreviousRouterId))
3429         {
3430             if (HasChildren())
3431             {
3432                 RemoveChildren();
3433             }
3434 
3435             SetRouterId(kInvalidRouterId);
3436         }
3437 
3438         ExitNow();
3439     }
3440 
3441     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
3442     routerId = RouterIdFromRloc16(rloc16);
3443 
3444     SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
3445     VerifyOrExit(routerMaskTlv.IsValid());
3446 
3447     SetAlternateRloc16(GetRloc16());
3448 
3449     SetRouterId(routerId);
3450 
3451     SetStateRouter(Rloc16FromRouterId(mRouterId));
3452 
3453     // We keep the router table next hop and cost as what we had as a
3454     // REED, i.e., our parent was the next hop towards all other
3455     // routers and we tracked its cost towards them. As an FTD child,
3456     // we may have established links with a subset of neighboring routers.
3457     // We ensure to clear these links to avoid using them (since will
3458     // be rejected by the neighbor).
3459 
3460     mRouterTable.ClearNeighbors();
3461 
3462     mRouterTable.UpdateRouterIdSet(routerMaskTlv.GetIdSequence(), routerMaskTlv.GetAssignedRouterIdMask());
3463 
3464     router = mRouterTable.FindRouterById(routerId);
3465     VerifyOrExit(router != nullptr);
3466     router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
3467     router->SetNextHopToInvalid();
3468 
3469     // Ensure we have our parent as a neighboring router, copying the
3470     // `mParent` entry.
3471 
3472     router = mRouterTable.FindRouterById(mParent.GetRouterId());
3473     VerifyOrExit(router != nullptr);
3474     router->SetFrom(mParent);
3475     router->SetState(Neighbor::kStateValid);
3476     router->SetNextHopToInvalid();
3477 
3478     // Ensure we have a next hop and cost towards leader.
3479     if (mRouterTable.GetPathCostToLeader() >= kMaxRouteCost)
3480     {
3481         Router *leader = mRouterTable.GetLeader();
3482 
3483         OT_ASSERT(leader != nullptr);
3484         leader->SetNextHopAndCost(RouterIdFromRloc16(mParent.GetRloc16()), mParent.GetLeaderCost());
3485     }
3486 
3487     // We send a unicast Link Request to our former parent if its
3488     // version is earlier than 1.3. This is to address a potential
3489     // compatibility issue with some non-OpenThread stacks which may
3490     // ignore MLE Advertisements from a former/existing child.
3491 
3492     if (mParent.GetVersion() < kThreadVersion1p3)
3493     {
3494         SendLinkRequest(&mParent);
3495     }
3496 
3497     // We send an Advertisement to inform our former parent of our
3498     // newly allocated Router ID. This will cause the parent to
3499     // reset its advertisement trickle timer which can help speed
3500     // up the dissemination of the new Router ID to other routers.
3501     // This can also help with quicker link establishment with our
3502     // former parent and other routers.
3503     SendMulticastAdvertisement();
3504 
3505     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
3506     {
3507         IgnoreError(SendChildIdResponse(child));
3508     }
3509 
3510 exit:
3511     InformPreviousChannel();
3512 }
3513 
SetChildRouterLinks(uint8_t aChildRouterLinks)3514 Error MleRouter::SetChildRouterLinks(uint8_t aChildRouterLinks)
3515 {
3516     Error error = kErrorNone;
3517 
3518     VerifyOrExit(IsDisabled(), error = kErrorInvalidState);
3519     mChildRouterLinks = aChildRouterLinks;
3520 exit:
3521     return error;
3522 }
3523 
IsExpectedToBecomeRouterSoon(void) const3524 bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
3525 {
3526     static constexpr uint8_t kMaxDelay = 10;
3527 
3528     return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
3529            ((mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay) ||
3530             mAddressSolicitPending);
3531 }
3532 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3533 template <> void MleRouter::HandleTmf<kUriAddressSolicit>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3534 {
3535     Error                   error          = kErrorNone;
3536     ThreadStatusTlv::Status responseStatus = ThreadStatusTlv::kNoAddressAvailable;
3537     Router                 *router         = nullptr;
3538     Mac::ExtAddress         extAddress;
3539     uint16_t                rloc16;
3540     uint8_t                 status;
3541 
3542     VerifyOrExit(mRole == kRoleLeader, error = kErrorInvalidState);
3543 
3544     VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
3545 
3546     Log(kMessageReceive, kTypeAddressSolicit, aMessageInfo.GetPeerAddr());
3547 
3548     SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3549     SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
3550 
3551     switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
3552     {
3553     case kErrorNone:
3554         break;
3555     case kErrorNotFound:
3556         rloc16 = kInvalidRloc16;
3557         break;
3558     default:
3559         ExitNow(error = kErrorParse);
3560     }
3561 
3562 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3563     {
3564         uint16_t xtalAccuracy;
3565 
3566         SuccessOrExit(Tlv::Find<XtalAccuracyTlv>(aMessage, xtalAccuracy));
3567         VerifyOrExit(xtalAccuracy <= Get<TimeSync>().GetXtalThreshold());
3568     }
3569 #endif
3570 
3571     router = mRouterTable.FindRouter(extAddress);
3572 
3573     if (router != nullptr)
3574     {
3575         responseStatus = ThreadStatusTlv::kSuccess;
3576         ExitNow();
3577     }
3578 
3579     switch (status)
3580     {
3581     case ThreadStatusTlv::kTooFewRouters:
3582         VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
3583         break;
3584 
3585     case ThreadStatusTlv::kHaveChildIdRequest:
3586     case ThreadStatusTlv::kParentPartitionChange:
3587         break;
3588 
3589     case ThreadStatusTlv::kBorderRouterRequest:
3590         if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
3591             (Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
3592              kRouterUpgradeBorderRouterRequestThreshold))
3593         {
3594             LogInfo("Rejecting BR %s router role req - have %u BR routers", extAddress.ToString().AsCString(),
3595                     kRouterUpgradeBorderRouterRequestThreshold);
3596             ExitNow();
3597         }
3598         break;
3599 
3600     default:
3601         responseStatus = ThreadStatusTlv::kUnrecognizedStatus;
3602         ExitNow();
3603     }
3604 
3605     if (rloc16 != kInvalidRloc16)
3606     {
3607         router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16));
3608 
3609         if (router != nullptr)
3610         {
3611             LogInfo("Router id %u requested and provided!", RouterIdFromRloc16(rloc16));
3612         }
3613     }
3614 
3615     if (router == nullptr)
3616     {
3617         router = mRouterTable.Allocate();
3618         VerifyOrExit(router != nullptr);
3619     }
3620 
3621     router->SetExtAddress(extAddress);
3622     responseStatus = ThreadStatusTlv::kSuccess;
3623 
3624 exit:
3625     if (error == kErrorNone)
3626     {
3627         SendAddressSolicitResponse(aMessage, responseStatus, router, aMessageInfo);
3628     }
3629 }
3630 
SendAddressSolicitResponse(const Coap::Message & aRequest,ThreadStatusTlv::Status aResponseStatus,const Router * aRouter,const Ip6::MessageInfo & aMessageInfo)3631 void MleRouter::SendAddressSolicitResponse(const Coap::Message    &aRequest,
3632                                            ThreadStatusTlv::Status aResponseStatus,
3633                                            const Router           *aRouter,
3634                                            const Ip6::MessageInfo &aMessageInfo)
3635 {
3636     Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
3637 
3638     VerifyOrExit(message != nullptr);
3639 
3640     SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aResponseStatus));
3641 
3642     if (aRouter != nullptr)
3643     {
3644         ThreadRouterMaskTlv routerMaskTlv;
3645 
3646         SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aRouter->GetRloc16()));
3647 
3648         routerMaskTlv.Init();
3649         routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3650         mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask());
3651 
3652         SuccessOrExit(routerMaskTlv.AppendTo(*message));
3653     }
3654 
3655     SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
3656     message = nullptr;
3657 
3658     Log(kMessageSend, kTypeAddressReply, aMessageInfo.GetPeerAddr());
3659 
3660     // If assigning a new RLOC16 (e.g., on promotion of a child to
3661     // router role) we clear any address cache entries associated
3662     // with the old RLOC16 unless the sender is a direct child. For
3663     // direct children, we retain the cache entries to allow
3664     // association with the promoted router's new RLOC16 upon
3665     // receiving its Link Advertisement.
3666 
3667     if ((aResponseStatus == ThreadStatusTlv::kSuccess) && (aRouter != nullptr))
3668     {
3669         uint16_t oldRloc16;
3670 
3671         VerifyOrExit(IsRoutingLocator(aMessageInfo.GetPeerAddr()));
3672         oldRloc16 = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
3673 
3674         VerifyOrExit(oldRloc16 != aRouter->GetRloc16());
3675         VerifyOrExit(!RouterIdMatch(oldRloc16, GetRloc16()));
3676         Get<AddressResolver>().RemoveEntriesForRloc16(oldRloc16);
3677     }
3678 
3679 exit:
3680     FreeMessage(message);
3681 }
3682 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3683 template <> void MleRouter::HandleTmf<kUriAddressRelease>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3684 {
3685     uint16_t        rloc16;
3686     Mac::ExtAddress extAddress;
3687     uint8_t         routerId;
3688     Router         *router;
3689 
3690     VerifyOrExit(mRole == kRoleLeader);
3691 
3692     VerifyOrExit(aMessage.IsConfirmablePostRequest());
3693 
3694     Log(kMessageReceive, kTypeAddressRelease, aMessageInfo.GetPeerAddr());
3695 
3696     SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16));
3697     SuccessOrExit(Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3698 
3699     routerId = RouterIdFromRloc16(rloc16);
3700     router   = mRouterTable.FindRouterById(routerId);
3701 
3702     VerifyOrExit((router != nullptr) && (router->GetExtAddress() == extAddress));
3703 
3704     IgnoreError(mRouterTable.Release(routerId));
3705 
3706     SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
3707 
3708     Log(kMessageSend, kTypeAddressReleaseReply, aMessageInfo.GetPeerAddr());
3709 
3710 exit:
3711     return;
3712 }
3713 
FillConnectivityTlv(ConnectivityTlv & aTlv)3714 void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
3715 {
3716     int8_t parentPriority = kParentPriorityMedium;
3717 
3718     if (mParentPriority != kParentPriorityUnspecified)
3719     {
3720         parentPriority = mParentPriority;
3721     }
3722     else
3723     {
3724         uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
3725         uint16_t maxAllowed  = mChildTable.GetMaxChildrenAllowed();
3726 
3727         if ((maxAllowed - numChildren) < (maxAllowed / 3))
3728         {
3729             parentPriority = kParentPriorityLow;
3730         }
3731         else
3732         {
3733             parentPriority = kParentPriorityMedium;
3734         }
3735     }
3736 
3737     aTlv.SetParentPriority(parentPriority);
3738 
3739     aTlv.SetLinkQuality1(0);
3740     aTlv.SetLinkQuality2(0);
3741     aTlv.SetLinkQuality3(0);
3742 
3743     if (IsChild())
3744     {
3745         aTlv.IncrementLinkQuality(mParent.GetLinkQualityIn());
3746     }
3747 
3748     for (const Router &router : Get<RouterTable>())
3749     {
3750         if (router.GetRloc16() == GetRloc16())
3751         {
3752             continue;
3753         }
3754 
3755         if (!router.IsStateValid())
3756         {
3757             continue;
3758         }
3759 
3760         aTlv.IncrementLinkQuality(router.GetTwoWayLinkQuality());
3761     }
3762 
3763     aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
3764     aTlv.SetLeaderCost(Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost));
3765     aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3766     aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
3767     aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
3768 }
3769 
ShouldDowngrade(uint8_t aNeighborId,const RouteTlv & aRouteTlv) const3770 bool MleRouter::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
3771 {
3772     // Determine whether all conditions are satisfied for the router
3773     // to downgrade after receiving info for a neighboring router
3774     // with Router ID `aNeighborId` along with its `aRouteTlv`.
3775 
3776     bool    shouldDowngrade   = false;
3777     uint8_t activeRouterCount = mRouterTable.GetActiveRouterCount();
3778     uint8_t count;
3779 
3780     VerifyOrExit(IsRouter());
3781     VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
3782 
3783     VerifyOrExit(!mRouterRoleTransition.IsPending());
3784 
3785     VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
3786 
3787     // Check that we have at least `kMinDowngradeNeighbors`
3788     // neighboring routers with two-way link quality of 2 or better.
3789 
3790     count = 0;
3791 
3792     for (const Router &router : mRouterTable)
3793     {
3794         if (!router.IsStateValid() || (router.GetTwoWayLinkQuality() < kLinkQuality2))
3795         {
3796             continue;
3797         }
3798 
3799         count++;
3800 
3801         if (count >= kMinDowngradeNeighbors)
3802         {
3803             break;
3804         }
3805     }
3806 
3807     VerifyOrExit(count >= kMinDowngradeNeighbors);
3808 
3809     // Check that we have fewer children than three times the number
3810     // of excess routers (defined as the difference between number of
3811     // active routers and `mRouterDowngradeThreshold`).
3812 
3813     count = activeRouterCount - mRouterDowngradeThreshold;
3814     VerifyOrExit(mChildTable.GetNumChildren(Child::kInStateValid) < count * 3);
3815 
3816     // Check that the neighbor has as good or better-quality links to
3817     // same routers.
3818 
3819     VerifyOrExit(NeighborHasComparableConnectivity(aRouteTlv, aNeighborId));
3820 
3821 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3822     // Check if we are eligible to be router due to being a BR.
3823     VerifyOrExit(!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter());
3824 #endif
3825 
3826     shouldDowngrade = true;
3827 
3828 exit:
3829     return shouldDowngrade;
3830 }
3831 
NeighborHasComparableConnectivity(const RouteTlv & aRouteTlv,uint8_t aNeighborId) const3832 bool MleRouter::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const
3833 {
3834     // Check whether the neighboring router with Router ID `aNeighborId`
3835     // (along with its `aRouteTlv`) has as good or better-quality links
3836     // to all our neighboring routers which have a two-way link quality
3837     // of two or better.
3838 
3839     bool isComparable = true;
3840 
3841     for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId;
3842          index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
3843     {
3844         const Router *router;
3845         LinkQuality   localLinkQuality;
3846         LinkQuality   peerLinkQuality;
3847 
3848         if ((routerId == mRouterId) || (routerId == aNeighborId))
3849         {
3850             continue;
3851         }
3852 
3853         router = mRouterTable.FindRouterById(routerId);
3854 
3855         if ((router == nullptr) || !router->IsStateValid())
3856         {
3857             continue;
3858         }
3859 
3860         localLinkQuality = router->GetTwoWayLinkQuality();
3861 
3862         if (localLinkQuality < kLinkQuality2)
3863         {
3864             continue;
3865         }
3866 
3867         // `router` is our neighbor with two-way link quality of
3868         // at least two. Check that `aRouteTlv` has as good or
3869         // better-quality link to it as well.
3870 
3871         if (!aRouteTlv.IsRouterIdSet(routerId))
3872         {
3873             ExitNow(isComparable = false);
3874         }
3875 
3876         peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index));
3877 
3878         if (peerLinkQuality < localLinkQuality)
3879         {
3880             ExitNow(isComparable = false);
3881         }
3882     }
3883 
3884 exit:
3885     return isComparable;
3886 }
3887 
SetChildStateToValid(Child & aChild)3888 void MleRouter::SetChildStateToValid(Child &aChild)
3889 {
3890     VerifyOrExit(!aChild.IsStateValid());
3891 
3892     aChild.SetState(Neighbor::kStateValid);
3893     IgnoreError(mChildTable.StoreChild(aChild));
3894 
3895 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
3896     Get<MlrManager>().UpdateProxiedSubscriptions(aChild, MlrManager::MlrAddressArray());
3897 #endif
3898 
3899     mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
3900 
3901 exit:
3902     return;
3903 }
3904 
HasChildren(void)3905 bool MleRouter::HasChildren(void) { return mChildTable.HasChildren(Child::kInStateValidOrAttaching); }
3906 
RemoveChildren(void)3907 void MleRouter::RemoveChildren(void)
3908 {
3909     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
3910     {
3911         RemoveNeighbor(child);
3912     }
3913 }
3914 
SetAssignParentPriority(int8_t aParentPriority)3915 Error MleRouter::SetAssignParentPriority(int8_t aParentPriority)
3916 {
3917     Error error = kErrorNone;
3918 
3919     VerifyOrExit(aParentPriority <= kParentPriorityHigh && aParentPriority >= kParentPriorityUnspecified,
3920                  error = kErrorInvalidArgs);
3921 
3922     mParentPriority = aParentPriority;
3923 
3924 exit:
3925     return error;
3926 }
3927 
GetMaxChildTimeout(uint32_t & aTimeout) const3928 Error MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
3929 {
3930     Error error = kErrorNotFound;
3931 
3932     aTimeout = 0;
3933 
3934     VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
3935 
3936     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
3937     {
3938         if (child.IsFullThreadDevice())
3939         {
3940             continue;
3941         }
3942 
3943         if (child.GetTimeout() > aTimeout)
3944         {
3945             aTimeout = child.GetTimeout();
3946         }
3947 
3948         error = kErrorNone;
3949     }
3950 
3951 exit:
3952     return error;
3953 }
3954 
3955 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
SendTimeSync(void)3956 Error MleRouter::SendTimeSync(void)
3957 {
3958     Error        error = kErrorNone;
3959     Ip6::Address destination;
3960     TxMessage   *message = nullptr;
3961 
3962     VerifyOrExit((message = NewMleMessage(kCommandTimeSync)) != nullptr, error = kErrorNoBufs);
3963 
3964     message->SetTimeSync(true);
3965 
3966     destination.SetToLinkLocalAllNodesMulticast();
3967     SuccessOrExit(error = message->SendTo(destination));
3968 
3969     Log(kMessageSend, kTypeTimeSync, destination);
3970 
3971 exit:
3972     FreeMessageOnError(message, error);
3973     return error;
3974 }
3975 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3976 
3977 //----------------------------------------------------------------------------------------------------------------------
3978 // RouterRoleTransition
3979 
RouterRoleTransition(void)3980 MleRouter::RouterRoleTransition::RouterRoleTransition(void)
3981     : mTimeout(0)
3982     , mJitter(kRouterSelectionJitter)
3983 {
3984 }
3985 
StartTimeout(void)3986 void MleRouter::RouterRoleTransition::StartTimeout(void)
3987 {
3988     mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter);
3989 }
3990 
HandleTimeTick(void)3991 bool MleRouter::RouterRoleTransition::HandleTimeTick(void)
3992 {
3993     bool expired = false;
3994 
3995     VerifyOrExit(mTimeout > 0);
3996     mTimeout--;
3997     expired = (mTimeout == 0);
3998 
3999 exit:
4000     return expired;
4001 }
4002 
4003 //----------------------------------------------------------------------------------------------------------------------
4004 // RouterRoleRestorer
4005 
RouterRoleRestorer(Instance & aInstance)4006 MleRouter::RouterRoleRestorer::RouterRoleRestorer(Instance &aInstance)
4007     : InstanceLocator(aInstance)
4008     , mAttempts(0)
4009 {
4010 }
4011 
Start(DeviceRole aPreviousRole)4012 void MleRouter::RouterRoleRestorer::Start(DeviceRole aPreviousRole)
4013 {
4014     // If the device was previously the leader or had more than
4015     // `kMinCriticalChildrenCount` children, we use more link
4016     // request attempts.
4017 
4018     mAttempts = 0;
4019 
4020     switch (aPreviousRole)
4021     {
4022     case kRoleRouter:
4023         if (Get<MleRouter>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount)
4024         {
4025             mAttempts = kMaxTxCount;
4026             break;
4027         }
4028 
4029         OT_FALL_THROUGH;
4030 
4031     case kRoleLeader:
4032         mAttempts = kMaxCriticalTxCount;
4033         break;
4034 
4035     case kRoleChild:
4036     case kRoleDetached:
4037     case kRoleDisabled:
4038         break;
4039     }
4040 
4041     SendMulticastLinkRequest();
4042 }
4043 
HandleTimer(void)4044 void MleRouter::RouterRoleRestorer::HandleTimer(void)
4045 {
4046     if (mAttempts > 0)
4047     {
4048         mAttempts--;
4049     }
4050 
4051     SendMulticastLinkRequest();
4052 }
4053 
SendMulticastLinkRequest(void)4054 void MleRouter::RouterRoleRestorer::SendMulticastLinkRequest(void)
4055 {
4056     uint32_t delay;
4057 
4058     VerifyOrExit(Get<Mle>().IsDetached(), mAttempts = 0);
4059 
4060     if (mAttempts == 0)
4061     {
4062         IgnoreError(Get<Mle>().BecomeDetached());
4063         ExitNow();
4064     }
4065 
4066     Get<MleRouter>().SendLinkRequest(nullptr);
4067 
4068     delay = (mAttempts == 1) ? kLinkRequestTimeout
4069                              : Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
4070 
4071     Get<Mle>().mAttachTimer.Start(delay);
4072 
4073 exit:
4074     return;
4075 }
4076 
4077 } // namespace Mle
4078 } // namespace ot
4079 
4080 #endif // OPENTHREAD_FTD
4081