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(×tamp, 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