1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements MLE functionality required for the Thread Child, Router and Leader roles.
32  */
33 
34 #include "mle.hpp"
35 
36 #include <openthread/platform/radio.h>
37 #include <openthread/platform/time.h>
38 
39 #include "common/code_utils.hpp"
40 #include "common/debug.hpp"
41 #include "common/encoding.hpp"
42 #include "common/instance.hpp"
43 #include "common/locator_getters.hpp"
44 #include "common/logging.hpp"
45 #include "common/random.hpp"
46 #include "common/settings.hpp"
47 #include "crypto/aes_ccm.hpp"
48 #include "meshcop/meshcop.hpp"
49 #include "meshcop/meshcop_tlvs.hpp"
50 #include "net/netif.hpp"
51 #include "net/udp6.hpp"
52 #include "thread/address_resolver.hpp"
53 #include "thread/key_manager.hpp"
54 #include "thread/link_metrics.hpp"
55 #include "thread/mle_router.hpp"
56 #include "thread/thread_netif.hpp"
57 #include "thread/time_sync_service.hpp"
58 
59 using ot::Encoding::BigEndian::HostSwap16;
60 
61 namespace ot {
62 namespace Mle {
63 
Mle(Instance & aInstance)64 Mle::Mle(Instance &aInstance)
65     : InstanceLocator(aInstance)
66     , mRetrieveNewNetworkData(false)
67     , mRole(kRoleDisabled)
68     , mNeighborTable(aInstance)
69     , mDeviceMode(DeviceMode::kModeRxOnWhenIdle)
70     , mAttachState(kAttachStateIdle)
71     , mReattachState(kReattachStop)
72     , mAttachCounter(0)
73     , mAnnounceDelay(kAnnounceTimeout)
74     , mAttachTimer(aInstance, Mle::HandleAttachTimer)
75     , mDelayedResponseTimer(aInstance, Mle::HandleDelayedResponseTimer)
76     , mMessageTransmissionTimer(aInstance, Mle::HandleMessageTransmissionTimer)
77     , mParentLeaderCost(0)
78     , mParentRequestMode(kAttachAny)
79     , mParentPriority(0)
80     , mParentLinkQuality3(0)
81     , mParentLinkQuality2(0)
82     , mParentLinkQuality1(0)
83     , mParentSedBufferSize(0)
84     , mParentSedDatagramCount(0)
85     , mChildUpdateAttempts(0)
86     , mChildUpdateRequestState(kChildUpdateRequestNone)
87     , mDataRequestAttempts(0)
88     , mDataRequestState(kDataRequestNone)
89     , mAddressRegistrationMode(kAppendAllAddresses)
90     , mHasRestored(false)
91     , mParentLinkMargin(0)
92     , mParentIsSingleton(false)
93     , mReceivedResponseFromParent(false)
94     , mSocket(aInstance)
95     , mTimeout(kMleEndDeviceTimeout)
96 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
97     , mCslTimeout(OPENTHREAD_CONFIG_CSL_TIMEOUT)
98 #endif
99 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
100     , mPreviousParentRloc(Mac::kShortAddrInvalid)
101 #endif
102 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
103     , mParentSearchIsInBackoff(false)
104     , mParentSearchBackoffWasCanceled(false)
105     , mParentSearchRecentlyDetached(false)
106     , mParentSearchBackoffCancelTime(0)
107     , mParentSearchTimer(aInstance, Mle::HandleParentSearchTimer)
108 #endif
109     , mAnnounceChannel(0)
110     , mAlternateChannel(0)
111     , mAlternatePanId(Mac::kPanIdBroadcast)
112     , mAlternateTimestamp(0)
113     , mParentResponseCb(nullptr)
114     , mParentResponseCbContext(nullptr)
115 {
116     MeshLocalPrefix meshLocalPrefix;
117 
118     mParent.Init(aInstance);
119     mParentCandidate.Init(aInstance);
120 
121     mLeaderData.Clear();
122     mParentLeaderData.Clear();
123     mParent.Clear();
124     mParentCandidate.Clear();
125     ResetCounters();
126 
127     mLinkLocal64.InitAsThreadOrigin(/* aPreferred */ true);
128     mLinkLocal64.GetAddress().SetToLinkLocalAddress(Get<Mac::Mac>().GetExtAddress());
129 
130     mLeaderAloc.InitAsThreadOriginRealmLocalScope();
131 
132 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
133     for (Ip6::Netif::UnicastAddress &serviceAloc : mServiceAlocs)
134     {
135         serviceAloc.InitAsThreadOriginRealmLocalScope();
136         serviceAloc.GetAddress().GetIid().SetLocator(Mac::kShortAddrInvalid);
137     }
138 #endif
139 
140     meshLocalPrefix.SetFromExtendedPanId(Get<Mac::Mac>().GetExtendedPanId());
141 
142     mMeshLocal64.InitAsThreadOriginRealmLocalScope();
143     mMeshLocal64.GetAddress().GetIid().GenerateRandom();
144 
145     mMeshLocal16.InitAsThreadOriginRealmLocalScope();
146     mMeshLocal16.GetAddress().GetIid().SetToLocator(0);
147     mMeshLocal16.mRloc = true;
148 
149     // Store RLOC address reference in MPL module.
150     Get<Ip6::Mpl>().SetMatchingAddress(mMeshLocal16.GetAddress());
151 
152     mLinkLocalAllThreadNodes.Clear();
153     mLinkLocalAllThreadNodes.GetAddress().mFields.m16[0] = HostSwap16(0xff32);
154     mLinkLocalAllThreadNodes.GetAddress().mFields.m16[7] = HostSwap16(0x0001);
155 
156     mRealmLocalAllThreadNodes.Clear();
157     mRealmLocalAllThreadNodes.GetAddress().mFields.m16[0] = HostSwap16(0xff33);
158     mRealmLocalAllThreadNodes.GetAddress().mFields.m16[7] = HostSwap16(0x0001);
159 
160     SetMeshLocalPrefix(meshLocalPrefix);
161 
162     // `SetMeshLocalPrefix()` also adds the Mesh-Local EID and subscribes
163     // to the Link- and Realm-Local All Thread Nodes multicast addresses.
164 }
165 
Enable(void)166 Error Mle::Enable(void)
167 {
168     Error error = kErrorNone;
169 
170     UpdateLinkLocalAddress();
171     SuccessOrExit(error = mSocket.Open(&Mle::HandleUdpReceive, this));
172     SuccessOrExit(error = mSocket.Bind(kUdpPort));
173 
174 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
175     StartParentSearchTimer();
176 #endif
177 exit:
178     return error;
179 }
180 
ScheduleChildUpdateRequest(void)181 void Mle::ScheduleChildUpdateRequest(void)
182 {
183     mChildUpdateRequestState = kChildUpdateRequestPending;
184     ScheduleMessageTransmissionTimer();
185 }
186 
Disable(void)187 Error Mle::Disable(void)
188 {
189     Error error = kErrorNone;
190 
191     Stop(false);
192     SuccessOrExit(error = mSocket.Close());
193     Get<ThreadNetif>().RemoveUnicastAddress(mLinkLocal64);
194 
195 exit:
196     return error;
197 }
198 
Start(bool aAnnounceAttach)199 Error Mle::Start(bool aAnnounceAttach)
200 {
201     Error error = kErrorNone;
202 
203     // cannot bring up the interface if IEEE 802.15.4 promiscuous mode is enabled
204     VerifyOrExit(!Get<Radio>().GetPromiscuous(), error = kErrorInvalidState);
205     VerifyOrExit(Get<ThreadNetif>().IsUp(), error = kErrorInvalidState);
206 
207     if (Get<Mac::Mac>().GetPanId() == Mac::kPanIdBroadcast)
208     {
209         Get<Mac::Mac>().SetPanId(Mac::GenerateRandomPanId());
210     }
211 
212     SetStateDetached();
213 
214     ApplyMeshLocalPrefix();
215     SetRloc16(GetRloc16());
216 
217     mAttachCounter = 0;
218 
219     Get<KeyManager>().Start();
220 
221     if (!aAnnounceAttach)
222     {
223         mReattachState = kReattachStart;
224     }
225 
226     if (aAnnounceAttach || (GetRloc16() == Mac::kShortAddrInvalid))
227     {
228         IgnoreError(BecomeChild(kAttachAny));
229     }
230 #if OPENTHREAD_FTD
231     else if (IsActiveRouter(GetRloc16()))
232     {
233         if (Get<MleRouter>().BecomeRouter(ThreadStatusTlv::kTooFewRouters) != kErrorNone)
234         {
235             IgnoreError(BecomeChild(kAttachAny));
236         }
237     }
238 #endif
239     else
240     {
241         mChildUpdateAttempts = 0;
242         IgnoreError(SendChildUpdateRequest());
243     }
244 
245 exit:
246     return error;
247 }
248 
Stop(bool aClearNetworkDatasets)249 void Mle::Stop(bool aClearNetworkDatasets)
250 {
251     if (aClearNetworkDatasets)
252     {
253         Get<MeshCoP::ActiveDataset>().HandleDetach();
254         Get<MeshCoP::PendingDataset>().HandleDetach();
255     }
256 
257     VerifyOrExit(!IsDisabled());
258 
259     Get<KeyManager>().Stop();
260     SetStateDetached();
261     Get<ThreadNetif>().UnsubscribeMulticast(mRealmLocalAllThreadNodes);
262     Get<ThreadNetif>().UnsubscribeMulticast(mLinkLocalAllThreadNodes);
263     Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocal16);
264     Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocal64);
265 
266     SetRole(kRoleDisabled);
267 
268 exit:
269     return;
270 }
271 
SetRole(DeviceRole aRole)272 void Mle::SetRole(DeviceRole aRole)
273 {
274     DeviceRole oldRole = mRole;
275 
276     SuccessOrExit(Get<Notifier>().Update(mRole, aRole, kEventThreadRoleChanged));
277 
278     otLogNoteMle("Role %s -> %s", RoleToString(oldRole), RoleToString(mRole));
279 
280     switch (mRole)
281     {
282     case kRoleDisabled:
283         mCounters.mDisabledRole++;
284         break;
285     case kRoleDetached:
286         mCounters.mDetachedRole++;
287         break;
288     case kRoleChild:
289         mCounters.mChildRole++;
290         break;
291     case kRoleRouter:
292         mCounters.mRouterRole++;
293         break;
294     case kRoleLeader:
295         mCounters.mLeaderRole++;
296         break;
297     }
298 
299     // If the previous state is disabled, the parent can be in kStateRestored.
300     if (!IsChild() && oldRole != kRoleDisabled)
301     {
302         mParent.SetState(Neighbor::kStateInvalid);
303     }
304 
305 exit:
306     OT_UNUSED_VARIABLE(oldRole);
307 }
308 
SetAttachState(AttachState aState)309 void Mle::SetAttachState(AttachState aState)
310 {
311     VerifyOrExit(aState != mAttachState);
312     otLogInfoMle("AttachState %s -> %s", AttachStateToString(mAttachState), AttachStateToString(aState));
313     mAttachState = aState;
314 
315 exit:
316     return;
317 }
318 
Restore(void)319 Error Mle::Restore(void)
320 {
321     Error                 error = kErrorNone;
322     Settings::NetworkInfo networkInfo;
323     Settings::ParentInfo  parentInfo;
324 
325     IgnoreError(Get<MeshCoP::ActiveDataset>().Restore());
326     IgnoreError(Get<MeshCoP::PendingDataset>().Restore());
327 
328 #if OPENTHREAD_CONFIG_DUA_ENABLE
329     Get<DuaManager>().Restore();
330 #endif
331 
332     SuccessOrExit(error = Get<Settings>().Read(networkInfo));
333 
334     Get<KeyManager>().SetCurrentKeySequence(networkInfo.GetKeySequence());
335     Get<KeyManager>().SetMleFrameCounter(networkInfo.GetMleFrameCounter());
336     Get<KeyManager>().SetAllMacFrameCounters(networkInfo.GetMacFrameCounter());
337     mDeviceMode.Set(networkInfo.GetDeviceMode());
338 
339     // force re-attach when version mismatch.
340     VerifyOrExit(networkInfo.GetVersion() == kThreadVersion);
341 
342     switch (networkInfo.GetRole())
343     {
344     case kRoleChild:
345     case kRoleRouter:
346     case kRoleLeader:
347         break;
348 
349     default:
350         ExitNow();
351     }
352 
353     Get<Mac::Mac>().SetShortAddress(networkInfo.GetRloc16());
354     Get<Mac::Mac>().SetExtAddress(networkInfo.GetExtAddress());
355 
356     mMeshLocal64.GetAddress().SetIid(networkInfo.GetMeshLocalIid());
357 
358     if (networkInfo.GetRloc16() == Mac::kShortAddrInvalid)
359     {
360         ExitNow();
361     }
362 
363     if (!IsActiveRouter(networkInfo.GetRloc16()))
364     {
365         error = Get<Settings>().Read(parentInfo);
366 
367         if (error != kErrorNone)
368         {
369             // If the restored RLOC16 corresponds to an end-device, it
370             // is expected that the `ParentInfo` settings to be valid
371             // as well. The device can still recover from such an invalid
372             // setting by skipping the re-attach ("Child Update Request"
373             // exchange) and going through the full attach process.
374 
375             otLogWarnMle("Invalid settings - no saved parent info with valid end-device RLOC16 0x%04x",
376                          networkInfo.GetRloc16());
377             ExitNow();
378         }
379 
380         mParent.Clear();
381         mParent.SetExtAddress(parentInfo.GetExtAddress());
382         mParent.SetVersion(static_cast<uint8_t>(parentInfo.GetVersion()));
383         mParent.SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
384                                          DeviceMode::kModeFullNetworkData));
385         mParent.SetRloc16(Rloc16FromRouterId(RouterIdFromRloc16(networkInfo.GetRloc16())));
386         mParent.SetState(Neighbor::kStateRestored);
387 
388 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
389         mPreviousParentRloc = mParent.GetRloc16();
390 #endif
391     }
392 #if OPENTHREAD_FTD
393     else
394     {
395         Get<MleRouter>().SetRouterId(RouterIdFromRloc16(GetRloc16()));
396         Get<MleRouter>().SetPreviousPartitionId(networkInfo.GetPreviousPartitionId());
397         Get<ChildTable>().Restore();
398     }
399 #endif
400 
401     // Sucessfully restored the network information from non-volatile settings after boot.
402     mHasRestored = true;
403 
404 exit:
405     return error;
406 }
407 
Store(void)408 Error Mle::Store(void)
409 {
410     Error                 error = kErrorNone;
411     Settings::NetworkInfo networkInfo;
412 
413     networkInfo.Init();
414 
415     if (IsAttached())
416     {
417         // Only update network information while we are attached to
418         // avoid losing/overwriting previous information when a reboot
419         // occurs after a message is sent but before attaching.
420 
421         networkInfo.SetRole(mRole);
422         networkInfo.SetRloc16(GetRloc16());
423         networkInfo.SetPreviousPartitionId(mLeaderData.GetPartitionId());
424         networkInfo.SetExtAddress(Get<Mac::Mac>().GetExtAddress());
425         networkInfo.SetMeshLocalIid(mMeshLocal64.GetAddress().GetIid());
426         networkInfo.SetVersion(kThreadVersion);
427 
428         if (IsChild())
429         {
430             Settings::ParentInfo parentInfo;
431 
432             parentInfo.Init();
433             parentInfo.SetExtAddress(mParent.GetExtAddress());
434             parentInfo.SetVersion(mParent.GetVersion());
435 
436             SuccessOrExit(error = Get<Settings>().Save(parentInfo));
437         }
438     }
439     else
440     {
441         // When not attached, read out any previous saved `NetworkInfo`.
442         // If there is none, it indicates that device was never attached
443         // before. In that case, no need to save any info (note that on
444         // a device reset the MLE/MAC frame counters would reset but
445         // device also starts with a new randomly generated extended
446         // address. If there is a previously saved `NetworkInfo`, we
447         // just update the key sequence and MAC and MLE frame counters.
448 
449         SuccessOrExit(Get<Settings>().Read(networkInfo));
450     }
451 
452     networkInfo.SetKeySequence(Get<KeyManager>().GetCurrentKeySequence());
453     networkInfo.SetMleFrameCounter(Get<KeyManager>().GetMleFrameCounter() +
454                                    OPENTHREAD_CONFIG_STORE_FRAME_COUNTER_AHEAD);
455     networkInfo.SetMacFrameCounter(Get<KeyManager>().GetMaximumMacFrameCounter() +
456                                    OPENTHREAD_CONFIG_STORE_FRAME_COUNTER_AHEAD);
457     networkInfo.SetDeviceMode(mDeviceMode.Get());
458 
459     SuccessOrExit(error = Get<Settings>().Save(networkInfo));
460 
461     Get<KeyManager>().SetStoredMleFrameCounter(networkInfo.GetMleFrameCounter());
462     Get<KeyManager>().SetStoredMacFrameCounter(networkInfo.GetMacFrameCounter());
463 
464     otLogDebgMle("Store Network Information");
465 
466 exit:
467     return error;
468 }
469 
BecomeDetached(void)470 Error Mle::BecomeDetached(void)
471 {
472     Error error = kErrorNone;
473 
474     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
475 
476     // In case role is already detached and attach state is `kAttachStateStart`
477     // (i.e., waiting to start an attach attempt), there is no need to make any
478     // changes.
479 
480     VerifyOrExit(!IsDetached() || mAttachState != kAttachStateStart);
481 
482     // not in reattach stage after reset
483     if (mReattachState == kReattachStop)
484     {
485         Get<MeshCoP::PendingDataset>().HandleDetach();
486     }
487 
488 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
489     mParentSearchRecentlyDetached = true;
490 #endif
491 
492     SetStateDetached();
493     mParent.SetState(Neighbor::kStateInvalid);
494     SetRloc16(Mac::kShortAddrInvalid);
495     IgnoreError(BecomeChild(kAttachAny));
496 
497 exit:
498     return error;
499 }
500 
BecomeChild(AttachMode aMode)501 Error Mle::BecomeChild(AttachMode aMode)
502 {
503     Error error = kErrorNone;
504 
505     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
506     VerifyOrExit(!IsAttaching(), error = kErrorBusy);
507 
508     if (!IsDetached())
509     {
510         mAttachCounter = 0;
511     }
512 
513     if (mReattachState == kReattachStart)
514     {
515         if (Get<MeshCoP::ActiveDataset>().Restore() == kErrorNone)
516         {
517             mReattachState = kReattachActive;
518         }
519         else
520         {
521             mReattachState = kReattachStop;
522         }
523     }
524 
525     mParentCandidate.Clear();
526     SetAttachState(kAttachStateStart);
527     mParentRequestMode = aMode;
528 
529     if (aMode != kAttachBetter)
530     {
531 #if OPENTHREAD_FTD
532         if (IsFullThreadDevice())
533         {
534             Get<MleRouter>().StopAdvertiseTrickleTimer();
535         }
536 #endif
537     }
538     else
539     {
540         mCounters.mBetterPartitionAttachAttempts++;
541     }
542 
543     mAttachTimer.Start(GetAttachStartDelay());
544 
545     if (IsDetached())
546     {
547         mAttachCounter++;
548 
549         if (mAttachCounter == 0)
550         {
551             mAttachCounter--;
552         }
553 
554         mCounters.mAttachAttempts++;
555 
556         if (!IsRxOnWhenIdle())
557         {
558             Get<Mac::Mac>().SetRxOnWhenIdle(false);
559         }
560     }
561 
562 exit:
563     return error;
564 }
565 
GetAttachStartDelay(void) const566 uint32_t Mle::GetAttachStartDelay(void) const
567 {
568     uint32_t delay = 1;
569     uint32_t jitter;
570 
571     VerifyOrExit(IsDetached());
572 
573     if (mAttachCounter == 0)
574     {
575         delay = 1 + Random::NonCrypto::GetUint32InRange(0, kParentRequestRouterTimeout);
576         ExitNow();
577     }
578 #if OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_ENABLE
579     else
580     {
581         uint16_t       counter = mAttachCounter - 1;
582         const uint32_t ratio   = kAttachBackoffMaxInterval / kAttachBackoffMinInterval;
583 
584         if ((counter < sizeof(ratio) * CHAR_BIT) && ((1UL << counter) <= ratio))
585         {
586             delay = kAttachBackoffMinInterval;
587             delay <<= counter;
588         }
589         else
590         {
591             delay = Random::NonCrypto::AddJitter(kAttachBackoffMaxInterval, kAttachBackoffJitter);
592         }
593     }
594 #endif // OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_ENABLE
595 
596     jitter = Random::NonCrypto::GetUint32InRange(0, kAttachStartJitter);
597 
598     if (jitter + delay > delay) // check for overflow
599     {
600         delay += jitter;
601     }
602 
603     otLogNoteMle("Attach attempt %d unsuccessful, will try again in %u.%03u seconds", mAttachCounter, delay / 1000,
604                  delay % 1000);
605 
606 exit:
607     return delay;
608 }
609 
IsAttached(void) const610 bool Mle::IsAttached(void) const
611 {
612     return (IsChild() || IsRouter() || IsLeader());
613 }
614 
IsRouterOrLeader(void) const615 bool Mle::IsRouterOrLeader(void) const
616 {
617     return (IsRouter() || IsLeader());
618 }
619 
SetStateDetached(void)620 void Mle::SetStateDetached(void)
621 {
622 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
623     if (Get<Mac::Mac>().IsCslEnabled())
624     {
625         IgnoreError(Get<Radio>().EnableCsl(0, GetParent().GetRloc16(), &GetParent().GetExtAddress()));
626     }
627 #endif
628 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
629     Get<BackboneRouter::Local>().Reset();
630 #endif
631 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
632     Get<BackboneRouter::Leader>().Reset();
633 #endif
634 
635     if (IsLeader())
636     {
637         Get<ThreadNetif>().RemoveUnicastAddress(mLeaderAloc);
638     }
639 
640     SetRole(kRoleDetached);
641     SetAttachState(kAttachStateIdle);
642     mAttachTimer.Stop();
643     mMessageTransmissionTimer.Stop();
644     mChildUpdateRequestState = kChildUpdateRequestNone;
645     mChildUpdateAttempts     = 0;
646     mDataRequestState        = kDataRequestNone;
647     mDataRequestAttempts     = 0;
648     Get<MeshForwarder>().SetRxOnWhenIdle(true);
649     Get<Mac::Mac>().SetBeaconEnabled(false);
650 #if OPENTHREAD_FTD
651     Get<MleRouter>().HandleDetachStart();
652 #endif
653     Get<Ip6::Ip6>().SetForwardingEnabled(false);
654 #if OPENTHREAD_FTD
655     Get<Ip6::Mpl>().SetTimerExpirations(0);
656 #endif
657 }
658 
SetStateChild(uint16_t aRloc16)659 void Mle::SetStateChild(uint16_t aRloc16)
660 {
661     if (IsLeader())
662     {
663         Get<ThreadNetif>().RemoveUnicastAddress(mLeaderAloc);
664     }
665 
666     SetRloc16(aRloc16);
667     SetRole(kRoleChild);
668     SetAttachState(kAttachStateIdle);
669     mAttachTimer.Start(kAttachBackoffDelayToResetCounter);
670     mReattachState       = kReattachStop;
671     mChildUpdateAttempts = 0;
672     mDataRequestAttempts = 0;
673     Get<Mac::Mac>().SetBeaconEnabled(false);
674     ScheduleMessageTransmissionTimer();
675 
676 #if OPENTHREAD_FTD
677     if (IsFullThreadDevice())
678     {
679         Get<MleRouter>().HandleChildStart(mParentRequestMode);
680     }
681 #endif
682 
683     Get<Ip6::Ip6>().SetForwardingEnabled(false);
684 #if OPENTHREAD_FTD
685     Get<Ip6::Mpl>().SetTimerExpirations(kMplChildDataMessageTimerExpirations);
686 #endif
687 
688     // send announce after attached if needed
689     InformPreviousChannel();
690 
691 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
692     UpdateParentSearchState();
693 #endif
694 
695 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
696     InformPreviousParent();
697     mPreviousParentRloc = mParent.GetRloc16();
698 #endif
699 
700 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
701     if (Get<Mac::Mac>().IsCslCapable())
702     {
703         uint32_t period = IsRxOnWhenIdle() ? 0 : Get<Mac::Mac>().GetCslPeriod();
704         IgnoreError(Get<Radio>().EnableCsl(period, GetParent().GetRloc16(), &GetParent().GetExtAddress()));
705         ScheduleChildUpdateRequest();
706     }
707 #endif
708 }
709 
InformPreviousChannel(void)710 void Mle::InformPreviousChannel(void)
711 {
712     VerifyOrExit(mAlternatePanId != Mac::kPanIdBroadcast);
713     VerifyOrExit(IsChild() || IsRouter());
714 
715 #if OPENTHREAD_FTD
716     VerifyOrExit(!IsFullThreadDevice() || IsRouter() || Get<MleRouter>().GetRouterSelectionJitterTimeout() == 0);
717 #endif
718 
719     mAlternatePanId = Mac::kPanIdBroadcast;
720     Get<AnnounceBeginServer>().SendAnnounce(1 << mAlternateChannel);
721 
722 exit:
723     return;
724 }
725 
SetTimeout(uint32_t aTimeout)726 void Mle::SetTimeout(uint32_t aTimeout)
727 {
728     VerifyOrExit(mTimeout != aTimeout);
729 
730     if (aTimeout < kMinTimeout)
731     {
732         aTimeout = kMinTimeout;
733     }
734 
735     mTimeout = aTimeout;
736 
737     Get<DataPollSender>().RecalculatePollPeriod();
738 
739     if (IsChild())
740     {
741         IgnoreError(SendChildUpdateRequest());
742     }
743 
744 exit:
745     return;
746 }
747 
SetDeviceMode(DeviceMode aDeviceMode)748 Error Mle::SetDeviceMode(DeviceMode aDeviceMode)
749 {
750     Error      error   = kErrorNone;
751     DeviceMode oldMode = mDeviceMode;
752 
753     VerifyOrExit(aDeviceMode.IsValid(), error = kErrorInvalidArgs);
754     VerifyOrExit(mDeviceMode != aDeviceMode);
755     mDeviceMode = aDeviceMode;
756 
757 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
758     Get<Utils::HistoryTracker>().RecordNetworkInfo();
759 #endif
760 
761 #if OPENTHREAD_CONFIG_OTNS_ENABLE
762     Get<Utils::Otns>().EmitDeviceMode(mDeviceMode);
763 #endif
764 
765     otLogNoteMle("Mode 0x%02x -> 0x%02x [%s]", oldMode.Get(), mDeviceMode.Get(), mDeviceMode.ToString().AsCString());
766 
767     IgnoreError(Store());
768 
769     switch (mRole)
770     {
771     case kRoleDisabled:
772         break;
773 
774     case kRoleDetached:
775         mAttachCounter = 0;
776         SetStateDetached();
777         IgnoreError(BecomeChild(kAttachAny));
778         break;
779 
780     case kRoleChild:
781         SetStateChild(GetRloc16());
782         IgnoreError(SendChildUpdateRequest());
783         break;
784 
785     case kRoleRouter:
786     case kRoleLeader:
787         if (oldMode.IsFullThreadDevice() && !mDeviceMode.IsFullThreadDevice())
788         {
789             IgnoreError(BecomeDetached());
790         }
791 
792         break;
793     }
794 
795 exit:
796     return error;
797 }
798 
UpdateLinkLocalAddress(void)799 void Mle::UpdateLinkLocalAddress(void)
800 {
801     Get<ThreadNetif>().RemoveUnicastAddress(mLinkLocal64);
802     mLinkLocal64.GetAddress().GetIid().SetFromExtAddress(Get<Mac::Mac>().GetExtAddress());
803     Get<ThreadNetif>().AddUnicastAddress(mLinkLocal64);
804 
805     Get<Notifier>().Signal(kEventThreadLinkLocalAddrChanged);
806 }
807 
SetMeshLocalPrefix(const MeshLocalPrefix & aMeshLocalPrefix)808 void Mle::SetMeshLocalPrefix(const MeshLocalPrefix &aMeshLocalPrefix)
809 {
810     VerifyOrExit(GetMeshLocalPrefix() != aMeshLocalPrefix,
811                  Get<Notifier>().SignalIfFirst(kEventThreadMeshLocalAddrChanged));
812 
813     if (Get<ThreadNetif>().IsUp())
814     {
815         Get<ThreadNetif>().RemoveUnicastAddress(mLeaderAloc);
816 
817         // We must remove the old addresses before adding the new ones.
818         Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocal64);
819         Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocal16);
820         Get<ThreadNetif>().UnsubscribeMulticast(mLinkLocalAllThreadNodes);
821         Get<ThreadNetif>().UnsubscribeMulticast(mRealmLocalAllThreadNodes);
822     }
823 
824     mMeshLocal64.GetAddress().SetPrefix(aMeshLocalPrefix);
825     mMeshLocal16.GetAddress().SetPrefix(aMeshLocalPrefix);
826     mLeaderAloc.GetAddress().SetPrefix(aMeshLocalPrefix);
827 
828     // Just keep mesh local prefix if network interface is down
829     VerifyOrExit(Get<ThreadNetif>().IsUp());
830 
831     ApplyMeshLocalPrefix();
832 
833 exit:
834     return;
835 }
836 
837 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMeshLocalIid(const Ip6::InterfaceIdentifier & aMlIid)838 Error Mle::SetMeshLocalIid(const Ip6::InterfaceIdentifier &aMlIid)
839 {
840     Error error = kErrorNone;
841 
842     VerifyOrExit(!Get<ThreadNetif>().HasUnicastAddress(mMeshLocal64), error = kErrorInvalidState);
843 
844     mMeshLocal64.GetAddress().SetIid(aMlIid);
845 exit:
846     return error;
847 }
848 #endif
849 
ApplyMeshLocalPrefix(void)850 void Mle::ApplyMeshLocalPrefix(void)
851 {
852     mLinkLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(GetMeshLocalPrefix());
853     mRealmLocalAllThreadNodes.GetAddress().SetMulticastNetworkPrefix(GetMeshLocalPrefix());
854 
855     VerifyOrExit(!IsDisabled());
856 
857     // Add the addresses back into the table.
858     Get<ThreadNetif>().AddUnicastAddress(mMeshLocal64);
859     Get<ThreadNetif>().SubscribeMulticast(mLinkLocalAllThreadNodes);
860     Get<ThreadNetif>().SubscribeMulticast(mRealmLocalAllThreadNodes);
861 
862     if (IsAttached())
863     {
864         Get<ThreadNetif>().AddUnicastAddress(mMeshLocal16);
865     }
866 
867     // update Leader ALOC
868     if (IsLeader())
869     {
870         Get<ThreadNetif>().AddUnicastAddress(mLeaderAloc);
871     }
872 
873 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
874     Get<MeshCoP::Commissioner>().ApplyMeshLocalPrefix();
875 #endif
876 
877 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
878     Get<MeshCoP::BorderAgent>().ApplyMeshLocalPrefix();
879 #endif
880 
881 #if OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
882     Get<Dhcp6::Server>().ApplyMeshLocalPrefix();
883 #endif
884 
885 #if OPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE
886     Get<NeighborDiscovery::Agent>().ApplyMeshLocalPrefix();
887 #endif
888 
889 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
890 
891     for (Ip6::Netif::UnicastAddress &serviceAloc : mServiceAlocs)
892     {
893         if (serviceAloc.GetAddress().GetIid().GetLocator() != Mac::kShortAddrInvalid)
894         {
895             Get<ThreadNetif>().RemoveUnicastAddress(serviceAloc);
896             serviceAloc.GetAddress().SetPrefix(GetMeshLocalPrefix());
897             Get<ThreadNetif>().AddUnicastAddress(serviceAloc);
898         }
899     }
900 
901 #endif
902 
903 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
904     Get<BackboneRouter::Local>().ApplyMeshLocalPrefix();
905 #endif
906 
907 exit:
908     // Changing the prefix also causes the mesh local address to be different.
909     Get<Notifier>().Signal(kEventThreadMeshLocalAddrChanged);
910 }
911 
GetRloc16(void) const912 uint16_t Mle::GetRloc16(void) const
913 {
914     return Get<Mac::Mac>().GetShortAddress();
915 }
916 
SetRloc16(uint16_t aRloc16)917 void Mle::SetRloc16(uint16_t aRloc16)
918 {
919     uint16_t oldRloc16 = GetRloc16();
920 
921     if (aRloc16 != oldRloc16)
922     {
923         otLogNoteMle("RLOC16 %04x -> %04x", oldRloc16, aRloc16);
924     }
925 
926     if (Get<ThreadNetif>().HasUnicastAddress(mMeshLocal16) &&
927         (mMeshLocal16.GetAddress().GetIid().GetLocator() != aRloc16))
928     {
929         Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocal16);
930         Get<Tmf::Agent>().ClearRequests(mMeshLocal16.GetAddress());
931     }
932 
933     Get<Mac::Mac>().SetShortAddress(aRloc16);
934     Get<Ip6::Mpl>().SetSeedId(aRloc16);
935 
936     if (aRloc16 != Mac::kShortAddrInvalid)
937     {
938         // We can always call `AddUnicastAddress(mMeshLocat16)` and if
939         // the address is already added, it will perform no action.
940 
941         mMeshLocal16.GetAddress().GetIid().SetLocator(aRloc16);
942         Get<ThreadNetif>().AddUnicastAddress(mMeshLocal16);
943 #if OPENTHREAD_FTD
944         Get<AddressResolver>().RestartAddressQueries();
945 #endif
946     }
947 }
948 
SetLeaderData(uint32_t aPartitionId,uint8_t aWeighting,uint8_t aLeaderRouterId)949 void Mle::SetLeaderData(uint32_t aPartitionId, uint8_t aWeighting, uint8_t aLeaderRouterId)
950 {
951     if (mLeaderData.GetPartitionId() != aPartitionId)
952     {
953 #if OPENTHREAD_FTD
954         Get<MleRouter>().HandlePartitionChange();
955 #endif
956         Get<Notifier>().Signal(kEventThreadPartitionIdChanged);
957         mCounters.mPartitionIdChanges++;
958     }
959     else
960     {
961         Get<Notifier>().SignalIfFirst(kEventThreadPartitionIdChanged);
962     }
963 
964     mLeaderData.SetPartitionId(aPartitionId);
965     mLeaderData.SetWeighting(aWeighting);
966     mLeaderData.SetLeaderRouterId(aLeaderRouterId);
967 }
968 
GetLeaderAddress(Ip6::Address & aAddress) const969 Error Mle::GetLeaderAddress(Ip6::Address &aAddress) const
970 {
971     Error error = kErrorNone;
972 
973     VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached);
974 
975     aAddress.SetToRoutingLocator(GetMeshLocalPrefix(), Rloc16FromRouterId(mLeaderData.GetLeaderRouterId()));
976 
977 exit:
978     return error;
979 }
980 
GetLocatorAddress(Ip6::Address & aAddress,uint16_t aLocator) const981 Error Mle::GetLocatorAddress(Ip6::Address &aAddress, uint16_t aLocator) const
982 {
983     Error error = kErrorNone;
984 
985     VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached);
986 
987     memcpy(&aAddress, &mMeshLocal16.GetAddress(), 14);
988     aAddress.GetIid().SetLocator(aLocator);
989 
990 exit:
991     return error;
992 }
993 
GetServiceAloc(uint8_t aServiceId,Ip6::Address & aAddress) const994 Error Mle::GetServiceAloc(uint8_t aServiceId, Ip6::Address &aAddress) const
995 {
996     Error error = kErrorNone;
997 
998     VerifyOrExit(GetRloc16() != Mac::kShortAddrInvalid, error = kErrorDetached);
999     aAddress.SetToAnycastLocator(GetMeshLocalPrefix(), ServiceAlocFromId(aServiceId));
1000 
1001 exit:
1002     return error;
1003 }
1004 
GetLeaderData(void)1005 const LeaderData &Mle::GetLeaderData(void)
1006 {
1007     mLeaderData.SetDataVersion(Get<NetworkData::Leader>().GetVersion());
1008     mLeaderData.SetStableDataVersion(Get<NetworkData::Leader>().GetStableVersion());
1009 
1010     return mLeaderData;
1011 }
1012 
NewMleMessage(void)1013 Message *Mle::NewMleMessage(void)
1014 {
1015     Message *         message;
1016     Message::Settings settings(Message::kNoLinkSecurity, Message::kPriorityNet);
1017 
1018     message = mSocket.NewMessage(0, settings);
1019     VerifyOrExit(message != nullptr);
1020 
1021     message->SetSubType(Message::kSubTypeMleGeneral);
1022 
1023 exit:
1024     return message;
1025 }
1026 
AppendHeader(Message & aMessage,Command aCommand)1027 Error Mle::AppendHeader(Message &aMessage, Command aCommand)
1028 {
1029     Error  error = kErrorNone;
1030     Header header;
1031 
1032     header.Init();
1033 
1034     if (aCommand == kCommandDiscoveryRequest || aCommand == kCommandDiscoveryResponse)
1035     {
1036         header.SetSecuritySuite(Header::kNoSecurity);
1037     }
1038     else
1039     {
1040         header.SetKeyIdMode2();
1041     }
1042 
1043     header.SetCommand(aCommand);
1044 
1045     SuccessOrExit(error = aMessage.AppendBytes(&header, header.GetLength()));
1046 
1047 exit:
1048     return error;
1049 }
1050 
AppendSourceAddress(Message & aMessage) const1051 Error Mle::AppendSourceAddress(Message &aMessage) const
1052 {
1053     return Tlv::Append<SourceAddressTlv>(aMessage, GetRloc16());
1054 }
1055 
AppendStatus(Message & aMessage,StatusTlv::Status aStatus)1056 Error Mle::AppendStatus(Message &aMessage, StatusTlv::Status aStatus)
1057 {
1058     return Tlv::Append<StatusTlv>(aMessage, aStatus);
1059 }
1060 
AppendMode(Message & aMessage,DeviceMode aMode)1061 Error Mle::AppendMode(Message &aMessage, DeviceMode aMode)
1062 {
1063     return Tlv::Append<ModeTlv>(aMessage, aMode.Get());
1064 }
1065 
AppendTimeout(Message & aMessage,uint32_t aTimeout)1066 Error Mle::AppendTimeout(Message &aMessage, uint32_t aTimeout)
1067 {
1068     return Tlv::Append<TimeoutTlv>(aMessage, aTimeout);
1069 }
1070 
AppendChallenge(Message & aMessage,const Challenge & aChallenge)1071 Error Mle::AppendChallenge(Message &aMessage, const Challenge &aChallenge)
1072 {
1073     return Tlv::Append<ChallengeTlv>(aMessage, aChallenge.mBuffer, aChallenge.mLength);
1074 }
1075 
AppendChallenge(Message & aMessage,const uint8_t * aChallenge,uint8_t aChallengeLength)1076 Error Mle::AppendChallenge(Message &aMessage, const uint8_t *aChallenge, uint8_t aChallengeLength)
1077 {
1078     return Tlv::Append<ChallengeTlv>(aMessage, aChallenge, aChallengeLength);
1079 }
1080 
AppendResponse(Message & aMessage,const Challenge & aResponse)1081 Error Mle::AppendResponse(Message &aMessage, const Challenge &aResponse)
1082 {
1083     return Tlv::Append<ResponseTlv>(aMessage, aResponse.mBuffer, aResponse.mLength);
1084 }
1085 
ReadChallengeOrResponse(const Message & aMessage,uint8_t aTlvType,Challenge & aBuffer)1086 Error Mle::ReadChallengeOrResponse(const Message &aMessage, uint8_t aTlvType, Challenge &aBuffer)
1087 {
1088     Error    error;
1089     uint16_t offset;
1090     uint16_t length;
1091 
1092     SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, aTlvType, offset, length));
1093     VerifyOrExit(length >= kMinChallengeSize, error = kErrorParse);
1094 
1095     if (length > kMaxChallengeSize)
1096     {
1097         length = kMaxChallengeSize;
1098     }
1099 
1100     aMessage.ReadBytes(offset, aBuffer.mBuffer, length);
1101     aBuffer.mLength = static_cast<uint8_t>(length);
1102 
1103 exit:
1104     return error;
1105 }
1106 
ReadChallenge(const Message & aMessage,Challenge & aChallenge)1107 Error Mle::ReadChallenge(const Message &aMessage, Challenge &aChallenge)
1108 {
1109     return ReadChallengeOrResponse(aMessage, Tlv::kChallenge, aChallenge);
1110 }
1111 
ReadResponse(const Message & aMessage,Challenge & aResponse)1112 Error Mle::ReadResponse(const Message &aMessage, Challenge &aResponse)
1113 {
1114     return ReadChallengeOrResponse(aMessage, Tlv::kResponse, aResponse);
1115 }
1116 
AppendLinkFrameCounter(Message & aMessage)1117 Error Mle::AppendLinkFrameCounter(Message &aMessage)
1118 {
1119     uint32_t counter;
1120 
1121     // When including Link-layer Frame Counter TLV in an MLE message
1122     // the value is set to the maximum MAC frame counter on all
1123     // supported radio links. All radio links must also start using
1124     // the same counter value as the value included in the TLV.
1125 
1126     counter = Get<KeyManager>().GetMaximumMacFrameCounter();
1127 
1128 #if OPENTHREAD_CONFIG_MULTI_RADIO
1129     Get<KeyManager>().SetAllMacFrameCounters(counter);
1130 #endif
1131 
1132     return Tlv::Append<LinkFrameCounterTlv>(aMessage, counter);
1133 }
1134 
AppendMleFrameCounter(Message & aMessage)1135 Error Mle::AppendMleFrameCounter(Message &aMessage)
1136 {
1137     return Tlv::Append<MleFrameCounterTlv>(aMessage, Get<KeyManager>().GetMleFrameCounter());
1138 }
1139 
ReadFrameCounters(const Message & aMessage,uint32_t & aLinkFrameCounter,uint32_t & aMleFrameCounter) const1140 Error Mle::ReadFrameCounters(const Message &aMessage, uint32_t &aLinkFrameCounter, uint32_t &aMleFrameCounter) const
1141 {
1142     Error error;
1143 
1144     SuccessOrExit(error = Tlv::Find<LinkFrameCounterTlv>(aMessage, aLinkFrameCounter));
1145 
1146     switch (Tlv::Find<MleFrameCounterTlv>(aMessage, aMleFrameCounter))
1147     {
1148     case kErrorNone:
1149         break;
1150     case kErrorNotFound:
1151         aMleFrameCounter = aLinkFrameCounter;
1152         break;
1153     default:
1154         error = kErrorParse;
1155         break;
1156     }
1157 
1158 exit:
1159     return error;
1160 }
1161 
AppendAddress16(Message & aMessage,uint16_t aRloc16)1162 Error Mle::AppendAddress16(Message &aMessage, uint16_t aRloc16)
1163 {
1164     return Tlv::Append<Address16Tlv>(aMessage, aRloc16);
1165 }
1166 
AppendLeaderData(Message & aMessage)1167 Error Mle::AppendLeaderData(Message &aMessage)
1168 {
1169     LeaderDataTlv leaderDataTlv;
1170 
1171     mLeaderData.SetDataVersion(Get<NetworkData::Leader>().GetVersion());
1172     mLeaderData.SetStableDataVersion(Get<NetworkData::Leader>().GetStableVersion());
1173 
1174     leaderDataTlv.Init();
1175     leaderDataTlv.Set(mLeaderData);
1176 
1177     return leaderDataTlv.AppendTo(aMessage);
1178 }
1179 
ReadLeaderData(const Message & aMessage,LeaderData & aLeaderData)1180 Error Mle::ReadLeaderData(const Message &aMessage, LeaderData &aLeaderData)
1181 {
1182     Error         error;
1183     LeaderDataTlv leaderDataTlv;
1184 
1185     SuccessOrExit(error = Tlv::FindTlv(aMessage, leaderDataTlv));
1186     VerifyOrExit(leaderDataTlv.IsValid(), error = kErrorParse);
1187     leaderDataTlv.Get(aLeaderData);
1188 
1189 exit:
1190     return error;
1191 }
1192 
AppendNetworkData(Message & aMessage,bool aStableOnly)1193 Error Mle::AppendNetworkData(Message &aMessage, bool aStableOnly)
1194 {
1195     Error   error = kErrorNone;
1196     uint8_t networkData[NetworkData::NetworkData::kMaxSize];
1197     uint8_t length;
1198 
1199     VerifyOrExit(!mRetrieveNewNetworkData, error = kErrorInvalidState);
1200 
1201     length = sizeof(networkData);
1202     IgnoreError(Get<NetworkData::Leader>().GetNetworkData(aStableOnly, networkData, length));
1203 
1204     error = Tlv::Append<NetworkDataTlv>(aMessage, networkData, length);
1205 
1206 exit:
1207     return error;
1208 }
1209 
AppendTlvRequest(Message & aMessage,const uint8_t * aTlvs,uint8_t aTlvsLength)1210 Error Mle::AppendTlvRequest(Message &aMessage, const uint8_t *aTlvs, uint8_t aTlvsLength)
1211 {
1212     return Tlv::Append<TlvRequestTlv>(aMessage, aTlvs, aTlvsLength);
1213 }
1214 
FindTlvRequest(const Message & aMessage,RequestedTlvs & aRequestedTlvs)1215 Error Mle::FindTlvRequest(const Message &aMessage, RequestedTlvs &aRequestedTlvs)
1216 {
1217     Error    error;
1218     uint16_t offset;
1219     uint16_t length;
1220 
1221     SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kTlvRequest, offset, length));
1222 
1223     if (length > sizeof(aRequestedTlvs.mTlvs))
1224     {
1225         length = sizeof(aRequestedTlvs.mTlvs);
1226     }
1227 
1228     aMessage.ReadBytes(offset, aRequestedTlvs.mTlvs, length);
1229     aRequestedTlvs.mNumTlvs = static_cast<uint8_t>(length);
1230 
1231 exit:
1232     return error;
1233 }
1234 
AppendScanMask(Message & aMessage,uint8_t aScanMask)1235 Error Mle::AppendScanMask(Message &aMessage, uint8_t aScanMask)
1236 {
1237     return Tlv::Append<ScanMaskTlv>(aMessage, aScanMask);
1238 }
1239 
AppendLinkMargin(Message & aMessage,uint8_t aLinkMargin)1240 Error Mle::AppendLinkMargin(Message &aMessage, uint8_t aLinkMargin)
1241 {
1242     return Tlv::Append<LinkMarginTlv>(aMessage, aLinkMargin);
1243 }
1244 
AppendVersion(Message & aMessage)1245 Error Mle::AppendVersion(Message &aMessage)
1246 {
1247     return Tlv::Append<VersionTlv>(aMessage, kThreadVersion);
1248 }
1249 
HasUnregisteredAddress(void)1250 bool Mle::HasUnregisteredAddress(void)
1251 {
1252     bool retval = false;
1253 
1254     // Checks whether there are any addresses in addition to the mesh-local
1255     // address that need to be registered.
1256 
1257     for (const Ip6::Netif::UnicastAddress &addr : Get<ThreadNetif>().GetUnicastAddresses())
1258     {
1259         if (!addr.GetAddress().IsLinkLocal() && !IsRoutingLocator(addr.GetAddress()) &&
1260             !IsAnycastLocator(addr.GetAddress()) && addr.GetAddress() != GetMeshLocal64())
1261         {
1262             ExitNow(retval = true);
1263         }
1264     }
1265 
1266     if (!IsRxOnWhenIdle())
1267     {
1268         // For sleepy end-device, we register any external multicast
1269         // addresses.
1270 
1271         retval = Get<ThreadNetif>().HasAnyExternalMulticastAddress();
1272     }
1273 
1274 exit:
1275     return retval;
1276 }
1277 
AppendAddressRegistration(Message & aMessage,AddressRegistrationMode aMode)1278 Error Mle::AppendAddressRegistration(Message &aMessage, AddressRegistrationMode aMode)
1279 {
1280     Error                    error = kErrorNone;
1281     Tlv                      tlv;
1282     AddressRegistrationEntry entry;
1283     Lowpan::Context          context;
1284     uint8_t                  length      = 0;
1285     uint8_t                  counter     = 0;
1286     uint16_t                 startOffset = aMessage.GetLength();
1287 #if OPENTHREAD_CONFIG_DUA_ENABLE
1288     Ip6::Address domainUnicastAddress;
1289 #endif
1290 
1291     tlv.SetType(Tlv::kAddressRegistration);
1292     SuccessOrExit(error = aMessage.Append(tlv));
1293 
1294     // Prioritize ML-EID
1295     entry.SetContextId(kMeshLocalPrefixContextId);
1296     entry.SetIid(GetMeshLocal64().GetIid());
1297     SuccessOrExit(error = aMessage.AppendBytes(&entry, entry.GetLength()));
1298     length += entry.GetLength();
1299 
1300     // Continue to append the other addresses if not `kAppendMeshLocalOnly` mode
1301     VerifyOrExit(aMode != kAppendMeshLocalOnly);
1302     counter++;
1303 
1304 #if OPENTHREAD_CONFIG_DUA_ENABLE
1305     // Cache Domain Unicast Address.
1306     domainUnicastAddress = Get<DuaManager>().GetDomainUnicastAddress();
1307 
1308     if (Get<ThreadNetif>().HasUnicastAddress(domainUnicastAddress))
1309     {
1310         error = Get<NetworkData::Leader>().GetContext(domainUnicastAddress, context);
1311 
1312         OT_ASSERT(error == kErrorNone);
1313 
1314         // Prioritize DUA, compressed entry
1315         entry.SetContextId(context.mContextId);
1316         entry.SetIid(domainUnicastAddress.GetIid());
1317         SuccessOrExit(error = aMessage.AppendBytes(&entry, entry.GetLength()));
1318         length += entry.GetLength();
1319         counter++;
1320     }
1321 #endif // OPENTHREAD_CONFIG_DUA_ENABLE
1322 
1323     for (const Ip6::Netif::UnicastAddress &addr : Get<ThreadNetif>().GetUnicastAddresses())
1324     {
1325         if (addr.GetAddress().IsLinkLocal() || IsRoutingLocator(addr.GetAddress()) ||
1326             IsAnycastLocator(addr.GetAddress()) || addr.GetAddress() == GetMeshLocal64())
1327         {
1328             continue;
1329         }
1330 
1331 #if OPENTHREAD_CONFIG_DUA_ENABLE
1332         // Skip DUA that was already appended above.
1333         if (addr.GetAddress() == domainUnicastAddress)
1334         {
1335             continue;
1336         }
1337 #endif
1338 
1339         if (Get<NetworkData::Leader>().GetContext(addr.GetAddress(), context) == kErrorNone)
1340         {
1341             // compressed entry
1342             entry.SetContextId(context.mContextId);
1343             entry.SetIid(addr.GetAddress().GetIid());
1344         }
1345         else
1346         {
1347             // uncompressed entry
1348             entry.SetUncompressed();
1349             entry.SetIp6Address(addr.GetAddress());
1350         }
1351 
1352         SuccessOrExit(error = aMessage.AppendBytes(&entry, entry.GetLength()));
1353         length += entry.GetLength();
1354         counter++;
1355         // only continue to append if there is available entry.
1356         VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER);
1357     }
1358 
1359     // Append external multicast addresses.  For sleepy end device,
1360     // register all external multicast addresses with the parent for
1361     // indirect transmission. Since Thread 1.2, non-sleepy MED should
1362     // also register external multicast addresses of scope larger than
1363     // realm with a 1.2 or higher parent.
1364     if (!IsRxOnWhenIdle()
1365 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
1366         || !GetParent().IsThreadVersion1p1()
1367 #endif
1368     )
1369     {
1370         for (const Ip6::Netif::MulticastAddress &addr : Get<ThreadNetif>().IterateExternalMulticastAddresses())
1371         {
1372 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
1373             // For Thread 1.2 MED, skip multicast address with scope not
1374             // larger than realm local when registering.
1375             if (IsRxOnWhenIdle() && !addr.GetAddress().IsMulticastLargerThanRealmLocal())
1376             {
1377                 continue;
1378             }
1379 #endif
1380 
1381             entry.SetUncompressed();
1382             entry.SetIp6Address(addr.GetAddress());
1383             SuccessOrExit(error = aMessage.AppendBytes(&entry, entry.GetLength()));
1384             length += entry.GetLength();
1385 
1386             counter++;
1387             // only continue to append if there is available entry.
1388             VerifyOrExit(counter < OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER);
1389         }
1390     }
1391 
1392 exit:
1393 
1394     if (error == kErrorNone && length > 0)
1395     {
1396         tlv.SetLength(length);
1397         aMessage.Write(startOffset, tlv);
1398     }
1399 
1400     return error;
1401 }
1402 
1403 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
AppendTimeRequest(Message & aMessage)1404 Error Mle::AppendTimeRequest(Message &aMessage)
1405 {
1406     // `TimeRequestTlv` has no value.
1407     return Tlv::Append<TimeRequestTlv>(aMessage, nullptr, 0);
1408 }
1409 
AppendTimeParameter(Message & aMessage)1410 Error Mle::AppendTimeParameter(Message &aMessage)
1411 {
1412     TimeParameterTlv tlv;
1413 
1414     tlv.Init();
1415     tlv.SetTimeSyncPeriod(Get<TimeSync>().GetTimeSyncPeriod());
1416     tlv.SetXtalThreshold(Get<TimeSync>().GetXtalThreshold());
1417 
1418     return tlv.AppendTo(aMessage);
1419 }
1420 
AppendXtalAccuracy(Message & aMessage)1421 Error Mle::AppendXtalAccuracy(Message &aMessage)
1422 {
1423     return Tlv::Append<XtalAccuracyTlv>(aMessage, otPlatTimeGetXtalAccuracy());
1424 }
1425 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1426 
AppendActiveTimestamp(Message & aMessage)1427 Error Mle::AppendActiveTimestamp(Message &aMessage)
1428 {
1429     Error                     error;
1430     ActiveTimestampTlv        timestampTlv;
1431     const MeshCoP::Timestamp *timestamp;
1432 
1433     timestamp = Get<MeshCoP::ActiveDataset>().GetTimestamp();
1434     VerifyOrExit(timestamp, error = kErrorNone);
1435 
1436     timestampTlv.Init();
1437     *static_cast<MeshCoP::Timestamp *>(&timestampTlv) = *timestamp;
1438     error                                             = timestampTlv.AppendTo(aMessage);
1439 
1440 exit:
1441     return error;
1442 }
1443 
AppendPendingTimestamp(Message & aMessage)1444 Error Mle::AppendPendingTimestamp(Message &aMessage)
1445 {
1446     Error                     error;
1447     PendingTimestampTlv       timestampTlv;
1448     const MeshCoP::Timestamp *timestamp;
1449 
1450     timestamp = Get<MeshCoP::PendingDataset>().GetTimestamp();
1451     VerifyOrExit(timestamp && timestamp->GetSeconds() != 0, error = kErrorNone);
1452 
1453     timestampTlv.Init();
1454     *static_cast<MeshCoP::Timestamp *>(&timestampTlv) = *timestamp;
1455     error                                             = timestampTlv.AppendTo(aMessage);
1456 
1457 exit:
1458     return error;
1459 }
1460 
1461 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
AppendCslChannel(Message & aMessage)1462 Error Mle::AppendCslChannel(Message &aMessage)
1463 {
1464     Error         error = kErrorNone;
1465     CslChannelTlv cslChannel;
1466 
1467     // In current implementation, it's allowed to set CSL Channel unspecified. As `0` is not valid for Channel value
1468     // in CSL Channel TLV, if CSL channel is not specified, we don't append CSL Channel TLV.
1469     // And on transmitter side, it would also set CSL Channel for the child to `0` if it doesn't find a CSL Channel
1470     // TLV.
1471     VerifyOrExit(Get<Mac::Mac>().IsCslChannelSpecified());
1472 
1473     cslChannel.Init();
1474     cslChannel.SetChannelPage(0);
1475     cslChannel.SetChannel(Get<Mac::Mac>().GetCslChannel());
1476 
1477     SuccessOrExit(error = aMessage.Append(cslChannel));
1478 
1479 exit:
1480     return error;
1481 }
1482 
AppendCslTimeout(Message & aMessage)1483 Error Mle::AppendCslTimeout(Message &aMessage)
1484 {
1485     OT_ASSERT(Get<Mac::Mac>().IsCslEnabled());
1486     return Tlv::Append<CslTimeoutTlv>(aMessage, mCslTimeout == 0 ? mTimeout : mCslTimeout);
1487 }
1488 
SetCslTimeout(uint32_t aTimeout)1489 void Mle::SetCslTimeout(uint32_t aTimeout)
1490 {
1491     VerifyOrExit(mCslTimeout != aTimeout);
1492 
1493     mCslTimeout = aTimeout;
1494 
1495     Get<DataPollSender>().RecalculatePollPeriod();
1496 
1497     if (Get<Mac::Mac>().IsCslEnabled())
1498     {
1499         ScheduleChildUpdateRequest();
1500     }
1501 
1502 exit:
1503     return;
1504 }
1505 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1506 
1507 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
AppendCslClockAccuracy(Message & aMessage)1508 Error Mle::AppendCslClockAccuracy(Message &aMessage)
1509 {
1510     Error               error = kErrorNone;
1511     CslClockAccuracyTlv cslClockAccuracy;
1512 
1513     cslClockAccuracy.Init();
1514 
1515     cslClockAccuracy.SetCslClockAccuracy(Get<Radio>().GetCslAccuracy());
1516     cslClockAccuracy.SetCslUncertainty(Get<Radio>().GetCslClockUncertainty());
1517 
1518     SuccessOrExit(error = aMessage.Append(cslClockAccuracy));
1519 
1520 exit:
1521     return error;
1522 }
1523 #endif
1524 
HandleNotifierEvents(Events aEvents)1525 void Mle::HandleNotifierEvents(Events aEvents)
1526 {
1527     VerifyOrExit(!IsDisabled());
1528 
1529     if (aEvents.Contains(kEventThreadRoleChanged))
1530     {
1531         if (IsChild() && !IsFullThreadDevice() && mAddressRegistrationMode == kAppendMeshLocalOnly)
1532         {
1533             // If only mesh-local address was registered in the "Child
1534             // ID Request" message, after device is attached, trigger a
1535             // "Child Update Request" to register the remaining
1536             // addresses.
1537 
1538             mAddressRegistrationMode = kAppendAllAddresses;
1539             mChildUpdateRequestState = kChildUpdateRequestPending;
1540             ScheduleMessageTransmissionTimer();
1541         }
1542     }
1543 
1544     if (aEvents.ContainsAny(kEventIp6AddressAdded | kEventIp6AddressRemoved))
1545     {
1546         if (!Get<ThreadNetif>().HasUnicastAddress(mMeshLocal64.GetAddress()))
1547         {
1548             // Mesh Local EID was removed, choose a new one and add it back
1549             mMeshLocal64.GetAddress().GetIid().GenerateRandom();
1550 
1551             Get<ThreadNetif>().AddUnicastAddress(mMeshLocal64);
1552             Get<Notifier>().Signal(kEventThreadMeshLocalAddrChanged);
1553         }
1554 
1555         if (IsChild() && !IsFullThreadDevice())
1556         {
1557             mChildUpdateRequestState = kChildUpdateRequestPending;
1558             ScheduleMessageTransmissionTimer();
1559         }
1560     }
1561 
1562     if (aEvents.ContainsAny(kEventIp6MulticastSubscribed | kEventIp6MulticastUnsubscribed))
1563     {
1564         // When multicast subscription changes, SED always notifies its parent as it depends on its
1565         // parent for indirect transmission. Since Thread 1.2, MED MAY also notify its parent of 1.2
1566         // or higher version as it could depend on its parent to perform Multicast Listener Report.
1567         if (IsChild() && !IsFullThreadDevice() &&
1568             (!IsRxOnWhenIdle()
1569 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
1570              || !GetParent().IsThreadVersion1p1()
1571 #endif
1572                  ))
1573 
1574         {
1575             mChildUpdateRequestState = kChildUpdateRequestPending;
1576             ScheduleMessageTransmissionTimer();
1577         }
1578     }
1579 
1580     if (aEvents.Contains(kEventThreadNetdataChanged))
1581     {
1582 #if OPENTHREAD_FTD
1583         if (IsFullThreadDevice())
1584         {
1585             Get<MleRouter>().HandleNetworkDataUpdateRouter();
1586         }
1587         else
1588 #endif
1589         {
1590             if (!aEvents.Contains(kEventThreadRoleChanged))
1591             {
1592                 mChildUpdateRequestState = kChildUpdateRequestPending;
1593                 ScheduleMessageTransmissionTimer();
1594             }
1595         }
1596 
1597 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
1598         Get<BackboneRouter::Leader>().Update();
1599 #endif
1600 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
1601         UpdateServiceAlocs();
1602 #endif
1603 
1604 #if OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
1605         IgnoreError(Get<Dhcp6::Server>().UpdateService());
1606 #endif
1607 
1608 #if OPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE
1609         Get<NeighborDiscovery::Agent>().UpdateService();
1610 #endif
1611 
1612 #if OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE
1613         Get<Dhcp6::Client>().UpdateAddresses();
1614 #endif
1615     }
1616 
1617     if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadKeySeqCounterChanged))
1618     {
1619         // Store the settings on a key seq change, or when role changes and device
1620         // is attached (i.e., skip `Store()` on role change to detached).
1621 
1622         if (aEvents.Contains(kEventThreadKeySeqCounterChanged) || IsAttached())
1623         {
1624             IgnoreError(Store());
1625         }
1626     }
1627 
1628 exit:
1629     return;
1630 }
1631 
1632 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
UpdateServiceAlocs(void)1633 void Mle::UpdateServiceAlocs(void)
1634 {
1635     uint16_t              rloc               = GetRloc16();
1636     uint16_t              serviceAloc        = 0;
1637     uint8_t               serviceId          = 0;
1638     NetworkData::Iterator serviceIterator    = NetworkData::kIteratorInit;
1639     size_t                serviceAlocsLength = OT_ARRAY_LENGTH(mServiceAlocs);
1640     size_t                i                  = 0;
1641 
1642     VerifyOrExit(!IsDisabled());
1643 
1644     // First remove all alocs which are no longer necessary, to free up space in mServiceAlocs
1645     for (i = 0; i < serviceAlocsLength; i++)
1646     {
1647         serviceAloc = mServiceAlocs[i].GetAddress().GetIid().GetLocator();
1648 
1649         if ((serviceAloc != Mac::kShortAddrInvalid) &&
1650             (!Get<NetworkData::Leader>().ContainsService(Mle::ServiceIdFromAloc(serviceAloc), rloc)))
1651         {
1652             Get<ThreadNetif>().RemoveUnicastAddress(mServiceAlocs[i]);
1653             mServiceAlocs[i].GetAddress().GetIid().SetLocator(Mac::kShortAddrInvalid);
1654         }
1655     }
1656 
1657     // Now add any missing service alocs which should be there, if there is enough space in mServiceAlocs
1658     while (Get<NetworkData::Leader>().GetNextServiceId(serviceIterator, rloc, serviceId) == kErrorNone)
1659     {
1660         for (i = 0; i < serviceAlocsLength; i++)
1661         {
1662             serviceAloc = mServiceAlocs[i].GetAddress().GetIid().GetLocator();
1663 
1664             if ((serviceAloc != Mac::kShortAddrInvalid) && (Mle::ServiceIdFromAloc(serviceAloc) == serviceId))
1665             {
1666                 break;
1667             }
1668         }
1669 
1670         if (i >= serviceAlocsLength)
1671         {
1672             // Service Aloc is not there, but it should be. Lets add it into first empty space
1673             for (i = 0; i < serviceAlocsLength; i++)
1674             {
1675                 serviceAloc = mServiceAlocs[i].GetAddress().GetIid().GetLocator();
1676 
1677                 if (serviceAloc == Mac::kShortAddrInvalid)
1678                 {
1679                     SuccessOrExit(GetServiceAloc(serviceId, mServiceAlocs[i].GetAddress()));
1680                     Get<ThreadNetif>().AddUnicastAddress(mServiceAlocs[i]);
1681                     break;
1682                 }
1683             }
1684         }
1685     }
1686 
1687 exit:
1688     return;
1689 }
1690 #endif
1691 
HandleAttachTimer(Timer & aTimer)1692 void Mle::HandleAttachTimer(Timer &aTimer)
1693 {
1694     aTimer.Get<Mle>().HandleAttachTimer();
1695 }
1696 
HandleAttachTimer(void)1697 void Mle::HandleAttachTimer(void)
1698 {
1699     uint32_t delay          = 0;
1700     bool     shouldAnnounce = true;
1701 
1702     if (mAttachState == kAttachStateParentRequestRouter || mAttachState == kAttachStateParentRequestReed ||
1703         (mAttachState == kAttachStateAnnounce && !HasMoreChannelsToAnnouce()))
1704     {
1705         uint8_t linkQuality;
1706 
1707         linkQuality = mParentCandidate.GetLinkInfo().GetLinkQuality();
1708 
1709         if (linkQuality > mParentCandidate.GetLinkQualityOut())
1710         {
1711             linkQuality = mParentCandidate.GetLinkQualityOut();
1712         }
1713 
1714         // If already attached, accept the parent candidate if
1715         // we are trying to attach to a better partition or if a
1716         // Parent Response was also received from the current parent
1717         // to which the device is attached. This ensures that the
1718         // new parent candidate is compared with the current parent
1719         // and that it is indeed preferred over the current one.
1720         // If we are in kAttachStateParentRequestRouter and cannot
1721         // find a parent with best link quality(3), we will keep
1722         // the candidate and forward to REED stage to find a better
1723         // parent.
1724 
1725         if ((linkQuality == 3 || mAttachState != kAttachStateParentRequestRouter) &&
1726             mParentCandidate.IsStateParentResponse() &&
1727             (!IsChild() || mReceivedResponseFromParent || mParentRequestMode == kAttachBetter) &&
1728             SendChildIdRequest() == kErrorNone)
1729         {
1730             SetAttachState(kAttachStateChildIdRequest);
1731             delay = kParentRequestReedTimeout;
1732             ExitNow();
1733         }
1734     }
1735 
1736     switch (mAttachState)
1737     {
1738     case kAttachStateIdle:
1739         mAttachCounter = 0;
1740         break;
1741 
1742     case kAttachStateProcessAnnounce:
1743         ProcessAnnounce();
1744         break;
1745 
1746     case kAttachStateStart:
1747         if (mAttachCounter > 0)
1748         {
1749             otLogNoteMle("Attempt to attach - attempt %d, %s %s", mAttachCounter,
1750                          AttachModeToString(mParentRequestMode), ReattachStateToString(mReattachState));
1751         }
1752         else
1753         {
1754             otLogNoteMle("Attempt to attach - %s %s", AttachModeToString(mParentRequestMode),
1755                          ReattachStateToString(mReattachState));
1756         }
1757 
1758         SetAttachState(kAttachStateParentRequestRouter);
1759         mParentCandidate.SetState(Neighbor::kStateInvalid);
1760         mReceivedResponseFromParent = false;
1761         Get<MeshForwarder>().SetRxOnWhenIdle(true);
1762 
1763         // initial MLE Parent Request has both E and R flags set in Scan Mask TLV
1764         // during reattach when losing connectivity.
1765         if (mParentRequestMode == kAttachSame1 || mParentRequestMode == kAttachSame2)
1766         {
1767             IgnoreError(SendParentRequest(kParentRequestTypeRoutersAndReeds));
1768             delay = kParentRequestReedTimeout;
1769         }
1770         // initial MLE Parent Request has only R flag set in Scan Mask TLV for
1771         // during initial attach or downgrade process
1772         else
1773         {
1774             IgnoreError(SendParentRequest(kParentRequestTypeRouters));
1775             delay = kParentRequestRouterTimeout;
1776         }
1777 
1778         break;
1779 
1780     case kAttachStateParentRequestRouter:
1781         SetAttachState(kAttachStateParentRequestReed);
1782         IgnoreError(SendParentRequest(kParentRequestTypeRoutersAndReeds));
1783         delay = kParentRequestReedTimeout;
1784         break;
1785 
1786     case kAttachStateParentRequestReed:
1787         shouldAnnounce = PrepareAnnounceState();
1788 
1789         if (shouldAnnounce)
1790         {
1791             // We send an extra "Parent Request" as we switch to
1792             // `kAttachStateAnnounce` and start sending Announce on
1793             // all channels. This gives an additional chance to find
1794             // a parent during this phase. Note that we can stay in
1795             // `kAttachStateAnnounce` for multiple iterations, each
1796             // time sending an Announce on a different channel
1797             // (with `mAnnounceDelay` wait between them).
1798 
1799             SetAttachState(kAttachStateAnnounce);
1800             IgnoreError(SendParentRequest(kParentRequestTypeRoutersAndReeds));
1801             mAnnounceChannel = Mac::ChannelMask::kChannelIteratorFirst;
1802             delay            = mAnnounceDelay;
1803             break;
1804         }
1805 
1806         OT_FALL_THROUGH;
1807 
1808     case kAttachStateAnnounce:
1809         if (shouldAnnounce && (GetNextAnnouceChannel(mAnnounceChannel) == kErrorNone))
1810         {
1811             SendAnnounce(mAnnounceChannel, /* aOrphanAnnounce */ true);
1812             delay = mAnnounceDelay;
1813             break;
1814         }
1815 
1816         OT_FALL_THROUGH;
1817 
1818     case kAttachStateChildIdRequest:
1819         SetAttachState(kAttachStateIdle);
1820         mParentCandidate.Clear();
1821         delay = Reattach();
1822         break;
1823     }
1824 
1825 exit:
1826 
1827     if (delay != 0)
1828     {
1829         mAttachTimer.Start(delay);
1830     }
1831 }
1832 
PrepareAnnounceState(void)1833 bool Mle::PrepareAnnounceState(void)
1834 {
1835     bool             shouldAnnounce = false;
1836     Mac::ChannelMask channelMask;
1837 
1838     VerifyOrExit(!IsChild() && (mReattachState == kReattachStop) &&
1839                  (Get<MeshCoP::ActiveDataset>().IsPartiallyComplete() || !IsFullThreadDevice()));
1840 
1841     if (Get<MeshCoP::ActiveDataset>().GetChannelMask(channelMask) != kErrorNone)
1842     {
1843         channelMask = Get<Mac::Mac>().GetSupportedChannelMask();
1844     }
1845 
1846     mAnnounceDelay = kAnnounceTimeout / (channelMask.GetNumberOfChannels() + 1);
1847 
1848     if (mAnnounceDelay < kMinAnnounceDelay)
1849     {
1850         mAnnounceDelay = kMinAnnounceDelay;
1851     }
1852 
1853     shouldAnnounce = true;
1854 
1855 exit:
1856     return shouldAnnounce;
1857 }
1858 
Reattach(void)1859 uint32_t Mle::Reattach(void)
1860 {
1861     uint32_t delay = 0;
1862 
1863     if (mReattachState == kReattachActive)
1864     {
1865         if (Get<MeshCoP::PendingDataset>().Restore() == kErrorNone)
1866         {
1867             IgnoreError(Get<MeshCoP::PendingDataset>().ApplyConfiguration());
1868             mReattachState = kReattachPending;
1869             SetAttachState(kAttachStateStart);
1870             delay = 1 + Random::NonCrypto::GetUint32InRange(0, kAttachStartJitter);
1871         }
1872         else
1873         {
1874             mReattachState = kReattachStop;
1875         }
1876     }
1877     else if (mReattachState == kReattachPending)
1878     {
1879         mReattachState = kReattachStop;
1880         IgnoreError(Get<MeshCoP::ActiveDataset>().Restore());
1881     }
1882 
1883     VerifyOrExit(mReattachState == kReattachStop);
1884 
1885     switch (mParentRequestMode)
1886     {
1887     case kAttachAny:
1888         if (!IsChild())
1889         {
1890             if (mAlternatePanId != Mac::kPanIdBroadcast)
1891             {
1892                 IgnoreError(Get<Mac::Mac>().SetPanChannel(mAlternateChannel));
1893                 Get<Mac::Mac>().SetPanId(mAlternatePanId);
1894                 mAlternatePanId = Mac::kPanIdBroadcast;
1895                 IgnoreError(BecomeDetached());
1896             }
1897 #if OPENTHREAD_FTD
1898             else if (IsFullThreadDevice() && Get<MleRouter>().BecomeLeader() == kErrorNone)
1899             {
1900                 // do nothing
1901             }
1902 #endif
1903             else
1904             {
1905                 IgnoreError(BecomeDetached());
1906             }
1907         }
1908         else if (!IsRxOnWhenIdle())
1909         {
1910             // return to sleepy operation
1911             Get<DataPollSender>().SetAttachMode(false);
1912             Get<MeshForwarder>().SetRxOnWhenIdle(false);
1913         }
1914 
1915         break;
1916 
1917     case kAttachSame1:
1918         IgnoreError(BecomeChild(kAttachSame2));
1919         break;
1920 
1921     case kAttachSame2:
1922     case kAttachSameDowngrade:
1923         IgnoreError(BecomeChild(kAttachAny));
1924         break;
1925 
1926     case kAttachBetter:
1927         break;
1928     }
1929 
1930 exit:
1931     return delay;
1932 }
1933 
HandleDelayedResponseTimer(Timer & aTimer)1934 void Mle::HandleDelayedResponseTimer(Timer &aTimer)
1935 {
1936     aTimer.Get<Mle>().HandleDelayedResponseTimer();
1937 }
1938 
HandleDelayedResponseTimer(void)1939 void Mle::HandleDelayedResponseTimer(void)
1940 {
1941     DelayedResponseMetadata metadata;
1942     TimeMilli               now          = TimerMilli::GetNow();
1943     TimeMilli               nextSendTime = now.GetDistantFuture();
1944     Message *               message;
1945     Message *               nextMessage;
1946 
1947     for (message = mDelayedResponses.GetHead(); message != nullptr; message = nextMessage)
1948     {
1949         nextMessage = message->GetNext();
1950 
1951         metadata.ReadFrom(*message);
1952 
1953         if (now < metadata.mSendTime)
1954         {
1955             if (nextSendTime > metadata.mSendTime)
1956             {
1957                 nextSendTime = metadata.mSendTime;
1958             }
1959         }
1960         else
1961         {
1962             mDelayedResponses.Dequeue(*message);
1963             metadata.RemoveFrom(*message);
1964 
1965             if (SendMessage(*message, metadata.mDestination) == kErrorNone)
1966             {
1967                 Log(kMessageSend, kTypeGenericDelayed, metadata.mDestination);
1968 
1969                 // Here enters fast poll mode, as for Rx-Off-when-idle device, the enqueued msg should
1970                 // be Mle Data Request.
1971                 // Note: Finer-grade check (e.g. message subtype) might be required when deciding whether
1972                 // or not enters fast poll mode fast poll mode if there are other type of delayed message
1973                 // for Rx-Off-when-idle device.
1974                 if (!IsRxOnWhenIdle())
1975                 {
1976                     Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
1977                 }
1978             }
1979             else
1980             {
1981                 message->Free();
1982             }
1983         }
1984     }
1985 
1986     if (nextSendTime < now.GetDistantFuture())
1987     {
1988         mDelayedResponseTimer.FireAt(nextSendTime);
1989     }
1990 }
1991 
RemoveDelayedDataResponseMessage(void)1992 void Mle::RemoveDelayedDataResponseMessage(void)
1993 {
1994     Message *               message = mDelayedResponses.GetHead();
1995     DelayedResponseMetadata metadata;
1996 
1997     while (message != nullptr)
1998     {
1999         metadata.ReadFrom(*message);
2000 
2001         if (message->GetSubType() == Message::kSubTypeMleDataResponse)
2002         {
2003             mDelayedResponses.DequeueAndFree(*message);
2004             Log(kMessageRemoveDelayed, kTypeDataResponse, metadata.mDestination);
2005 
2006             // no more than one multicast MLE Data Response in Delayed Message Queue.
2007             break;
2008         }
2009 
2010         message = message->GetNext();
2011     }
2012 }
2013 
SendParentRequest(ParentRequestType aType)2014 Error Mle::SendParentRequest(ParentRequestType aType)
2015 {
2016     Error        error = kErrorNone;
2017     Message *    message;
2018     uint8_t      scanMask = 0;
2019     Ip6::Address destination;
2020 
2021     mParentRequestChallenge.GenerateRandom();
2022 
2023     switch (aType)
2024     {
2025     case kParentRequestTypeRouters:
2026         scanMask = ScanMaskTlv::kRouterFlag;
2027         break;
2028 
2029     case kParentRequestTypeRoutersAndReeds:
2030         scanMask = ScanMaskTlv::kRouterFlag | ScanMaskTlv::kEndDeviceFlag;
2031         break;
2032     }
2033 
2034     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2035     SuccessOrExit(error = AppendHeader(*message, kCommandParentRequest));
2036     SuccessOrExit(error = AppendMode(*message, mDeviceMode));
2037     SuccessOrExit(error = AppendChallenge(*message, mParentRequestChallenge));
2038     SuccessOrExit(error = AppendScanMask(*message, scanMask));
2039     SuccessOrExit(error = AppendVersion(*message));
2040 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2041     SuccessOrExit(error = AppendTimeRequest(*message));
2042 #endif
2043 
2044     destination.SetToLinkLocalAllRoutersMulticast();
2045     SuccessOrExit(error = SendMessage(*message, destination));
2046 
2047     switch (aType)
2048     {
2049     case kParentRequestTypeRouters:
2050         Log(kMessageSend, kTypeParentRequestToRouters, destination);
2051         break;
2052 
2053     case kParentRequestTypeRoutersAndReeds:
2054         Log(kMessageSend, kTypeParentRequestToRoutersReeds, destination);
2055         break;
2056     }
2057 
2058 exit:
2059     FreeMessageOnError(message, error);
2060     return error;
2061 }
2062 
RequestShorterChildIdRequest(void)2063 void Mle::RequestShorterChildIdRequest(void)
2064 {
2065     if (mAttachState == kAttachStateChildIdRequest)
2066     {
2067         mAddressRegistrationMode = kAppendMeshLocalOnly;
2068         IgnoreError(SendChildIdRequest());
2069     }
2070 }
2071 
SendChildIdRequest(void)2072 Error Mle::SendChildIdRequest(void)
2073 {
2074     Error        error   = kErrorNone;
2075     uint8_t      tlvs[]  = {Tlv::kAddress16, Tlv::kNetworkData, Tlv::kRoute};
2076     uint8_t      tlvsLen = sizeof(tlvs);
2077     Message *    message = nullptr;
2078     Ip6::Address destination;
2079 
2080     if (mParent.GetExtAddress() == mParentCandidate.GetExtAddress())
2081     {
2082         if (IsChild())
2083         {
2084             otLogInfoMle("Already attached to candidate parent");
2085             ExitNow(error = kErrorAlready);
2086         }
2087         else
2088         {
2089             // Invalidate stale parent state.
2090             //
2091             // Parent state is not normally invalidated after becoming a Router/Leader (see #1875).  When trying to
2092             // attach to a better partition, invalidating old parent state (especially when in kStateRestored) ensures
2093             // that FindNeighbor() returns mParentCandidate when processing the Child ID Response.
2094             mParent.SetState(Neighbor::kStateInvalid);
2095         }
2096     }
2097 
2098     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2099     message->SetSubType(Message::kSubTypeMleChildIdRequest);
2100     SuccessOrExit(error = AppendHeader(*message, kCommandChildIdRequest));
2101     SuccessOrExit(error = AppendResponse(*message, mParentCandidateChallenge));
2102     SuccessOrExit(error = AppendLinkFrameCounter(*message));
2103     SuccessOrExit(error = AppendMleFrameCounter(*message));
2104     SuccessOrExit(error = AppendMode(*message, mDeviceMode));
2105     SuccessOrExit(error = AppendTimeout(*message, mTimeout));
2106     SuccessOrExit(error = AppendVersion(*message));
2107 
2108     if (!IsFullThreadDevice())
2109     {
2110         SuccessOrExit(error = AppendAddressRegistration(*message, mAddressRegistrationMode));
2111 
2112         // no need to request the last Route64 TLV for MTD
2113         tlvsLen -= 1;
2114     }
2115 
2116     SuccessOrExit(error = AppendTlvRequest(*message, tlvs, tlvsLen));
2117     SuccessOrExit(error = AppendActiveTimestamp(*message));
2118     SuccessOrExit(error = AppendPendingTimestamp(*message));
2119 
2120     mParentCandidate.SetState(Neighbor::kStateValid);
2121 
2122     destination.SetToLinkLocalAddress(mParentCandidate.GetExtAddress());
2123     SuccessOrExit(error = SendMessage(*message, destination));
2124 
2125     Log(kMessageSend,
2126         (mAddressRegistrationMode == kAppendMeshLocalOnly) ? kTypeChildIdRequestShort : kTypeChildIdRequest,
2127         destination);
2128 
2129     if (!IsRxOnWhenIdle())
2130     {
2131         Get<DataPollSender>().SetAttachMode(true);
2132         Get<MeshForwarder>().SetRxOnWhenIdle(false);
2133     }
2134 
2135 exit:
2136     FreeMessageOnError(message, error);
2137     return error;
2138 }
2139 
SendDataRequest(const Ip6::Address & aDestination,const uint8_t * aTlvs,uint8_t aTlvsLength,uint16_t aDelay,const uint8_t * aExtraTlvs,uint8_t aExtraTlvsLength)2140 Error Mle::SendDataRequest(const Ip6::Address &aDestination,
2141                            const uint8_t *     aTlvs,
2142                            uint8_t             aTlvsLength,
2143                            uint16_t            aDelay,
2144                            const uint8_t *     aExtraTlvs,
2145                            uint8_t             aExtraTlvsLength)
2146 {
2147     OT_UNUSED_VARIABLE(aExtraTlvs);
2148     OT_UNUSED_VARIABLE(aExtraTlvsLength);
2149 
2150     Error    error = kErrorNone;
2151     Message *message;
2152 
2153     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2154     SuccessOrExit(error = AppendHeader(*message, kCommandDataRequest));
2155     SuccessOrExit(error = AppendTlvRequest(*message, aTlvs, aTlvsLength));
2156     SuccessOrExit(error = AppendActiveTimestamp(*message));
2157     SuccessOrExit(error = AppendPendingTimestamp(*message));
2158 
2159     if (aExtraTlvs != nullptr && aExtraTlvsLength > 0)
2160     {
2161         SuccessOrExit(error = message->AppendBytes(aExtraTlvs, aExtraTlvsLength));
2162     }
2163 
2164     if (aDelay)
2165     {
2166         SuccessOrExit(error = AddDelayedResponse(*message, aDestination, aDelay));
2167         Log(kMessageDelay, kTypeDataRequest, aDestination);
2168     }
2169     else
2170     {
2171         SuccessOrExit(error = SendMessage(*message, aDestination));
2172         Log(kMessageSend, kTypeDataRequest, aDestination);
2173 
2174         if (!IsRxOnWhenIdle())
2175         {
2176             Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
2177         }
2178     }
2179 
2180 exit:
2181     FreeMessageOnError(message, error);
2182 
2183     if (IsChild() && !IsRxOnWhenIdle())
2184     {
2185         mDataRequestState = kDataRequestActive;
2186 
2187         if (mChildUpdateRequestState == kChildUpdateRequestNone)
2188         {
2189             ScheduleMessageTransmissionTimer();
2190         }
2191     }
2192 
2193     return error;
2194 }
2195 
ScheduleMessageTransmissionTimer(void)2196 void Mle::ScheduleMessageTransmissionTimer(void)
2197 {
2198     uint32_t interval = 0;
2199 
2200     switch (mChildUpdateRequestState)
2201     {
2202     case kChildUpdateRequestNone:
2203         break;
2204 
2205     case kChildUpdateRequestPending:
2206         ExitNow(interval = kChildUpdateRequestPendingDelay);
2207 
2208     case kChildUpdateRequestActive:
2209 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
2210         // CSL transmitter may respond in next CSL cycle.
2211         // This condition IsCslCapable() && !IsRxOnWhenIdle() is used instead of
2212         // IsCslEnabled because during transitions SSED -> MED and MED -> SSED
2213         // there is a delay in synchronisation of IsRxOnWhenIdle residing in MAC
2214         // and in MLE, which causes below datapoll interval to be calculated incorrectly.
2215         if (Get<Mac::Mac>().IsCslCapable() && !IsRxOnWhenIdle())
2216         {
2217             ExitNow(interval = Get<Mac::Mac>().GetCslPeriod() * kUsPerTenSymbols / 1000 +
2218                                static_cast<uint32_t>(kUnicastRetransmissionDelay));
2219         }
2220         else
2221 #endif
2222         {
2223             ExitNow(interval = kUnicastRetransmissionDelay);
2224         }
2225     }
2226 
2227     switch (mDataRequestState)
2228     {
2229     case kDataRequestNone:
2230         break;
2231 
2232     case kDataRequestActive:
2233         ExitNow(interval = kUnicastRetransmissionDelay);
2234     }
2235 
2236     if (IsChild() && IsRxOnWhenIdle())
2237     {
2238         interval =
2239             Time::SecToMsec(mTimeout) - static_cast<uint32_t>(kUnicastRetransmissionDelay) * kMaxChildKeepAliveAttempts;
2240     }
2241 
2242 exit:
2243     if (interval != 0)
2244     {
2245         mMessageTransmissionTimer.Start(interval);
2246     }
2247     else
2248     {
2249         mMessageTransmissionTimer.Stop();
2250     }
2251 }
2252 
HandleMessageTransmissionTimer(Timer & aTimer)2253 void Mle::HandleMessageTransmissionTimer(Timer &aTimer)
2254 {
2255     aTimer.Get<Mle>().HandleMessageTransmissionTimer();
2256 }
2257 
HandleMessageTransmissionTimer(void)2258 void Mle::HandleMessageTransmissionTimer(void)
2259 {
2260     // The `mMessageTransmissionTimer` is used for:
2261     //
2262     //  - Delaying kEvent notification triggered "Child Update Request" transmission (to allow aggregation),
2263     //  - Retransmission of "Child Update Request",
2264     //  - Retransmission of "Data Request" on a child,
2265     //  - Sending periodic keep-alive "Child Update Request" messages on a non-sleepy (rx-on) child.
2266 
2267     switch (mChildUpdateRequestState)
2268     {
2269     case kChildUpdateRequestNone:
2270         if (mDataRequestState == kDataRequestActive)
2271         {
2272             static const uint8_t tlvs[] = {Tlv::kNetworkData};
2273             Ip6::Address         destination;
2274 
2275             VerifyOrExit(mDataRequestAttempts < kMaxChildKeepAliveAttempts, IgnoreError(BecomeDetached()));
2276 
2277             destination.SetToLinkLocalAddress(mParent.GetExtAddress());
2278 
2279             if (SendDataRequest(destination, tlvs, sizeof(tlvs), 0) == kErrorNone)
2280             {
2281                 mDataRequestAttempts++;
2282             }
2283 
2284             ExitNow();
2285         }
2286 
2287         // Keep-alive "Child Update Request" only on a non-sleepy child
2288         VerifyOrExit(IsChild() && IsRxOnWhenIdle());
2289         break;
2290 
2291     case kChildUpdateRequestPending:
2292         if (Get<Notifier>().IsPending())
2293         {
2294             // Here intentionally delay another kChildUpdateRequestPendingDelay
2295             // cycle to ensure we only send a Child Update Request after we
2296             // know there are no more pending changes.
2297             ScheduleMessageTransmissionTimer();
2298             ExitNow();
2299         }
2300 
2301         mChildUpdateAttempts = 0;
2302         break;
2303 
2304     case kChildUpdateRequestActive:
2305         break;
2306     }
2307 
2308     VerifyOrExit(mChildUpdateAttempts < kMaxChildKeepAliveAttempts, IgnoreError(BecomeDetached()));
2309 
2310     if (SendChildUpdateRequest() == kErrorNone)
2311     {
2312         mChildUpdateAttempts++;
2313     }
2314 
2315 exit:
2316     return;
2317 }
2318 
SendChildUpdateRequest(void)2319 Error Mle::SendChildUpdateRequest(void)
2320 {
2321     Error                   error = kErrorNone;
2322     Ip6::Address            destination;
2323     Message *               message = nullptr;
2324     AddressRegistrationMode mode    = kAppendAllAddresses;
2325 
2326     if (!mParent.IsStateValidOrRestoring())
2327     {
2328         otLogWarnMle("No valid parent when sending Child Update Request");
2329         IgnoreError(BecomeDetached());
2330         ExitNow();
2331     }
2332 
2333     mChildUpdateRequestState = kChildUpdateRequestActive;
2334     ScheduleMessageTransmissionTimer();
2335 
2336     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2337     message->SetSubType(Message::kSubTypeMleChildUpdateRequest);
2338     SuccessOrExit(error = AppendHeader(*message, kCommandChildUpdateRequest));
2339     SuccessOrExit(error = AppendMode(*message, mDeviceMode));
2340 
2341     switch (mRole)
2342     {
2343     case kRoleDetached:
2344         mParentRequestChallenge.GenerateRandom();
2345         SuccessOrExit(error = AppendChallenge(*message, mParentRequestChallenge));
2346         mode = kAppendMeshLocalOnly;
2347         break;
2348 
2349     case kRoleChild:
2350         SuccessOrExit(error = AppendSourceAddress(*message));
2351         SuccessOrExit(error = AppendLeaderData(*message));
2352         SuccessOrExit(error = AppendTimeout(*message, mTimeout));
2353 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
2354         if (Get<Mac::Mac>().IsCslEnabled())
2355         {
2356             SuccessOrExit(error = AppendCslChannel(*message));
2357             SuccessOrExit(error = AppendCslTimeout(*message));
2358         }
2359 #endif
2360         break;
2361 
2362     case kRoleDisabled:
2363     case kRoleRouter:
2364     case kRoleLeader:
2365         OT_ASSERT(false);
2366         OT_UNREACHABLE_CODE(break);
2367     }
2368 
2369     if (!IsFullThreadDevice())
2370     {
2371         SuccessOrExit(error = AppendAddressRegistration(*message, mode));
2372     }
2373 
2374     destination.SetToLinkLocalAddress(mParent.GetExtAddress());
2375     SuccessOrExit(error = SendMessage(*message, destination));
2376 
2377     Log(kMessageSend, kTypeChildUpdateRequestOfParent, destination);
2378 
2379     if (!IsRxOnWhenIdle())
2380     {
2381         Get<MeshForwarder>().SetRxOnWhenIdle(false);
2382 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
2383         Get<DataPollSender>().SetAttachMode(!Get<Mac::Mac>().IsCslEnabled());
2384 #else
2385         Get<DataPollSender>().SetAttachMode(true);
2386 #endif
2387     }
2388     else
2389     {
2390         Get<MeshForwarder>().SetRxOnWhenIdle(true);
2391     }
2392 
2393 exit:
2394     FreeMessageOnError(message, error);
2395     return error;
2396 }
2397 
SendChildUpdateResponse(const uint8_t * aTlvs,uint8_t aNumTlvs,const Challenge & aChallenge)2398 Error Mle::SendChildUpdateResponse(const uint8_t *aTlvs, uint8_t aNumTlvs, const Challenge &aChallenge)
2399 {
2400     Error        error = kErrorNone;
2401     Ip6::Address destination;
2402     Message *    message;
2403     bool         checkAddress = false;
2404 
2405     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2406     SuccessOrExit(error = AppendHeader(*message, kCommandChildUpdateResponse));
2407     SuccessOrExit(error = AppendSourceAddress(*message));
2408     SuccessOrExit(error = AppendLeaderData(*message));
2409 
2410     for (int i = 0; i < aNumTlvs; i++)
2411     {
2412         switch (aTlvs[i])
2413         {
2414         case Tlv::kTimeout:
2415             SuccessOrExit(error = AppendTimeout(*message, mTimeout));
2416             break;
2417 
2418         case Tlv::kStatus:
2419             SuccessOrExit(error = AppendStatus(*message, StatusTlv::kError));
2420             break;
2421 
2422         case Tlv::kAddressRegistration:
2423             if (!IsFullThreadDevice())
2424             {
2425                 // We only register the mesh-local address in the "Child
2426                 // Update Response" message and if there are additional
2427                 // addresses to register we follow up with a "Child Update
2428                 // Request".
2429 
2430                 SuccessOrExit(error = AppendAddressRegistration(*message, kAppendMeshLocalOnly));
2431                 checkAddress = true;
2432             }
2433 
2434             break;
2435 
2436         case Tlv::kResponse:
2437             SuccessOrExit(error = AppendResponse(*message, aChallenge));
2438             break;
2439 
2440         case Tlv::kLinkFrameCounter:
2441             SuccessOrExit(error = AppendLinkFrameCounter(*message));
2442             break;
2443 
2444         case Tlv::kMleFrameCounter:
2445             SuccessOrExit(error = AppendMleFrameCounter(*message));
2446             break;
2447         }
2448     }
2449 
2450     destination.SetToLinkLocalAddress(mParent.GetExtAddress());
2451     SuccessOrExit(error = SendMessage(*message, destination));
2452 
2453     Log(kMessageSend, kTypeChildUpdateResponseOfParent, destination);
2454 
2455     if (checkAddress && HasUnregisteredAddress())
2456     {
2457         IgnoreError(SendChildUpdateRequest());
2458     }
2459 
2460 exit:
2461     FreeMessageOnError(message, error);
2462     return error;
2463 }
2464 
SendAnnounce(uint8_t aChannel,bool aOrphanAnnounce)2465 void Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce)
2466 {
2467     Ip6::Address destination;
2468 
2469     destination.SetToLinkLocalAllNodesMulticast();
2470 
2471     SendAnnounce(aChannel, aOrphanAnnounce, destination);
2472 }
2473 
SendAnnounce(uint8_t aChannel,bool aOrphanAnnounce,const Ip6::Address & aDestination)2474 void Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination)
2475 {
2476     Error              error = kErrorNone;
2477     ChannelTlv         channel;
2478     ActiveTimestampTlv activeTimestamp;
2479     Message *          message = nullptr;
2480 
2481     VerifyOrExit(Get<Mac::Mac>().GetSupportedChannelMask().ContainsChannel(aChannel), error = kErrorInvalidArgs);
2482     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2483     message->SetLinkSecurityEnabled(true);
2484     message->SetSubType(Message::kSubTypeMleAnnounce);
2485     message->SetChannel(aChannel);
2486     SuccessOrExit(error = AppendHeader(*message, kCommandAnnounce));
2487 
2488     channel.Init();
2489     channel.SetChannel(Get<Mac::Mac>().GetPanChannel());
2490     SuccessOrExit(error = channel.AppendTo(*message));
2491 
2492     if (aOrphanAnnounce)
2493     {
2494         activeTimestamp.Init();
2495         activeTimestamp.SetSeconds(0);
2496         activeTimestamp.SetTicks(0);
2497         activeTimestamp.SetAuthoritative(true);
2498 
2499         SuccessOrExit(error = activeTimestamp.AppendTo(*message));
2500     }
2501     else
2502     {
2503         SuccessOrExit(error = AppendActiveTimestamp(*message));
2504     }
2505 
2506     SuccessOrExit(error = Tlv::Append<PanIdTlv>(*message, Get<Mac::Mac>().GetPanId()));
2507 
2508     SuccessOrExit(error = SendMessage(*message, aDestination));
2509 
2510     otLogInfoMle("Send Announce on channel %d", aChannel);
2511 
2512 exit:
2513     FreeMessageOnError(message, error);
2514 }
2515 
GetNextAnnouceChannel(uint8_t & aChannel) const2516 Error Mle::GetNextAnnouceChannel(uint8_t &aChannel) const
2517 {
2518     // This method gets the next channel to send announce on after
2519     // `aChannel`. Returns `kErrorNotFound` if no more channel in the
2520     // channel mask after `aChannel`.
2521 
2522     Mac::ChannelMask channelMask;
2523 
2524     if (Get<MeshCoP::ActiveDataset>().GetChannelMask(channelMask) != kErrorNone)
2525     {
2526         channelMask = Get<Mac::Mac>().GetSupportedChannelMask();
2527     }
2528 
2529     return channelMask.GetNextChannel(aChannel);
2530 }
2531 
HasMoreChannelsToAnnouce(void) const2532 bool Mle::HasMoreChannelsToAnnouce(void) const
2533 {
2534     uint8_t channel = mAnnounceChannel;
2535 
2536     return GetNextAnnouceChannel(channel) == kErrorNone;
2537 }
2538 
2539 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
SendLinkMetricsManagementResponse(const Ip6::Address & aDestination,LinkMetrics::Status aStatus)2540 Error Mle::SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, LinkMetrics::Status aStatus)
2541 {
2542     Error    error = kErrorNone;
2543     Message *message;
2544     Tlv      tlv;
2545     ot::Tlv  statusSubTlv;
2546 
2547     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2548     SuccessOrExit(error = AppendHeader(*message, kCommandLinkMetricsManagementResponse));
2549 
2550     tlv.SetType(Tlv::kLinkMetricsManagement);
2551     statusSubTlv.SetType(LinkMetrics::SubTlv::kStatus);
2552     statusSubTlv.SetLength(sizeof(aStatus));
2553     tlv.SetLength(statusSubTlv.GetSize());
2554 
2555     SuccessOrExit(error = message->Append(tlv));
2556     SuccessOrExit(error = message->Append(statusSubTlv));
2557     SuccessOrExit(error = message->Append(aStatus));
2558 
2559     SuccessOrExit(error = SendMessage(*message, aDestination));
2560 
2561 exit:
2562     FreeMessageOnError(message, error);
2563     return error;
2564 }
2565 #endif
2566 
2567 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
SendLinkProbe(const Ip6::Address & aDestination,uint8_t aSeriesId,uint8_t * aBuf,uint8_t aLength)2568 Error Mle::SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t *aBuf, uint8_t aLength)
2569 {
2570     Error    error = kErrorNone;
2571     Message *message;
2572     Tlv      tlv;
2573 
2574     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
2575     SuccessOrExit(error = AppendHeader(*message, kCommandLinkProbe));
2576 
2577     tlv.SetType(Tlv::kLinkProbe);
2578     tlv.SetLength(sizeof(aSeriesId) + aLength);
2579 
2580     SuccessOrExit(error = message->Append(tlv));
2581     SuccessOrExit(error = message->Append(aSeriesId));
2582     SuccessOrExit(error = message->AppendBytes(aBuf, aLength));
2583 
2584     SuccessOrExit(error = SendMessage(*message, aDestination));
2585 
2586 exit:
2587     FreeMessageOnError(message, error);
2588     return error;
2589 }
2590 #endif
2591 
SendMessage(Message & aMessage,const Ip6::Address & aDestination)2592 Error Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination)
2593 {
2594     Error            error = kErrorNone;
2595     Header           header;
2596     uint32_t         keySequence;
2597     uint8_t          nonce[Crypto::AesCcm::kNonceSize];
2598     uint8_t          tag[kMleSecurityTagSize];
2599     Crypto::AesCcm   aesCcm;
2600     uint8_t          buf[64];
2601     uint16_t         length;
2602     Ip6::MessageInfo messageInfo;
2603 
2604     IgnoreError(aMessage.Read(0, header));
2605 
2606     if (header.GetSecuritySuite() == Header::k154Security)
2607     {
2608         header.SetFrameCounter(Get<KeyManager>().GetMleFrameCounter());
2609 
2610         keySequence = Get<KeyManager>().GetCurrentKeySequence();
2611         header.SetKeyId(keySequence);
2612 
2613         aMessage.WriteBytes(0, &header, header.GetLength());
2614 
2615         Crypto::AesCcm::GenerateNonce(Get<Mac::Mac>().GetExtAddress(), Get<KeyManager>().GetMleFrameCounter(),
2616                                       Mac::Frame::kSecEncMic32, nonce);
2617 
2618         aesCcm.SetKey(Get<KeyManager>().GetCurrentMleKey());
2619         aesCcm.Init(16 + 16 + header.GetHeaderLength(), aMessage.GetLength() - (header.GetLength() - 1), sizeof(tag),
2620                     nonce, sizeof(nonce));
2621 
2622         aesCcm.Header(&mLinkLocal64.GetAddress(), sizeof(mLinkLocal64.GetAddress()));
2623         aesCcm.Header(&aDestination, sizeof(aDestination));
2624         aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
2625 
2626         aMessage.SetOffset(header.GetLength() - 1);
2627 
2628         while (aMessage.GetOffset() < aMessage.GetLength())
2629         {
2630             length = aMessage.ReadBytes(aMessage.GetOffset(), buf, sizeof(buf));
2631             aesCcm.Payload(buf, buf, length, Crypto::AesCcm::kEncrypt);
2632             aMessage.WriteBytes(aMessage.GetOffset(), buf, length);
2633             aMessage.MoveOffset(length);
2634         }
2635 
2636         aesCcm.Finalize(tag);
2637         SuccessOrExit(error = aMessage.AppendBytes(tag, sizeof(tag)));
2638 
2639         Get<KeyManager>().IncrementMleFrameCounter();
2640     }
2641 
2642     messageInfo.SetPeerAddr(aDestination);
2643     messageInfo.SetSockAddr(mLinkLocal64.GetAddress());
2644     messageInfo.SetPeerPort(kUdpPort);
2645     messageInfo.SetHopLimit(kMleHopLimit);
2646 
2647     SuccessOrExit(error = mSocket.SendTo(aMessage, messageInfo));
2648 
2649 exit:
2650     return error;
2651 }
2652 
AddDelayedResponse(Message & aMessage,const Ip6::Address & aDestination,uint16_t aDelay)2653 Error Mle::AddDelayedResponse(Message &aMessage, const Ip6::Address &aDestination, uint16_t aDelay)
2654 {
2655     Error                   error = kErrorNone;
2656     DelayedResponseMetadata metadata;
2657 
2658     metadata.mSendTime    = TimerMilli::GetNow() + aDelay;
2659     metadata.mDestination = aDestination;
2660 
2661     SuccessOrExit(error = metadata.AppendTo(aMessage));
2662     mDelayedResponses.Enqueue(aMessage);
2663 
2664     mDelayedResponseTimer.FireAtIfEarlier(metadata.mSendTime);
2665 
2666 exit:
2667     return error;
2668 }
2669 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)2670 void Mle::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
2671 {
2672     static_cast<Mle *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
2673                                                    *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
2674 }
2675 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)2676 void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
2677 {
2678     Error           error = kErrorNone;
2679     Header          header;
2680     uint32_t        keySequence;
2681     const Key *     mleKey;
2682     uint32_t        frameCounter;
2683     uint8_t         messageTag[kMleSecurityTagSize];
2684     uint8_t         nonce[Crypto::AesCcm::kNonceSize];
2685     Mac::ExtAddress extAddr;
2686     Crypto::AesCcm  aesCcm;
2687     uint16_t        mleOffset;
2688     uint8_t         buf[64];
2689     uint16_t        length;
2690     uint8_t         tag[kMleSecurityTagSize];
2691     uint8_t         command;
2692     Neighbor *      neighbor;
2693 
2694     otLogDebgMle("Receive UDP message");
2695 
2696     VerifyOrExit(aMessageInfo.GetLinkInfo() != nullptr);
2697     VerifyOrExit(aMessageInfo.GetHopLimit() == kMleHopLimit, error = kErrorParse);
2698 
2699     length = aMessage.ReadBytes(aMessage.GetOffset(), &header, sizeof(header));
2700     VerifyOrExit(header.IsValid() && header.GetLength() <= length, error = kErrorParse);
2701 
2702     if (header.GetSecuritySuite() == Header::kNoSecurity)
2703     {
2704         aMessage.MoveOffset(header.GetLength());
2705 
2706         switch (header.GetCommand())
2707         {
2708 #if OPENTHREAD_FTD
2709         case kCommandDiscoveryRequest:
2710             Get<MleRouter>().HandleDiscoveryRequest(aMessage, aMessageInfo);
2711             break;
2712 #endif
2713 
2714         case kCommandDiscoveryResponse:
2715             Get<DiscoverScanner>().HandleDiscoveryResponse(aMessage, aMessageInfo);
2716             break;
2717 
2718         default:
2719             break;
2720         }
2721 
2722         ExitNow();
2723     }
2724 
2725     VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
2726     VerifyOrExit(header.GetSecuritySuite() == Header::k154Security, error = kErrorParse);
2727 
2728     keySequence = header.GetKeyId();
2729 
2730     if (keySequence == Get<KeyManager>().GetCurrentKeySequence())
2731     {
2732         mleKey = &Get<KeyManager>().GetCurrentMleKey();
2733     }
2734     else
2735     {
2736         mleKey = &Get<KeyManager>().GetTemporaryMleKey(keySequence);
2737     }
2738 
2739     VerifyOrExit(aMessage.GetOffset() + header.GetLength() + sizeof(messageTag) <= aMessage.GetLength(),
2740                  error = kErrorParse);
2741     aMessage.MoveOffset(header.GetLength() - 1);
2742 
2743     IgnoreError(aMessage.Read(aMessage.GetLength() - sizeof(messageTag), messageTag));
2744     SuccessOrExit(error = aMessage.SetLength(aMessage.GetLength() - sizeof(messageTag)));
2745 
2746     aMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2747 
2748     frameCounter = header.GetFrameCounter();
2749     Crypto::AesCcm::GenerateNonce(extAddr, frameCounter, Mac::Frame::kSecEncMic32, nonce);
2750 
2751     aesCcm.SetKey(*mleKey);
2752     aesCcm.Init(sizeof(aMessageInfo.GetPeerAddr()) + sizeof(aMessageInfo.GetSockAddr()) + header.GetHeaderLength(),
2753                 aMessage.GetLength() - aMessage.GetOffset(), sizeof(messageTag), nonce, sizeof(nonce));
2754 
2755     aesCcm.Header(&aMessageInfo.GetPeerAddr(), sizeof(aMessageInfo.GetPeerAddr()));
2756     aesCcm.Header(&aMessageInfo.GetSockAddr(), sizeof(aMessageInfo.GetSockAddr()));
2757     aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
2758 
2759     mleOffset = aMessage.GetOffset();
2760 
2761     while (aMessage.GetOffset() < aMessage.GetLength())
2762     {
2763         length = aMessage.ReadBytes(aMessage.GetOffset(), buf, sizeof(buf));
2764         aesCcm.Payload(buf, buf, length, Crypto::AesCcm::kDecrypt);
2765 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2766         aMessage.WriteBytes(aMessage.GetOffset(), buf, length);
2767 #endif
2768         aMessage.MoveOffset(length);
2769     }
2770 
2771     aesCcm.Finalize(tag);
2772 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2773     VerifyOrExit(memcmp(messageTag, tag, sizeof(tag)) == 0, error = kErrorSecurity);
2774 #endif
2775 
2776     if (keySequence > Get<KeyManager>().GetCurrentKeySequence())
2777     {
2778         Get<KeyManager>().SetCurrentKeySequence(keySequence);
2779     }
2780 
2781     aMessage.SetOffset(mleOffset);
2782 
2783     IgnoreError(aMessage.Read(aMessage.GetOffset(), command));
2784     aMessage.MoveOffset(sizeof(command));
2785 
2786     neighbor = (command == kCommandChildIdResponse) ? mNeighborTable.FindParent(extAddr)
2787                                                     : mNeighborTable.FindNeighbor(extAddr);
2788 
2789     if (neighbor != nullptr && neighbor->IsStateValid())
2790     {
2791         if (keySequence == neighbor->GetKeySequence())
2792         {
2793 #if OPENTHREAD_CONFIG_MULTI_RADIO
2794             // Only when counter is exactly one off, we allow it to be
2795             // used for updating radio link info (by `RadioSelector`)
2796             // before message is dropped as a duplicate. This handles
2797             // the common case where a broadcast MLE message (such as
2798             // Link Advertisement) is received over multiple radio
2799             // links.
2800 
2801             if ((frameCounter + 1) == neighbor->GetMleFrameCounter())
2802             {
2803                 OT_ASSERT(aMessage.IsRadioTypeSet());
2804                 Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* IsDuplicate */ true);
2805 
2806                 // We intentionally exit without setting the error to
2807                 // skip logging "Failed to process UDP" at the exit
2808                 // label. Note that in multi-radio mode, receiving
2809                 // duplicate MLE message (with one-off counter) would
2810                 // be common and ok for broadcast MLE messages (e.g.
2811                 // MLE Link Advertisements).
2812                 ExitNow();
2813             }
2814 #endif
2815             VerifyOrExit(frameCounter >= neighbor->GetMleFrameCounter(), error = kErrorDuplicated);
2816         }
2817         else
2818         {
2819             VerifyOrExit(keySequence > neighbor->GetKeySequence(), error = kErrorDuplicated);
2820             neighbor->SetKeySequence(keySequence);
2821             neighbor->GetLinkFrameCounters().Reset();
2822             neighbor->SetLinkAckFrameCounter(0);
2823         }
2824 
2825         neighbor->SetMleFrameCounter(frameCounter + 1);
2826     }
2827 
2828 #if OPENTHREAD_CONFIG_MULTI_RADIO
2829     if (neighbor != nullptr)
2830     {
2831         OT_ASSERT(aMessage.IsRadioTypeSet());
2832         Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* IsDuplicate */ false);
2833     }
2834 #endif
2835 
2836     switch (command)
2837     {
2838     case kCommandAdvertisement:
2839         HandleAdvertisement(aMessage, aMessageInfo, neighbor);
2840         break;
2841 
2842     case kCommandDataResponse:
2843         HandleDataResponse(aMessage, aMessageInfo, neighbor);
2844         break;
2845 
2846     case kCommandParentResponse:
2847         HandleParentResponse(aMessage, aMessageInfo, keySequence);
2848         break;
2849 
2850     case kCommandChildIdResponse:
2851         HandleChildIdResponse(aMessage, aMessageInfo, neighbor);
2852         break;
2853 
2854     case kCommandAnnounce:
2855         HandleAnnounce(aMessage, aMessageInfo);
2856         break;
2857 
2858     case kCommandChildUpdateRequest:
2859 #if OPENTHREAD_FTD
2860         if (IsRouterOrLeader())
2861         {
2862             Get<MleRouter>().HandleChildUpdateRequest(aMessage, aMessageInfo);
2863         }
2864         else
2865 #endif
2866         {
2867             HandleChildUpdateRequest(aMessage, aMessageInfo, neighbor);
2868         }
2869 
2870         break;
2871 
2872     case kCommandChildUpdateResponse:
2873 #if OPENTHREAD_FTD
2874         if (IsRouterOrLeader())
2875         {
2876             Get<MleRouter>().HandleChildUpdateResponse(aMessage, aMessageInfo, keySequence, neighbor);
2877         }
2878         else
2879 #endif
2880         {
2881             HandleChildUpdateResponse(aMessage, aMessageInfo, neighbor);
2882         }
2883 
2884         break;
2885 
2886 #if OPENTHREAD_FTD
2887     case kCommandLinkRequest:
2888         Get<MleRouter>().HandleLinkRequest(aMessage, aMessageInfo, neighbor);
2889         break;
2890 
2891     case kCommandLinkAccept:
2892         Get<MleRouter>().HandleLinkAccept(aMessage, aMessageInfo, keySequence, neighbor);
2893         break;
2894 
2895     case kCommandLinkAcceptAndRequest:
2896         Get<MleRouter>().HandleLinkAcceptAndRequest(aMessage, aMessageInfo, keySequence, neighbor);
2897         break;
2898 
2899     case kCommandDataRequest:
2900         Get<MleRouter>().HandleDataRequest(aMessage, aMessageInfo, neighbor);
2901         break;
2902 
2903     case kCommandParentRequest:
2904         Get<MleRouter>().HandleParentRequest(aMessage, aMessageInfo);
2905         break;
2906 
2907     case kCommandChildIdRequest:
2908         Get<MleRouter>().HandleChildIdRequest(aMessage, aMessageInfo, keySequence);
2909         break;
2910 
2911 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2912     case kCommandTimeSync:
2913         Get<MleRouter>().HandleTimeSync(aMessage, aMessageInfo, neighbor);
2914         break;
2915 #endif
2916 #endif // OPENTHREAD_FTD
2917 
2918 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
2919     case kCommandLinkMetricsManagementRequest:
2920         HandleLinkMetricsManagementRequest(aMessage, aMessageInfo, neighbor);
2921         break;
2922 #endif
2923 
2924 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
2925     case kCommandLinkMetricsManagementResponse:
2926         HandleLinkMetricsManagementResponse(aMessage, aMessageInfo, neighbor);
2927         break;
2928 #endif
2929 
2930 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
2931     case kCommandLinkProbe:
2932         HandleLinkProbe(aMessage, aMessageInfo, neighbor);
2933         break;
2934 #endif
2935 
2936     default:
2937         ExitNow(error = kErrorDrop);
2938     }
2939 
2940 #if OPENTHREAD_CONFIG_MULTI_RADIO
2941     // If we could not find a neighbor matching the MAC address of the
2942     // received MLE messages, or if the neighbor is now invalid, we
2943     // check again after the message is handled with a relaxed neighbor
2944     // state filer. The processing of the received MLE message may
2945     // create a new neighbor or change the neighbor table (e.g.,
2946     // receiving a "Parent Request" from a new child, or processing a
2947     // "Link Request" from a previous child which is being promoted to a
2948     // router).
2949 
2950     if ((neighbor == nullptr) || neighbor->IsStateInvalid())
2951     {
2952         neighbor = Get<NeighborTable>().FindNeighbor(extAddr, Neighbor::kInStateAnyExceptInvalid);
2953 
2954         if (neighbor != nullptr)
2955         {
2956             Get<RadioSelector>().UpdateOnReceive(*neighbor, aMessage.GetRadioType(), /* aIsDuplicate */ false);
2957         }
2958     }
2959 #endif
2960 
2961 exit:
2962     LogProcessError(kTypeGenericUdp, error);
2963 }
2964 
HandleAdvertisement(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor)2965 void Mle::HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Neighbor *aNeighbor)
2966 {
2967     Error      error = kErrorNone;
2968     uint16_t   sourceAddress;
2969     LeaderData leaderData;
2970     uint8_t    tlvs[] = {Tlv::kNetworkData};
2971     uint16_t   delay;
2972 
2973     // Source Address
2974     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aMessage, sourceAddress));
2975 
2976     Log(kMessageReceive, kTypeAdvertisement, aMessageInfo.GetPeerAddr(), sourceAddress);
2977 
2978     // Leader Data
2979     SuccessOrExit(error = ReadLeaderData(aMessage, leaderData));
2980 
2981     if (!IsDetached())
2982     {
2983 #if OPENTHREAD_FTD
2984         if (IsFullThreadDevice())
2985         {
2986             SuccessOrExit(error = Get<MleRouter>().HandleAdvertisement(aMessage, aMessageInfo, aNeighbor));
2987         }
2988         else
2989 #endif
2990         {
2991             if ((aNeighbor == &mParent) && (mParent.GetRloc16() != sourceAddress))
2992             {
2993                 // Remove stale parent.
2994                 IgnoreError(BecomeDetached());
2995             }
2996         }
2997     }
2998 
2999     switch (mRole)
3000     {
3001     case kRoleDisabled:
3002     case kRoleDetached:
3003         ExitNow();
3004 
3005     case kRoleChild:
3006         VerifyOrExit(aNeighbor == &mParent);
3007 
3008         if ((mParent.GetRloc16() == sourceAddress) && (leaderData.GetPartitionId() != mLeaderData.GetPartitionId() ||
3009                                                        leaderData.GetLeaderRouterId() != GetLeaderId()))
3010         {
3011             SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
3012 
3013 #if OPENTHREAD_FTD
3014             if (IsFullThreadDevice())
3015             {
3016                 RouteTlv route;
3017 
3018                 if ((Tlv::FindTlv(aMessage, route) == kErrorNone) && route.IsValid())
3019                 {
3020                     // Overwrite Route Data
3021                     IgnoreError(Get<MleRouter>().ProcessRouteTlv(route));
3022                 }
3023             }
3024 #endif
3025 
3026             mRetrieveNewNetworkData = true;
3027         }
3028 
3029         mParent.SetLastHeard(TimerMilli::GetNow());
3030         break;
3031 
3032     case kRoleRouter:
3033     case kRoleLeader:
3034         VerifyOrExit(aNeighbor && aNeighbor->IsStateValid());
3035         break;
3036     }
3037 
3038     if (mRetrieveNewNetworkData || IsNetworkDataNewer(leaderData))
3039     {
3040         delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
3041         IgnoreError(SendDataRequest(aMessageInfo.GetPeerAddr(), tlvs, sizeof(tlvs), delay));
3042     }
3043 
3044 exit:
3045     LogProcessError(kTypeAdvertisement, error);
3046 }
3047 
HandleDataResponse(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Neighbor * aNeighbor)3048 void Mle::HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor)
3049 {
3050     Error error;
3051 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
3052     uint16_t metricsReportValueOffset;
3053     uint16_t length;
3054 #endif
3055 
3056     Log(kMessageReceive, kTypeDataResponse, aMessageInfo.GetPeerAddr());
3057 
3058     VerifyOrExit(aNeighbor && aNeighbor->IsStateValid(), error = kErrorSecurity);
3059 
3060 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
3061     if (Tlv::FindTlvValueOffset(aMessage, Tlv::kLinkMetricsReport, metricsReportValueOffset, length) == kErrorNone)
3062     {
3063         Get<LinkMetrics::LinkMetrics>().HandleReport(aMessage, metricsReportValueOffset, length,
3064                                                      aMessageInfo.GetPeerAddr());
3065     }
3066 #endif
3067 
3068     error = HandleLeaderData(aMessage, aMessageInfo);
3069 
3070     if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle())
3071     {
3072         // Here simply stops fast data poll request by Mle Data Request.
3073         // Note that in some cases fast data poll may continue after below stop operation until
3074         // running out the specified number. E.g. other component also trigger fast poll, and
3075         // is waiting for response; or the corner case where multiple Mle Data Request attempts
3076         // happened due to the retransmission mechanism.
3077         Get<DataPollSender>().StopFastPolls();
3078     }
3079 
3080 exit:
3081     LogProcessError(kTypeDataResponse, error);
3082 }
3083 
IsNetworkDataNewer(const LeaderData & aLeaderData)3084 bool Mle::IsNetworkDataNewer(const LeaderData &aLeaderData)
3085 {
3086     int8_t diff;
3087 
3088     if (IsFullNetworkData())
3089     {
3090         diff = static_cast<int8_t>(aLeaderData.GetDataVersion() - Get<NetworkData::Leader>().GetVersion());
3091     }
3092     else
3093     {
3094         diff = static_cast<int8_t>(aLeaderData.GetStableDataVersion() - Get<NetworkData::Leader>().GetStableVersion());
3095     }
3096 
3097     return (diff > 0);
3098 }
3099 
HandleLeaderData(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3100 Error Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3101 {
3102     Error               error = kErrorNone;
3103     LeaderData          leaderData;
3104     ActiveTimestampTlv  activeTimestamp;
3105     PendingTimestampTlv pendingTimestamp;
3106     uint16_t            networkDataOffset    = 0;
3107     uint16_t            activeDatasetOffset  = 0;
3108     uint16_t            pendingDatasetOffset = 0;
3109     bool                dataRequest          = false;
3110     Tlv                 tlv;
3111 
3112     // Leader Data
3113     SuccessOrExit(error = ReadLeaderData(aMessage, leaderData));
3114 
3115     if ((leaderData.GetPartitionId() != mLeaderData.GetPartitionId()) ||
3116         (leaderData.GetWeighting() != mLeaderData.GetWeighting()) || (leaderData.GetLeaderRouterId() != GetLeaderId()))
3117     {
3118         if (IsChild())
3119         {
3120             SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
3121             mRetrieveNewNetworkData = true;
3122         }
3123         else
3124         {
3125             ExitNow(error = kErrorDrop);
3126         }
3127     }
3128     else if (!mRetrieveNewNetworkData)
3129     {
3130         VerifyOrExit(IsNetworkDataNewer(leaderData));
3131     }
3132 
3133     // Active Timestamp
3134     if (Tlv::FindTlv(aMessage, activeTimestamp) == kErrorNone)
3135     {
3136         const MeshCoP::Timestamp *timestamp;
3137 
3138         VerifyOrExit(activeTimestamp.IsValid(), error = kErrorParse);
3139         timestamp = Get<MeshCoP::ActiveDataset>().GetTimestamp();
3140 
3141         // if received timestamp does not match the local value and message does not contain the dataset,
3142         // send MLE Data Request
3143         if (!IsLeader() && ((timestamp == nullptr) || (timestamp->Compare(activeTimestamp) != 0)) &&
3144             (Tlv::FindTlvOffset(aMessage, Tlv::kActiveDataset, activeDatasetOffset) != kErrorNone))
3145         {
3146             ExitNow(dataRequest = true);
3147         }
3148     }
3149     else
3150     {
3151         activeTimestamp.SetLength(0);
3152     }
3153 
3154     // Pending Timestamp
3155     if (Tlv::FindTlv(aMessage, pendingTimestamp) == kErrorNone)
3156     {
3157         const MeshCoP::Timestamp *timestamp;
3158 
3159         VerifyOrExit(pendingTimestamp.IsValid(), error = kErrorParse);
3160         timestamp = Get<MeshCoP::PendingDataset>().GetTimestamp();
3161 
3162         // if received timestamp does not match the local value and message does not contain the dataset,
3163         // send MLE Data Request
3164         if (!IsLeader() && ((timestamp == nullptr) || (timestamp->Compare(pendingTimestamp) != 0)) &&
3165             (Tlv::FindTlvOffset(aMessage, Tlv::kPendingDataset, pendingDatasetOffset) != kErrorNone))
3166         {
3167             ExitNow(dataRequest = true);
3168         }
3169     }
3170     else
3171     {
3172         pendingTimestamp.SetLength(0);
3173     }
3174 
3175     if (Tlv::FindTlvOffset(aMessage, Tlv::kNetworkData, networkDataOffset) == kErrorNone)
3176     {
3177         error =
3178             Get<NetworkData::Leader>().SetNetworkData(leaderData.GetDataVersion(), leaderData.GetStableDataVersion(),
3179                                                       !IsFullNetworkData(), aMessage, networkDataOffset);
3180         SuccessOrExit(error);
3181     }
3182     else
3183     {
3184         ExitNow(dataRequest = true);
3185     }
3186 
3187 #if OPENTHREAD_FTD
3188     if (IsLeader())
3189     {
3190         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
3191     }
3192     else
3193 #endif
3194     {
3195         // Active Dataset
3196         if (activeTimestamp.GetLength() > 0)
3197         {
3198             if (activeDatasetOffset > 0)
3199             {
3200                 IgnoreError(aMessage.Read(activeDatasetOffset, tlv));
3201                 IgnoreError(Get<MeshCoP::ActiveDataset>().Save(activeTimestamp, aMessage,
3202                                                                activeDatasetOffset + sizeof(tlv), tlv.GetLength()));
3203             }
3204         }
3205 
3206         // Pending Dataset
3207         if (pendingTimestamp.GetLength() > 0)
3208         {
3209             if (pendingDatasetOffset > 0)
3210             {
3211                 IgnoreError(aMessage.Read(pendingDatasetOffset, tlv));
3212                 IgnoreError(Get<MeshCoP::PendingDataset>().Save(pendingTimestamp, aMessage,
3213                                                                 pendingDatasetOffset + sizeof(tlv), tlv.GetLength()));
3214             }
3215         }
3216     }
3217 
3218     mRetrieveNewNetworkData = false;
3219 
3220 exit:
3221 
3222     if (dataRequest)
3223     {
3224         static const uint8_t tlvs[] = {Tlv::kNetworkData};
3225         uint16_t             delay;
3226 
3227         if (aMessageInfo.GetSockAddr().IsMulticast())
3228         {
3229             delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
3230         }
3231         else
3232         {
3233             // This method may have been called from an MLE request
3234             // handler.  We add a minimum delay here so that the MLE
3235             // response is enqueued before the MLE Data Request.
3236             delay = 10;
3237         }
3238 
3239         IgnoreError(SendDataRequest(aMessageInfo.GetPeerAddr(), tlvs, sizeof(tlvs), delay));
3240     }
3241     else if (error == kErrorNone)
3242     {
3243         mDataRequestAttempts = 0;
3244         mDataRequestState    = kDataRequestNone;
3245 
3246         // Here the `mMessageTransmissionTimer` is intentionally not canceled
3247         // so that when it fires from its callback a "Child Update" is sent
3248         // if the device is a rx-on child. This way, even when the timer is
3249         // reused for retransmission of "Data Request" messages, it is ensured
3250         // that keep-alive "Child Update Request" messages are send within the
3251         // child's timeout.
3252     }
3253 
3254     return error;
3255 }
3256 
IsBetterParent(uint16_t aRloc16,uint8_t aLinkQuality,uint8_t aLinkMargin,const ConnectivityTlv & aConnectivityTlv,uint8_t aVersion,uint8_t aCslClockAccuracy,uint8_t aCslUncertainty)3257 bool Mle::IsBetterParent(uint16_t               aRloc16,
3258                          uint8_t                aLinkQuality,
3259                          uint8_t                aLinkMargin,
3260                          const ConnectivityTlv &aConnectivityTlv,
3261                          uint8_t                aVersion,
3262                          uint8_t                aCslClockAccuracy,
3263                          uint8_t                aCslUncertainty)
3264 {
3265     bool rval = false;
3266 
3267     uint8_t candidateLinkQualityIn     = mParentCandidate.GetLinkInfo().GetLinkQuality();
3268     uint8_t candidateTwoWayLinkQuality = (candidateLinkQualityIn < mParentCandidate.GetLinkQualityOut())
3269                                              ? candidateLinkQualityIn
3270                                              : mParentCandidate.GetLinkQualityOut();
3271 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3272     uint64_t candidateCslMetric = 0;
3273     uint64_t cslMetric          = 0;
3274 #else
3275     OT_UNUSED_VARIABLE(aCslClockAccuracy);
3276     OT_UNUSED_VARIABLE(aCslUncertainty);
3277 #endif
3278 
3279     // Mesh Impacting Criteria
3280     if (aLinkQuality != candidateTwoWayLinkQuality)
3281     {
3282         ExitNow(rval = (aLinkQuality > candidateTwoWayLinkQuality));
3283     }
3284 
3285     if (IsActiveRouter(aRloc16) != IsActiveRouter(mParentCandidate.GetRloc16()))
3286     {
3287         ExitNow(rval = IsActiveRouter(aRloc16));
3288     }
3289 
3290     if (aConnectivityTlv.GetParentPriority() != mParentPriority)
3291     {
3292         ExitNow(rval = (aConnectivityTlv.GetParentPriority() > mParentPriority));
3293     }
3294 
3295     // Prefer the parent with highest quality links (Link Quality 3 field in Connectivity TLV) to neighbors
3296     if (aConnectivityTlv.GetLinkQuality3() != mParentLinkQuality3)
3297     {
3298         ExitNow(rval = (aConnectivityTlv.GetLinkQuality3() > mParentLinkQuality3));
3299     }
3300 
3301     // Thread 1.2 Specification 4.5.2.1.2 Child Impacting Criteria
3302     if (aVersion != mParentCandidate.GetVersion())
3303     {
3304         ExitNow(rval = (aVersion > mParentCandidate.GetVersion()));
3305     }
3306 
3307     if (aConnectivityTlv.GetSedBufferSize() != mParentSedBufferSize)
3308     {
3309         ExitNow(rval = (aConnectivityTlv.GetSedBufferSize() > mParentSedBufferSize));
3310     }
3311 
3312     if (aConnectivityTlv.GetSedDatagramCount() != mParentSedDatagramCount)
3313     {
3314         ExitNow(rval = (aConnectivityTlv.GetSedDatagramCount() > mParentSedDatagramCount));
3315     }
3316 
3317     // Extra rules
3318     if (aConnectivityTlv.GetLinkQuality2() != mParentLinkQuality2)
3319     {
3320         ExitNow(rval = (aConnectivityTlv.GetLinkQuality2() > mParentLinkQuality2));
3321     }
3322 
3323     if (aConnectivityTlv.GetLinkQuality1() != mParentLinkQuality1)
3324     {
3325         ExitNow(rval = (aConnectivityTlv.GetLinkQuality1() > mParentLinkQuality1));
3326     }
3327 
3328 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3329     // CSL metric
3330     if (!IsRxOnWhenIdle())
3331     {
3332         cslMetric = CalcParentCslMetric(aCslClockAccuracy, aCslUncertainty);
3333         candidateCslMetric =
3334             CalcParentCslMetric(mParentCandidate.GetCslClockAccuracy(), mParentCandidate.GetCslClockUncertainty());
3335         if (candidateCslMetric != cslMetric)
3336         {
3337             ExitNow(rval = (cslMetric < candidateCslMetric));
3338         }
3339     }
3340 #endif
3341 
3342     rval = (aLinkMargin > mParentLinkMargin);
3343 
3344 exit:
3345     return rval;
3346 }
3347 
HandleParentResponse(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,uint32_t aKeySequence)3348 void Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint32_t aKeySequence)
3349 {
3350     Error                 error    = kErrorNone;
3351     const ThreadLinkInfo *linkInfo = aMessageInfo.GetThreadLinkInfo();
3352     Challenge             response;
3353     uint16_t              version;
3354     uint16_t              sourceAddress;
3355     LeaderData            leaderData;
3356     uint8_t               linkMarginFromTlv;
3357     uint8_t               linkMargin;
3358     uint8_t               linkQuality;
3359     ConnectivityTlv       connectivity;
3360     uint32_t              linkFrameCounter;
3361     uint32_t              mleFrameCounter;
3362     Mac::ExtAddress       extAddress;
3363 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3364     TimeParameterTlv timeParameter;
3365 #endif
3366 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3367     CslClockAccuracyTlv clockAccuracy;
3368 #endif
3369 
3370     // Source Address
3371     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aMessage, sourceAddress));
3372 
3373     Log(kMessageReceive, kTypeParentResponse, aMessageInfo.GetPeerAddr(), sourceAddress);
3374 
3375     // Version
3376     SuccessOrExit(error = Tlv::Find<VersionTlv>(aMessage, version));
3377     VerifyOrExit(version >= OT_THREAD_VERSION_1_1, error = kErrorParse);
3378 
3379     // Response
3380     SuccessOrExit(error = ReadResponse(aMessage, response));
3381     VerifyOrExit(response == mParentRequestChallenge, error = kErrorParse);
3382 
3383     aMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddress);
3384 
3385     if (IsChild() && mParent.GetExtAddress() == extAddress)
3386     {
3387         mReceivedResponseFromParent = true;
3388     }
3389 
3390     // Leader Data
3391     SuccessOrExit(error = ReadLeaderData(aMessage, leaderData));
3392 
3393     // Link Margin
3394     SuccessOrExit(error = Tlv::Find<LinkMarginTlv>(aMessage, linkMarginFromTlv));
3395 
3396     linkMargin = LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(), linkInfo->GetRss());
3397 
3398     if (linkMargin > linkMarginFromTlv)
3399     {
3400         linkMargin = linkMarginFromTlv;
3401     }
3402 
3403     linkQuality = LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMargin);
3404 
3405     // Connectivity
3406     SuccessOrExit(error = Tlv::FindTlv(aMessage, connectivity));
3407     VerifyOrExit(connectivity.IsValid(), error = kErrorParse);
3408 
3409     // Share data with application, if requested.
3410     if (mParentResponseCb)
3411     {
3412         otThreadParentResponseInfo parentinfo;
3413 
3414         parentinfo.mExtAddr      = extAddress;
3415         parentinfo.mRloc16       = sourceAddress;
3416         parentinfo.mRssi         = linkInfo->GetRss();
3417         parentinfo.mPriority     = connectivity.GetParentPriority();
3418         parentinfo.mLinkQuality3 = connectivity.GetLinkQuality3();
3419         parentinfo.mLinkQuality2 = connectivity.GetLinkQuality2();
3420         parentinfo.mLinkQuality1 = connectivity.GetLinkQuality1();
3421         parentinfo.mIsAttached   = IsAttached();
3422 
3423         mParentResponseCb(&parentinfo, mParentResponseCbContext);
3424     }
3425 
3426 #if OPENTHREAD_FTD
3427     if (IsFullThreadDevice() && !IsDetached())
3428     {
3429         int8_t diff = static_cast<int8_t>(connectivity.GetIdSequence() - Get<RouterTable>().GetRouterIdSequence());
3430 
3431         switch (mParentRequestMode)
3432         {
3433         case kAttachAny:
3434             VerifyOrExit(leaderData.GetPartitionId() != mLeaderData.GetPartitionId() || diff > 0);
3435             break;
3436 
3437         case kAttachSame1:
3438         case kAttachSame2:
3439             VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
3440             VerifyOrExit(diff > 0);
3441             break;
3442 
3443         case kAttachSameDowngrade:
3444             VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
3445             VerifyOrExit(diff >= 0);
3446             break;
3447 
3448         case kAttachBetter:
3449             VerifyOrExit(leaderData.GetPartitionId() != mLeaderData.GetPartitionId());
3450 
3451             VerifyOrExit(MleRouter::ComparePartitions(connectivity.GetActiveRouters() <= 1, leaderData,
3452                                                       Get<MleRouter>().IsSingleton(), mLeaderData) > 0);
3453             break;
3454         }
3455     }
3456 #endif
3457 
3458     // Continue to process the "ParentResponse" if it is from current
3459     // parent candidate to update the challenge and frame counters.
3460 
3461     if (mParentCandidate.IsStateParentResponse() && (mParentCandidate.GetExtAddress() != extAddress))
3462     {
3463         // if already have a candidate parent, only seek a better parent
3464 
3465         int compare = 0;
3466 
3467 #if OPENTHREAD_FTD
3468         if (IsFullThreadDevice())
3469         {
3470             compare = MleRouter::ComparePartitions(connectivity.GetActiveRouters() <= 1, leaderData, mParentIsSingleton,
3471                                                    mParentLeaderData);
3472         }
3473 
3474         // only consider partitions that are the same or better
3475         VerifyOrExit(compare >= 0);
3476 #endif
3477 
3478 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3479         if (Tlv::FindTlv(aMessage, clockAccuracy) != kErrorNone)
3480         {
3481             clockAccuracy.SetCslClockAccuracy(kCslWorstCrystalPpm);
3482             clockAccuracy.SetCslUncertainty(kCslWorstUncertainty);
3483         }
3484 #endif
3485 
3486         // only consider better parents if the partitions are the same
3487 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3488         VerifyOrExit(compare != 0 ||
3489                      IsBetterParent(sourceAddress, linkQuality, linkMargin, connectivity, static_cast<uint8_t>(version),
3490                                     clockAccuracy.GetCslClockAccuracy(), clockAccuracy.GetCslUncertainty()));
3491 #else
3492         VerifyOrExit(compare != 0 || IsBetterParent(sourceAddress, linkQuality, linkMargin, connectivity,
3493                                                     static_cast<uint8_t>(version), 0, 0));
3494 #endif
3495     }
3496 
3497     // Link/MLE Frame Counters
3498     SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
3499 
3500 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3501 
3502     // Time Parameter
3503     if (Tlv::FindTlv(aMessage, timeParameter) == kErrorNone)
3504     {
3505         VerifyOrExit(timeParameter.IsValid());
3506 
3507         Get<TimeSync>().SetTimeSyncPeriod(timeParameter.GetTimeSyncPeriod());
3508         Get<TimeSync>().SetXtalThreshold(timeParameter.GetXtalThreshold());
3509     }
3510 
3511 #if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
3512     else
3513     {
3514         // If the time sync feature is required, don't choose the parent which doesn't support it.
3515         ExitNow();
3516     }
3517 
3518 #endif // OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
3519 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3520 
3521     // Challenge
3522     SuccessOrExit(error = ReadChallenge(aMessage, mParentCandidateChallenge));
3523 
3524     mParentCandidate.SetExtAddress(extAddress);
3525     mParentCandidate.SetRloc16(sourceAddress);
3526     mParentCandidate.GetLinkFrameCounters().SetAll(linkFrameCounter);
3527     mParentCandidate.SetLinkAckFrameCounter(linkFrameCounter);
3528     mParentCandidate.SetMleFrameCounter(mleFrameCounter);
3529     mParentCandidate.SetVersion(static_cast<uint8_t>(version));
3530     mParentCandidate.SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
3531                                               DeviceMode::kModeFullNetworkData));
3532     mParentCandidate.GetLinkInfo().Clear();
3533     mParentCandidate.GetLinkInfo().AddRss(linkInfo->GetRss());
3534     mParentCandidate.ResetLinkFailures();
3535     mParentCandidate.SetLinkQualityOut(LinkQualityInfo::ConvertLinkMarginToLinkQuality(linkMarginFromTlv));
3536     mParentCandidate.SetState(Neighbor::kStateParentResponse);
3537     mParentCandidate.SetKeySequence(aKeySequence);
3538 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3539     mParentCandidate.SetCslClockAccuracy(clockAccuracy.GetCslClockAccuracy());
3540     mParentCandidate.SetCslClockUncertainty(clockAccuracy.GetCslUncertainty());
3541 #endif
3542 
3543     mParentPriority         = connectivity.GetParentPriority();
3544     mParentLinkQuality3     = connectivity.GetLinkQuality3();
3545     mParentLinkQuality2     = connectivity.GetLinkQuality2();
3546     mParentLinkQuality1     = connectivity.GetLinkQuality1();
3547     mParentLeaderCost       = connectivity.GetLeaderCost();
3548     mParentSedBufferSize    = connectivity.GetSedBufferSize();
3549     mParentSedDatagramCount = connectivity.GetSedDatagramCount();
3550     mParentLeaderData       = leaderData;
3551     mParentIsSingleton      = connectivity.GetActiveRouters() <= 1;
3552     mParentLinkMargin       = linkMargin;
3553 
3554 exit:
3555     LogProcessError(kTypeParentResponse, error);
3556 }
3557 
HandleChildIdResponse(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Neighbor * aNeighbor)3558 void Mle::HandleChildIdResponse(const Message &         aMessage,
3559                                 const Ip6::MessageInfo &aMessageInfo,
3560                                 const Neighbor *        aNeighbor)
3561 {
3562     OT_UNUSED_VARIABLE(aMessageInfo);
3563 
3564     Error               error = kErrorNone;
3565     LeaderData          leaderData;
3566     uint16_t            sourceAddress;
3567     uint16_t            shortAddress;
3568     ActiveTimestampTlv  activeTimestamp;
3569     PendingTimestampTlv pendingTimestamp;
3570     Tlv                 tlv;
3571     uint16_t            networkDataOffset;
3572     uint16_t            offset;
3573 
3574     // Source Address
3575     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aMessage, sourceAddress));
3576 
3577     Log(kMessageReceive, kTypeChildIdResponse, aMessageInfo.GetPeerAddr(), sourceAddress);
3578 
3579     VerifyOrExit(aNeighbor && aNeighbor->IsStateValid(), error = kErrorSecurity);
3580 
3581     VerifyOrExit(mAttachState == kAttachStateChildIdRequest);
3582 
3583     // Leader Data
3584     SuccessOrExit(error = ReadLeaderData(aMessage, leaderData));
3585 
3586     // ShortAddress
3587     SuccessOrExit(error = Tlv::Find<Address16Tlv>(aMessage, shortAddress));
3588 
3589     // Network Data
3590     error = Tlv::FindTlvOffset(aMessage, Tlv::kNetworkData, networkDataOffset);
3591     SuccessOrExit(error);
3592 
3593     // Active Timestamp
3594     if (Tlv::FindTlv(aMessage, activeTimestamp) == kErrorNone)
3595     {
3596         VerifyOrExit(activeTimestamp.IsValid(), error = kErrorParse);
3597 
3598         // Active Dataset
3599         if (Tlv::FindTlvOffset(aMessage, Tlv::kActiveDataset, offset) == kErrorNone)
3600         {
3601             IgnoreError(aMessage.Read(offset, tlv));
3602             IgnoreError(
3603                 Get<MeshCoP::ActiveDataset>().Save(activeTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength()));
3604         }
3605     }
3606 
3607     // clear Pending Dataset if device succeed to reattach using stored Pending Dataset
3608     if (mReattachState == kReattachPending)
3609     {
3610         Get<MeshCoP::PendingDataset>().Clear();
3611     }
3612 
3613     // Pending Timestamp
3614     if (Tlv::FindTlv(aMessage, pendingTimestamp) == kErrorNone)
3615     {
3616         VerifyOrExit(pendingTimestamp.IsValid(), error = kErrorParse);
3617 
3618         // Pending Dataset
3619         if (Tlv::FindTlvOffset(aMessage, Tlv::kPendingDataset, offset) == kErrorNone)
3620         {
3621             IgnoreError(aMessage.Read(offset, tlv));
3622             IgnoreError(
3623                 Get<MeshCoP::PendingDataset>().Save(pendingTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength()));
3624         }
3625     }
3626     else
3627     {
3628         Get<MeshCoP::PendingDataset>().ClearNetwork();
3629     }
3630 
3631 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3632     // Sync to Thread network time
3633     if (aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ)
3634     {
3635         Get<TimeSync>().HandleTimeSyncMessage(aMessage);
3636     }
3637 #endif
3638 
3639     // Parent Attach Success
3640 
3641     SetStateDetached();
3642 
3643     SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId());
3644 
3645     if (!IsRxOnWhenIdle())
3646     {
3647         Get<DataPollSender>().SetAttachMode(false);
3648         Get<MeshForwarder>().SetRxOnWhenIdle(false);
3649     }
3650     else
3651     {
3652         Get<MeshForwarder>().SetRxOnWhenIdle(true);
3653     }
3654 
3655 #if OPENTHREAD_FTD
3656     if (IsFullThreadDevice())
3657     {
3658         RouteTlv route;
3659 
3660         if (Tlv::FindTlv(aMessage, route) == kErrorNone)
3661         {
3662             SuccessOrExit(error = Get<MleRouter>().ProcessRouteTlv(route));
3663         }
3664     }
3665 #endif
3666 
3667     mParent = mParentCandidate;
3668     mParentCandidate.Clear();
3669 
3670 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
3671     Get<Mac::Mac>().SetCslParentUncertainty(mParent.GetCslClockUncertainty());
3672     Get<Mac::Mac>().SetCslParentClockAccuracy(mParent.GetCslClockAccuracy());
3673 #endif
3674 
3675     mParent.SetRloc16(sourceAddress);
3676 
3677     IgnoreError(Get<NetworkData::Leader>().SetNetworkData(leaderData.GetDataVersion(),
3678                                                           leaderData.GetStableDataVersion(), !IsFullNetworkData(),
3679                                                           aMessage, networkDataOffset));
3680 
3681     SetStateChild(shortAddress);
3682 
3683 exit:
3684     LogProcessError(kTypeChildIdResponse, error);
3685 }
3686 
HandleChildUpdateRequest(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor)3687 void Mle::HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Neighbor *aNeighbor)
3688 {
3689     static const uint8_t kMaxResponseTlvs = 6;
3690 
3691     Error         error = kErrorNone;
3692     uint16_t      sourceAddress;
3693     Challenge     challenge;
3694     RequestedTlvs requestedTlvs;
3695     uint8_t       tlvs[kMaxResponseTlvs] = {};
3696     uint8_t       numTlvs                = 0;
3697 
3698     // Source Address
3699     SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aMessage, sourceAddress));
3700 
3701     Log(kMessageReceive, kTypeChildUpdateRequestOfParent, aMessageInfo.GetPeerAddr(), sourceAddress);
3702 
3703     // Challenge
3704     switch (ReadChallenge(aMessage, challenge))
3705     {
3706     case kErrorNone:
3707         tlvs[numTlvs++] = Tlv::kResponse;
3708         tlvs[numTlvs++] = Tlv::kMleFrameCounter;
3709         tlvs[numTlvs++] = Tlv::kLinkFrameCounter;
3710         break;
3711     case kErrorNotFound:
3712         challenge.mLength = 0;
3713         break;
3714     default:
3715         ExitNow(error = kErrorParse);
3716     }
3717 
3718     if (aNeighbor == &mParent)
3719     {
3720         uint8_t status;
3721 
3722         switch (Tlv::Find<StatusTlv>(aMessage, status))
3723         {
3724         case kErrorNone:
3725             VerifyOrExit(status != StatusTlv::kError, IgnoreError(BecomeDetached()));
3726             break;
3727         case kErrorNotFound:
3728             break;
3729         default:
3730             ExitNow(error = kErrorParse);
3731         }
3732 
3733         if (mParent.GetRloc16() != sourceAddress)
3734         {
3735             IgnoreError(BecomeDetached());
3736             ExitNow();
3737         }
3738 
3739         // Leader Data, Network Data, Active Timestamp, Pending Timestamp
3740         SuccessOrExit(error = HandleLeaderData(aMessage, aMessageInfo));
3741     }
3742     else
3743     {
3744         // this device is not a child of the Child Update Request source
3745         tlvs[numTlvs++] = Tlv::kStatus;
3746     }
3747 
3748     // TLV Request
3749     switch (FindTlvRequest(aMessage, requestedTlvs))
3750     {
3751     case kErrorNone:
3752         for (uint8_t i = 0; i < requestedTlvs.mNumTlvs; i++)
3753         {
3754             if (numTlvs >= sizeof(tlvs))
3755             {
3756                 otLogWarnMle("Failed to respond with TLVs: %d of %d", i, requestedTlvs.mNumTlvs);
3757                 break;
3758             }
3759 
3760             tlvs[numTlvs++] = requestedTlvs.mTlvs[i];
3761         }
3762         break;
3763     case kErrorNotFound:
3764         break;
3765     default:
3766         ExitNow(error = kErrorParse);
3767     }
3768 
3769 #if OPENTHREAD_CONFIG_MULTI_RADIO
3770     if ((aNeighbor != nullptr) && (challenge.mLength != 0))
3771     {
3772         aNeighbor->ClearLastRxFragmentTag();
3773     }
3774 #endif
3775 
3776     SuccessOrExit(error = SendChildUpdateResponse(tlvs, numTlvs, challenge));
3777 
3778 exit:
3779     LogProcessError(kTypeChildUpdateRequestOfParent, error);
3780 }
3781 
HandleChildUpdateResponse(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Neighbor * aNeighbor)3782 void Mle::HandleChildUpdateResponse(const Message &         aMessage,
3783                                     const Ip6::MessageInfo &aMessageInfo,
3784                                     const Neighbor *        aNeighbor)
3785 {
3786     Error     error = kErrorNone;
3787     uint8_t   status;
3788     uint8_t   mode;
3789     Challenge response;
3790     uint32_t  linkFrameCounter;
3791     uint32_t  mleFrameCounter;
3792     uint16_t  sourceAddress;
3793     uint32_t  timeout;
3794 
3795     Log(kMessageReceive, kTypeChildUpdateResponseOfParent, aMessageInfo.GetPeerAddr());
3796 
3797     switch (mRole)
3798     {
3799     case kRoleDetached:
3800         SuccessOrExit(error = ReadResponse(aMessage, response));
3801         VerifyOrExit(response == mParentRequestChallenge, error = kErrorSecurity);
3802         break;
3803 
3804     case kRoleChild:
3805         VerifyOrExit((aNeighbor == &mParent) && mParent.IsStateValid(), error = kErrorSecurity);
3806         break;
3807 
3808     default:
3809         OT_ASSERT(false);
3810         OT_UNREACHABLE_CODE(break);
3811     }
3812 
3813     // Status
3814     if (Tlv::Find<StatusTlv>(aMessage, status) == kErrorNone)
3815     {
3816         IgnoreError(BecomeDetached());
3817         ExitNow();
3818     }
3819 
3820     // Mode
3821     SuccessOrExit(error = Tlv::Find<ModeTlv>(aMessage, mode));
3822     VerifyOrExit(DeviceMode(mode) == mDeviceMode, error = kErrorDrop);
3823 
3824     switch (mRole)
3825     {
3826     case kRoleDetached:
3827         SuccessOrExit(error = ReadFrameCounters(aMessage, linkFrameCounter, mleFrameCounter));
3828 
3829         mParent.GetLinkFrameCounters().SetAll(linkFrameCounter);
3830         mParent.SetLinkAckFrameCounter(linkFrameCounter);
3831         mParent.SetMleFrameCounter(mleFrameCounter);
3832 
3833         mParent.SetState(Neighbor::kStateValid);
3834         SetStateChild(GetRloc16());
3835 
3836         mRetrieveNewNetworkData = true;
3837 
3838         OT_FALL_THROUGH;
3839 
3840     case kRoleChild:
3841         // Source Address
3842         SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aMessage, sourceAddress));
3843 
3844         if (RouterIdFromRloc16(sourceAddress) != RouterIdFromRloc16(GetRloc16()))
3845         {
3846             IgnoreError(BecomeDetached());
3847             ExitNow();
3848         }
3849 
3850         // Leader Data, Network Data, Active Timestamp, Pending Timestamp
3851         SuccessOrExit(error = HandleLeaderData(aMessage, aMessageInfo));
3852 
3853         // Timeout optional
3854         switch (Tlv::Find<TimeoutTlv>(aMessage, timeout))
3855         {
3856         case kErrorNone:
3857             mTimeout = timeout;
3858             break;
3859         case kErrorNotFound:
3860             break;
3861         default:
3862             ExitNow(error = kErrorParse);
3863         }
3864 
3865         if (!IsRxOnWhenIdle())
3866         {
3867             Get<DataPollSender>().SetAttachMode(false);
3868             Get<MeshForwarder>().SetRxOnWhenIdle(false);
3869         }
3870         else
3871         {
3872             Get<MeshForwarder>().SetRxOnWhenIdle(true);
3873         }
3874 
3875         break;
3876 
3877     default:
3878         OT_ASSERT(false);
3879         OT_UNREACHABLE_CODE(break);
3880     }
3881 
3882 exit:
3883 
3884     if (error == kErrorNone)
3885     {
3886         if (mChildUpdateRequestState == kChildUpdateRequestActive)
3887         {
3888             mChildUpdateAttempts     = 0;
3889             mChildUpdateRequestState = kChildUpdateRequestNone;
3890             ScheduleMessageTransmissionTimer();
3891         }
3892     }
3893 
3894     LogProcessError(kTypeChildUpdateResponseOfParent, error);
3895 }
3896 
HandleAnnounce(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3897 void Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3898 {
3899     OT_UNUSED_VARIABLE(aMessageInfo);
3900 
3901     Error                     error = kErrorNone;
3902     ChannelTlv                channelTlv;
3903     ActiveTimestampTlv        timestamp;
3904     const MeshCoP::Timestamp *localTimestamp;
3905     uint8_t                   channel;
3906     uint16_t                  panId;
3907 
3908     Log(kMessageReceive, kTypeAnnounce, aMessageInfo.GetPeerAddr());
3909 
3910     SuccessOrExit(error = Tlv::FindTlv(aMessage, channelTlv));
3911     VerifyOrExit(channelTlv.IsValid(), error = kErrorParse);
3912 
3913     channel = static_cast<uint8_t>(channelTlv.GetChannel());
3914 
3915     SuccessOrExit(error = Tlv::FindTlv(aMessage, timestamp));
3916     VerifyOrExit(timestamp.IsValid(), error = kErrorParse);
3917 
3918     SuccessOrExit(error = Tlv::Find<PanIdTlv>(aMessage, panId));
3919 
3920     localTimestamp = Get<MeshCoP::ActiveDataset>().GetTimestamp();
3921 
3922     if (localTimestamp == nullptr || localTimestamp->Compare(timestamp) > 0)
3923     {
3924         // No action is required if device is detached, and current
3925         // channel and pan-id match the values from the received MLE
3926         // Announce message.
3927 
3928         VerifyOrExit(!IsDetached() || (Get<Mac::Mac>().GetPanChannel() != channel) ||
3929                      (Get<Mac::Mac>().GetPanId() != panId));
3930 
3931         if (mAttachState == kAttachStateProcessAnnounce)
3932         {
3933             VerifyOrExit(mAlternateTimestamp < timestamp.GetSeconds());
3934         }
3935 
3936         mAlternateTimestamp = timestamp.GetSeconds();
3937         mAlternateChannel   = channel;
3938         mAlternatePanId     = panId;
3939         SetAttachState(kAttachStateProcessAnnounce);
3940         mAttachTimer.Start(kAnnounceProcessTimeout);
3941         mAttachCounter = 0;
3942 
3943         otLogNoteMle("Delay processing Announce - channel %d, panid 0x%02x", channel, panId);
3944     }
3945     else if (localTimestamp->Compare(timestamp) < 0)
3946     {
3947         SendAnnounce(channel, false);
3948 
3949 #if OPENTHREAD_CONFIG_MLE_SEND_UNICAST_ANNOUNCE_RESPONSE
3950         SendAnnounce(channel, false, aMessageInfo.GetPeerAddr());
3951 #endif
3952     }
3953     else
3954     {
3955         // Timestamps are equal.
3956 
3957 #if OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE
3958         // Notify `AnnounceSender` of the received Announce
3959         // message so it can update its state to determine
3960         // whether to send Announce or not.
3961         Get<AnnounceSender>().UpdateOnReceivedAnnounce();
3962 #endif
3963     }
3964 
3965 exit:
3966     LogProcessError(kTypeAnnounce, error);
3967 }
3968 
3969 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
HandleLinkMetricsManagementRequest(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor)3970 void Mle::HandleLinkMetricsManagementRequest(const Message &         aMessage,
3971                                              const Ip6::MessageInfo &aMessageInfo,
3972                                              Neighbor *              aNeighbor)
3973 {
3974     Error               error = kErrorNone;
3975     LinkMetrics::Status status;
3976 
3977     Log(kMessageReceive, kTypeLinkMetricsManagementRequest, aMessageInfo.GetPeerAddr());
3978 
3979     VerifyOrExit(aNeighbor != nullptr, error = kErrorInvalidState);
3980 
3981     SuccessOrExit(error = Get<LinkMetrics::LinkMetrics>().HandleManagementRequest(aMessage, *aNeighbor, status));
3982     error = SendLinkMetricsManagementResponse(aMessageInfo.GetPeerAddr(), status);
3983 
3984 exit:
3985     LogProcessError(kTypeLinkMetricsManagementRequest, error);
3986 }
3987 
3988 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3989 
3990 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
HandleLinkMetricsManagementResponse(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor)3991 void Mle::HandleLinkMetricsManagementResponse(const Message &         aMessage,
3992                                               const Ip6::MessageInfo &aMessageInfo,
3993                                               Neighbor *              aNeighbor)
3994 {
3995     Error error = kErrorNone;
3996 
3997     Log(kMessageReceive, kTypeLinkMetricsManagementResponse, aMessageInfo.GetPeerAddr());
3998 
3999     VerifyOrExit(aNeighbor != nullptr, error = kErrorInvalidState);
4000 
4001     error = Get<LinkMetrics::LinkMetrics>().HandleManagementResponse(aMessage, aMessageInfo.GetPeerAddr());
4002 
4003 exit:
4004     LogProcessError(kTypeLinkMetricsManagementResponse, error);
4005 }
4006 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
4007 
4008 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
HandleLinkProbe(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Neighbor * aNeighbor)4009 void Mle::HandleLinkProbe(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Neighbor *aNeighbor)
4010 {
4011     Error   error = kErrorNone;
4012     uint8_t seriesId;
4013 
4014     Log(kMessageReceive, kTypeLinkProbe, aMessageInfo.GetPeerAddr());
4015 
4016     SuccessOrExit(error = Get<LinkMetrics::LinkMetrics>().HandleLinkProbe(aMessage, seriesId));
4017     aNeighbor->AggregateLinkMetrics(seriesId, LinkMetrics::SeriesInfo::kSeriesTypeLinkProbe, aMessage.GetAverageLqi(),
4018                                     aMessage.GetAverageRss());
4019 
4020 exit:
4021     LogProcessError(kTypeLinkProbe, error);
4022 }
4023 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
4024 
ProcessAnnounce(void)4025 void Mle::ProcessAnnounce(void)
4026 {
4027     uint8_t  newChannel = mAlternateChannel;
4028     uint16_t newPanId   = mAlternatePanId;
4029 
4030     OT_ASSERT(mAttachState == kAttachStateProcessAnnounce);
4031 
4032     otLogNoteMle("Processing Announce - channel %d, panid 0x%02x", newChannel, newPanId);
4033 
4034     Stop(/* aClearNetworkDatasets */ false);
4035 
4036     // Save the current/previous channel and pan-id
4037     mAlternateChannel   = Get<Mac::Mac>().GetPanChannel();
4038     mAlternatePanId     = Get<Mac::Mac>().GetPanId();
4039     mAlternateTimestamp = 0;
4040 
4041     IgnoreError(Get<Mac::Mac>().SetPanChannel(newChannel));
4042     Get<Mac::Mac>().SetPanId(newPanId);
4043 
4044     IgnoreError(Start(/* aAnnounceAttach */ true));
4045 }
4046 
GetNextHop(uint16_t aDestination) const4047 uint16_t Mle::GetNextHop(uint16_t aDestination) const
4048 {
4049     OT_UNUSED_VARIABLE(aDestination);
4050     return (mParent.IsStateValid()) ? mParent.GetRloc16() : static_cast<uint16_t>(Mac::kShortAddrInvalid);
4051 }
4052 
IsRoutingLocator(const Ip6::Address & aAddress) const4053 bool Mle::IsRoutingLocator(const Ip6::Address &aAddress) const
4054 {
4055     return IsMeshLocalAddress(aAddress) && aAddress.GetIid().IsRoutingLocator();
4056 }
4057 
IsAnycastLocator(const Ip6::Address & aAddress) const4058 bool Mle::IsAnycastLocator(const Ip6::Address &aAddress) const
4059 {
4060     return IsMeshLocalAddress(aAddress) && aAddress.GetIid().IsAnycastLocator();
4061 }
4062 
IsMeshLocalAddress(const Ip6::Address & aAddress) const4063 bool Mle::IsMeshLocalAddress(const Ip6::Address &aAddress) const
4064 {
4065     return (aAddress.GetPrefix() == GetMeshLocalPrefix());
4066 }
4067 
CheckReachability(uint16_t aMeshDest,Ip6::Header & aIp6Header)4068 Error Mle::CheckReachability(uint16_t aMeshDest, Ip6::Header &aIp6Header)
4069 {
4070     Error error;
4071 
4072     if ((aMeshDest != GetRloc16()) || Get<ThreadNetif>().HasUnicastAddress(aIp6Header.GetDestination()))
4073     {
4074         error = kErrorNone;
4075     }
4076     else
4077     {
4078         error = kErrorNoRoute;
4079     }
4080 
4081     return error;
4082 }
4083 
4084 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
InformPreviousParent(void)4085 void Mle::InformPreviousParent(void)
4086 {
4087     Error            error   = kErrorNone;
4088     Message *        message = nullptr;
4089     Ip6::MessageInfo messageInfo;
4090 
4091     VerifyOrExit((mPreviousParentRloc != Mac::kShortAddrInvalid) && (mPreviousParentRloc != mParent.GetRloc16()));
4092 
4093     mCounters.mParentChanges++;
4094 
4095     VerifyOrExit((message = Get<Ip6::Ip6>().NewMessage(0)) != nullptr, error = kErrorNoBufs);
4096     SuccessOrExit(error = message->SetLength(0));
4097 
4098     messageInfo.SetSockAddr(GetMeshLocal64());
4099     messageInfo.SetPeerAddr(GetMeshLocal16());
4100     messageInfo.GetPeerAddr().GetIid().SetLocator(mPreviousParentRloc);
4101 
4102     SuccessOrExit(error = Get<Ip6::Ip6>().SendDatagram(*message, messageInfo, Ip6::kProtoNone));
4103 
4104     otLogNoteMle("Sending message to inform previous parent 0x%04x", mPreviousParentRloc);
4105 
4106 exit:
4107 
4108     if (error != kErrorNone)
4109     {
4110         otLogWarnMle("Failed to inform previous parent: %s", ErrorToString(error));
4111 
4112         FreeMessage(message);
4113     }
4114 }
4115 #endif // OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
4116 
4117 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
HandleParentSearchTimer(Timer & aTimer)4118 void Mle::HandleParentSearchTimer(Timer &aTimer)
4119 {
4120     aTimer.Get<Mle>().HandleParentSearchTimer();
4121 }
4122 
HandleParentSearchTimer(void)4123 void Mle::HandleParentSearchTimer(void)
4124 {
4125     int8_t parentRss;
4126 
4127     otLogInfoMle("PeriodicParentSearch: %s interval passed", mParentSearchIsInBackoff ? "Backoff" : "Check");
4128 
4129     if (mParentSearchBackoffWasCanceled)
4130     {
4131         // Backoff can be canceled if the device switches to a new parent.
4132         // from `UpdateParentSearchState()`. We want to limit this to happen
4133         // only once within a backoff interval.
4134 
4135         if (TimerMilli::GetNow() - mParentSearchBackoffCancelTime >= kParentSearchBackoffInterval)
4136         {
4137             mParentSearchBackoffWasCanceled = false;
4138             otLogInfoMle("PeriodicParentSearch: Backoff cancellation is allowed on parent switch");
4139         }
4140     }
4141 
4142     mParentSearchIsInBackoff = false;
4143 
4144     VerifyOrExit(IsChild());
4145 
4146     parentRss = GetParent().GetLinkInfo().GetAverageRss();
4147     otLogInfoMle("PeriodicParentSearch: Parent RSS %d", parentRss);
4148     VerifyOrExit(parentRss != OT_RADIO_RSSI_INVALID);
4149 
4150     if (parentRss < kParentSearchRssThreadhold)
4151     {
4152         otLogInfoMle("PeriodicParentSearch: Parent RSS less than %d, searching for new parents",
4153                      kParentSearchRssThreadhold);
4154         mParentSearchIsInBackoff = true;
4155         IgnoreError(BecomeChild(kAttachAny));
4156     }
4157 
4158 exit:
4159     StartParentSearchTimer();
4160 }
4161 
StartParentSearchTimer(void)4162 void Mle::StartParentSearchTimer(void)
4163 {
4164     uint32_t interval;
4165 
4166     interval = Random::NonCrypto::GetUint32InRange(0, kParentSearchJitterInterval);
4167 
4168     if (mParentSearchIsInBackoff)
4169     {
4170         interval += kParentSearchBackoffInterval;
4171     }
4172     else
4173     {
4174         interval += kParentSearchCheckInterval;
4175     }
4176 
4177     mParentSearchTimer.Start(interval);
4178 
4179     otLogInfoMle("PeriodicParentSearch: (Re)starting timer for %s interval",
4180                  mParentSearchIsInBackoff ? "backoff" : "check");
4181 }
4182 
UpdateParentSearchState(void)4183 void Mle::UpdateParentSearchState(void)
4184 {
4185 #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
4186 
4187     // If we are in middle of backoff and backoff was not canceled
4188     // recently and we recently detached from a previous parent,
4189     // then we check if the new parent is different from the previous
4190     // one, and if so, we cancel the backoff mode and also remember
4191     // the backoff cancel time. This way the canceling of backoff
4192     // is allowed only once within a backoff window.
4193     //
4194     // The reason behind the canceling of the backoff is to handle
4195     // the scenario where a previous parent is not available for a
4196     // short duration (e.g., it is going through a software update)
4197     // and the child switches to a less desirable parent. With this
4198     // model the child will check for other parents sooner and have
4199     // the chance to switch back to the original (and possibly
4200     // preferred) parent more quickly.
4201 
4202     if (mParentSearchIsInBackoff && !mParentSearchBackoffWasCanceled && mParentSearchRecentlyDetached)
4203     {
4204         if ((mPreviousParentRloc != Mac::kShortAddrInvalid) && (mPreviousParentRloc != mParent.GetRloc16()))
4205         {
4206             mParentSearchIsInBackoff        = false;
4207             mParentSearchBackoffWasCanceled = true;
4208             mParentSearchBackoffCancelTime  = TimerMilli::GetNow();
4209             otLogInfoMle("PeriodicParentSearch: Canceling backoff on switching to a new parent");
4210         }
4211     }
4212 
4213 #endif // OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
4214 
4215     mParentSearchRecentlyDetached = false;
4216 
4217     if (!mParentSearchIsInBackoff)
4218     {
4219         StartParentSearchTimer();
4220     }
4221 }
4222 #endif // OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
4223 
4224 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
Log(MessageAction aAction,MessageType aType,const Ip6::Address & aAddress)4225 void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress)
4226 {
4227     Log(aAction, aType, aAddress, Mac::kShortAddrInvalid);
4228 }
4229 
Log(MessageAction aAction,MessageType aType,const Ip6::Address & aAddress,uint16_t aRloc)4230 void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAddress, uint16_t aRloc)
4231 {
4232     enum : uint8_t
4233     {
4234         kRlocStringSize = 17,
4235     };
4236 
4237     String<kRlocStringSize> rlocString;
4238 
4239     if (aRloc != Mac::kShortAddrInvalid)
4240     {
4241         rlocString.Append(",0x%04x", aRloc);
4242     }
4243 
4244     otLogInfoMle("%s %s%s (%s%s)", MessageActionToString(aAction), MessageTypeToString(aType),
4245                  MessageTypeActionToSuffixString(aType, aAction), aAddress.ToString().AsCString(),
4246                  rlocString.AsCString());
4247 }
4248 #endif
4249 
4250 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
LogProcessError(MessageType aType,Error aError)4251 void Mle::LogProcessError(MessageType aType, Error aError)
4252 {
4253     LogError(kMessageReceive, aType, aError);
4254 }
4255 
LogSendError(MessageType aType,Error aError)4256 void Mle::LogSendError(MessageType aType, Error aError)
4257 {
4258     LogError(kMessageSend, aType, aError);
4259 }
4260 
LogError(MessageAction aAction,MessageType aType,Error aError)4261 void Mle::LogError(MessageAction aAction, MessageType aType, Error aError)
4262 {
4263     if (aError != kErrorNone)
4264     {
4265         otLogWarnMle("Failed to %s %s%s: %s", aAction == kMessageSend ? "send" : "process", MessageTypeToString(aType),
4266                      MessageTypeActionToSuffixString(aType, aAction), ErrorToString(aError));
4267     }
4268 }
4269 
MessageActionToString(MessageAction aAction)4270 const char *Mle::MessageActionToString(MessageAction aAction)
4271 {
4272     static const char *const kMessageActionStrings[] = {
4273         "Send",           // (0) kMessageSend
4274         "Receive",        // (1) kMessageReceive
4275         "Delay",          // (2) kMessageDelay
4276         "Remove Delayed", // (3) kMessageRemoveDelayed
4277     };
4278 
4279     static_assert(kMessageSend == 0, "kMessageSend value is incorrect");
4280     static_assert(kMessageReceive == 1, "kMessageReceive value is incorrect");
4281     static_assert(kMessageDelay == 2, "kMessageDelay value is incorrect");
4282     static_assert(kMessageRemoveDelayed == 3, "kMessageRemoveDelayed value is incorrect");
4283 
4284     return kMessageActionStrings[aAction];
4285 }
4286 
MessageTypeToString(MessageType aType)4287 const char *Mle::MessageTypeToString(MessageType aType)
4288 {
4289     static const char *const kMessageTypeStrings[] = {
4290         "Advertisement",         // (0)  kTypeAdvertisement
4291         "Announce",              // (1)  kTypeAnnounce
4292         "Child ID Request",      // (2)  kTypeChildIdRequest
4293         "Child ID Request",      // (3)  kTypeChildIdRequestShort
4294         "Child ID Response",     // (4)  kTypeChildIdResponse
4295         "Child Update Request",  // (5)  kTypeChildUpdateRequestOfParent
4296         "Child Update Response", // (6)  kTypeChildUpdateResponseOfParent
4297         "Data Request",          // (7)  kTypeDataRequest
4298         "Data Response",         // (8)  kTypeDataResponse
4299         "Discovery Request",     // (9)  kTypeDiscoveryRequest
4300         "Discovery Response",    // (10) kTypeDiscoveryResponse
4301         "delayed message",       // (11) kTypeGenericDelayed
4302         "UDP",                   // (12) kTypeGenericUdp
4303         "Parent Request",        // (13) kTypeParentRequestToRouters
4304         "Parent Request",        // (14) kTypeParentRequestToRoutersReeds
4305         "Parent Response",       // (15) kTypeParentResponse
4306 #if OPENTHREAD_FTD
4307         "Address Release",         // (16) kTypeAddressRelease
4308         "Address Release Reply",   // (17) kTypeAddressReleaseReply
4309         "Address Reply",           // (18) kTypeAddressReply
4310         "Address Solicit",         // (19) kTypeAddressSolicit
4311         "Child Update Request",    // (20) kTypeChildUpdateRequestOfChild
4312         "Child Update Response",   // (21) kTypeChildUpdateResponseOfChild
4313         "Child Update Response",   // (22) kTypeChildUpdateResponseOfUnknownChild
4314         "Link Accept",             // (23) kTypeLinkAccept
4315         "Link Accept and Request", // (24) kTypeLinkAcceptAndRequest
4316         "Link Reject",             // (25) kTypeLinkReject
4317         "Link Request",            // (26) kTypeLinkRequest
4318         "Parent Request",          // (27) kTypeParentRequest
4319 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4320         "Time Sync", // (28) kTypeTimeSync
4321 #endif
4322 #endif
4323 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
4324         "Link Metrics Management Request",  // (29) kTypeLinkMetricsManagementRequest
4325         "Link Metrics Management Response", // (30) kTypeLinkMetricsManagementResponse
4326         "Link Probe",                       // (31) kTypeLinkProbe
4327 #endif
4328     };
4329 
4330     static_assert(kTypeAdvertisement == 0, "kTypeAdvertisement value is incorrect");
4331     static_assert(kTypeAnnounce == 1, "kTypeAnnounce value is incorrect");
4332     static_assert(kTypeChildIdRequest == 2, "kTypeChildIdRequest value is incorrect");
4333     static_assert(kTypeChildIdRequestShort == 3, "kTypeChildIdRequestShort value is incorrect");
4334     static_assert(kTypeChildIdResponse == 4, "kTypeChildIdResponse value is incorrect");
4335     static_assert(kTypeChildUpdateRequestOfParent == 5, "kTypeChildUpdateRequestOfParent value is incorrect");
4336     static_assert(kTypeChildUpdateResponseOfParent == 6, "kTypeChildUpdateResponseOfParent value is incorrect");
4337     static_assert(kTypeDataRequest == 7, "kTypeDataRequest value is incorrect");
4338     static_assert(kTypeDataResponse == 8, "kTypeDataResponse value is incorrect");
4339     static_assert(kTypeDiscoveryRequest == 9, "kTypeDiscoveryRequest value is incorrect");
4340     static_assert(kTypeDiscoveryResponse == 10, "kTypeDiscoveryResponse value is incorrect");
4341     static_assert(kTypeGenericDelayed == 11, "kTypeGenericDelayed value is incorrect");
4342     static_assert(kTypeGenericUdp == 12, "kTypeGenericUdp value is incorrect");
4343     static_assert(kTypeParentRequestToRouters == 13, "kTypeParentRequestToRouters value is incorrect");
4344     static_assert(kTypeParentRequestToRoutersReeds == 14, "kTypeParentRequestToRoutersReeds value is incorrect");
4345     static_assert(kTypeParentResponse == 15, "kTypeParentResponse value is incorrect");
4346 #if OPENTHREAD_FTD
4347     static_assert(kTypeAddressRelease == 16, "kTypeAddressRelease value is incorrect");
4348     static_assert(kTypeAddressReleaseReply == 17, "kTypeAddressReleaseReply value is incorrect");
4349     static_assert(kTypeAddressReply == 18, "kTypeAddressReply value is incorrect");
4350     static_assert(kTypeAddressSolicit == 19, "kTypeAddressSolicit value is incorrect");
4351     static_assert(kTypeChildUpdateRequestOfChild == 20, "kTypeChildUpdateRequestOfChild value is incorrect");
4352     static_assert(kTypeChildUpdateResponseOfChild == 21, "kTypeChildUpdateResponseOfChild value is incorrect");
4353     static_assert(kTypeChildUpdateResponseOfUnknownChild == 22, "kTypeChildUpdateResponseOfUnknownChild is incorrect");
4354     static_assert(kTypeLinkAccept == 23, "kTypeLinkAccept value is incorrect");
4355     static_assert(kTypeLinkAcceptAndRequest == 24, "kTypeLinkAcceptAndRequest value is incorrect");
4356     static_assert(kTypeLinkReject == 25, "kTypeLinkReject value is incorrect");
4357     static_assert(kTypeLinkRequest == 26, "kTypeLinkRequest value is incorrect");
4358     static_assert(kTypeParentRequest == 27, "kTypeParentRequest value is incorrect");
4359 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4360     static_assert(kTypeTimeSync == 28, "kTypeTimeSync value is incorrect");
4361 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
4362     static_assert(kTypeLinkMetricsManagementRequest == 29, "kTypeLinkMetricsManagementRequest value is incorrect)");
4363     static_assert(kTypeLinkMetricsManagementResponse == 30, "kTypeLinkMetricsManagementResponse value is incorrect)");
4364     static_assert(kTypeLinkProbe == 31, "kTypeLinkProbe value is incorrect)");
4365 #endif
4366 #else // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4367 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
4368     static_assert(kTypeLinkMetricsManagementRequest == 28, "kTypeLinkMetricsManagementRequest value is incorrect)");
4369     static_assert(kTypeLinkMetricsManagementResponse == 29, "kTypeLinkMetricsManagementResponse value is incorrect)");
4370     static_assert(kTypeLinkProbe == 30, "kTypeLinkProbe value is incorrect)");
4371 #endif
4372 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
4373 #else  // OPENTHREAD_FTD
4374 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
4375     static_assert(kTypeLinkMetricsManagementRequest == 16, "kTypeLinkMetricsManagementRequest value is incorrect)");
4376     static_assert(kTypeLinkMetricsManagementResponse == 17, "kTypeLinkMetricsManagementResponse value is incorrect)");
4377     static_assert(kTypeLinkProbe == 18, "kTypeLinkProbe value is incorrect)");
4378 #endif
4379 #endif // OPENTHREAD_FTD
4380 
4381     return kMessageTypeStrings[aType];
4382 }
4383 
MessageTypeActionToSuffixString(MessageType aType,MessageAction aAction)4384 const char *Mle::MessageTypeActionToSuffixString(MessageType aType, MessageAction aAction)
4385 {
4386     const char *str = "";
4387 
4388     switch (aType)
4389     {
4390     case kTypeChildIdRequestShort:
4391         str = " - short";
4392         break;
4393     case kTypeChildUpdateRequestOfParent:
4394     case kTypeChildUpdateResponseOfParent:
4395         str = (aAction == kMessageReceive) ? " from parent" : " to parent";
4396         break;
4397     case kTypeParentRequestToRouters:
4398         str = " to routers";
4399         break;
4400     case kTypeParentRequestToRoutersReeds:
4401         str = " to routers and REEDs";
4402         break;
4403 #if OPENTHREAD_FTD
4404     case kTypeChildUpdateRequestOfChild:
4405     case kTypeChildUpdateResponseOfChild:
4406         str = (aAction == kMessageReceive) ? " from child" : " to child";
4407         break;
4408     case kTypeChildUpdateResponseOfUnknownChild:
4409         str = (aAction == kMessageReceive) ? " from unknown child" : " to child";
4410         break;
4411 #endif // OPENTHREAD_FTD
4412     default:
4413         break;
4414     }
4415 
4416     return str;
4417 }
4418 
4419 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
4420 
RoleToString(DeviceRole aRole)4421 const char *Mle::RoleToString(DeviceRole aRole)
4422 {
4423     static const char *const kRoleStrings[] = {
4424         "disabled", // (0) kRoleDisabled
4425         "detached", // (1) kRoleDetached
4426         "child",    // (2) kRoleChild
4427         "router",   // (3) kRoleRouter
4428         "leader",   // (4) kRoleLeader
4429     };
4430 
4431     static_assert(kRoleDisabled == 0, "kRoleDisabled value is incorrect");
4432     static_assert(kRoleDetached == 1, "kRoleDetached value is incorrect");
4433     static_assert(kRoleChild == 2, "kRoleChild value is incorrect");
4434     static_assert(kRoleRouter == 3, "kRoleRouter value is incorrect");
4435     static_assert(kRoleLeader == 4, "kRoleLeader value is incorrect");
4436 
4437     return (aRole <= OT_ARRAY_LENGTH(kRoleStrings)) ? kRoleStrings[aRole] : "invalid";
4438 }
4439 
4440 // LCOV_EXCL_START
4441 
4442 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
4443 
AttachModeToString(AttachMode aMode)4444 const char *Mle::AttachModeToString(AttachMode aMode)
4445 {
4446     static const char *const kAttachModeStrings[] = {
4447         "any-partition",            // (0) kAttachAny
4448         "same-partition-try-1",     // (1) kAttachSame1
4449         "same-partition-try-2",     // (2) kAttachSame2
4450         "better-partition",         // (3) kAttachBetter
4451         "same-partition-downgrade", // (4) kAttachSameDowngrade
4452     };
4453 
4454     static_assert(kAttachAny == 0, "kAttachAny value is incorrect");
4455     static_assert(kAttachSame1 == 1, "kAttachSame1 value is incorrect");
4456     static_assert(kAttachSame2 == 2, "kAttachSame2 value is incorrect");
4457     static_assert(kAttachBetter == 3, "kAttachBetter value is incorrect");
4458     static_assert(kAttachSameDowngrade == 4, "kAttachSameDowngrade value is incorrect");
4459 
4460     return kAttachModeStrings[aMode];
4461 }
4462 
AttachStateToString(AttachState aState)4463 const char *Mle::AttachStateToString(AttachState aState)
4464 {
4465     static const char *const kAttachStateStrings[] = {
4466         "Idle",             // (0) kAttachStateIdle
4467         "ProcessAnnounce",  // (1) kAttachStateProcessAnnounce
4468         "Start",            // (2) kAttachStateStart
4469         "ParentReqRouters", // (3) kAttachStateParentRequestRouter
4470         "ParentReqReeds",   // (4) kAttachStateParentRequestReed
4471         "Announce",         // (5) kAttachStateAnnounce
4472         "ChildIdReq",       // (6) kAttachStateChildIdRequest
4473     };
4474 
4475     static_assert(kAttachStateIdle == 0, "kAttachStateIdle value is incorrect");
4476     static_assert(kAttachStateProcessAnnounce == 1, "kAttachStateProcessAnnounce value is incorrect");
4477     static_assert(kAttachStateStart == 2, "kAttachStateStart value is incorrect");
4478     static_assert(kAttachStateParentRequestRouter == 3, "kAttachStateParentRequestRouter value is incorrect");
4479     static_assert(kAttachStateParentRequestReed == 4, "kAttachStateParentRequestReed value is incorrect");
4480     static_assert(kAttachStateAnnounce == 5, "kAttachStateAnnounce value is incorrect");
4481     static_assert(kAttachStateChildIdRequest == 6, "kAttachStateChildIdRequest value is incorrect");
4482 
4483     return kAttachStateStrings[aState];
4484 }
4485 
ReattachStateToString(ReattachState aState)4486 const char *Mle::ReattachStateToString(ReattachState aState)
4487 {
4488     static const char *const kReattachStateStrings[] = {
4489         "",                                 // (0) kReattachStop
4490         "reattaching",                      // (1) kReattachStart
4491         "reattaching with Active Dataset",  // (2) kReattachActive
4492         "reattaching with Pending Dataset", // (3) kReattachPending
4493     };
4494 
4495     static_assert(kReattachStop == 0, "kReattachStop value is incorrect");
4496     static_assert(kReattachStart == 1, "kReattachStart value is incorrect");
4497     static_assert(kReattachActive == 2, "kReattachActive value is incorrect");
4498     static_assert(kReattachPending == 3, "kReattachPending value is incorrect");
4499 
4500     return kReattachStateStrings[aState];
4501 }
4502 
4503 #endif // (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
4504 
4505 // LCOV_EXCL_STOP
4506 
4507 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
SendLinkMetricsManagementRequest(const Ip6::Address & aDestination,const uint8_t * aSubTlvs,uint8_t aLength)4508 Error Mle::SendLinkMetricsManagementRequest(const Ip6::Address &aDestination, const uint8_t *aSubTlvs, uint8_t aLength)
4509 {
4510     Error    error = kErrorNone;
4511     Message *message;
4512     Tlv      tlv;
4513 
4514     VerifyOrExit((message = NewMleMessage()) != nullptr, error = kErrorNoBufs);
4515     SuccessOrExit(error = AppendHeader(*message, kCommandLinkMetricsManagementRequest));
4516 
4517     // Link Metrics Management TLV
4518     tlv.SetType(Tlv::kLinkMetricsManagement);
4519     tlv.SetLength(aLength);
4520 
4521     SuccessOrExit(error = message->AppendBytes(&tlv, sizeof(tlv)));
4522     SuccessOrExit(error = message->AppendBytes(aSubTlvs, aLength));
4523 
4524     SuccessOrExit(error = SendMessage(*message, aDestination));
4525 
4526 exit:
4527     FreeMessageOnError(message, error);
4528     return error;
4529 }
4530 #endif
4531 
RegisterParentResponseStatsCallback(otThreadParentResponseCallback aCallback,void * aContext)4532 void Mle::RegisterParentResponseStatsCallback(otThreadParentResponseCallback aCallback, void *aContext)
4533 {
4534     mParentResponseCb        = aCallback;
4535     mParentResponseCbContext = aContext;
4536 }
4537 
4538 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
CalcParentCslMetric(uint8_t aCslClockAccuracy,uint8_t aCslUncertainty)4539 uint64_t Mle::CalcParentCslMetric(uint8_t aCslClockAccuracy, uint8_t aCslUncertainty)
4540 {
4541     /*
4542      * This function calculates the overall time that device will operate on battery
4543      * by summming sequence of "ON quants" over a period of time.
4544      */
4545     const uint64_t usInSecond   = 1000000;
4546     uint64_t       cslPeriodUs  = kMinCslPeriod * kUsPerTenSymbols;
4547     uint64_t       cslTimeoutUs = GetCslTimeout() * usInSecond;
4548     uint64_t       k            = cslTimeoutUs / cslPeriodUs;
4549 
4550     return k * (k + 1) * cslPeriodUs / usInSecond * aCslClockAccuracy + aCslUncertainty * k * kUsPerUncertUnit;
4551 }
4552 #endif
4553 
GenerateRandom(void)4554 void Mle::Challenge::GenerateRandom(void)
4555 {
4556     mLength = kMaxChallengeSize;
4557     IgnoreError(Random::Crypto::FillBuffer(mBuffer, mLength));
4558 }
4559 
Matches(const uint8_t * aBuffer,uint8_t aLength) const4560 bool Mle::Challenge::Matches(const uint8_t *aBuffer, uint8_t aLength) const
4561 {
4562     return (mLength == aLength) && (memcmp(mBuffer, aBuffer, aLength) == 0);
4563 }
4564 
ReadFrom(const Message & aMessage)4565 void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage)
4566 {
4567     uint16_t length = aMessage.GetLength();
4568 
4569     OT_ASSERT(length >= sizeof(*this));
4570     IgnoreError(aMessage.Read(length - sizeof(*this), *this));
4571 }
4572 
RemoveFrom(Message & aMessage) const4573 void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const
4574 {
4575     Error error = aMessage.SetLength(aMessage.GetLength() - sizeof(*this));
4576     OT_ASSERT(error == kErrorNone);
4577     OT_UNUSED_VARIABLE(error);
4578 }
4579 
4580 } // namespace Mle
4581 } // namespace ot
4582