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