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