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