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