Coverage Report

Created: 2025-05-12 06:47

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