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