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