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