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