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