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