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