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