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