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