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