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