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