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