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