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