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