1 /*
2 * Copyright (c) 2016, The OpenThread Authors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * 1. Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * 3. Neither the name of the copyright holder nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /**
29 * @file
30 * This file implements MLE functionality required for the Thread Router and Leader roles.
31 */
32
33 #include "mle_router.hpp"
34
35 #if OPENTHREAD_FTD
36
37 #include "instance/instance.hpp"
38
39 namespace ot {
40 namespace Mle {
41
42 RegisterLogModule("Mle");
43
MleRouter(Instance & aInstance)44 MleRouter::MleRouter(Instance &aInstance)
45 : Mle(aInstance)
46 , mRouterEligible(true)
47 , mAddressSolicitPending(false)
48 , mAddressSolicitRejected(false)
49 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
50 , mCcmEnabled(false)
51 , mThreadVersionCheckEnabled(true)
52 #endif
53 , mNetworkIdTimeout(kNetworkIdTimeout)
54 , mRouterUpgradeThreshold(kRouterUpgradeThreshold)
55 , mRouterDowngradeThreshold(kRouterDowngradeThreshold)
56 , mPreviousPartitionRouterIdSequence(0)
57 , mPreviousPartitionIdTimeout(0)
58 , mChildRouterLinks(kChildRouterLinks)
59 , mAlternateRloc16Timeout(0)
60 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
61 , mMaxChildIpAddresses(0)
62 #endif
63 , mParentPriority(kParentPriorityUnspecified)
64 , mNextChildId(kMaxChildId)
65 , mPreviousPartitionIdRouter(0)
66 , mPreviousPartitionId(0)
67 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
68 , mPreferredLeaderPartitionId(0)
69 #endif
70 , mAdvertiseTrickleTimer(aInstance, MleRouter::HandleAdvertiseTrickleTimer)
71 , mChildTable(aInstance)
72 , mRouterTable(aInstance)
73 , mRouterRoleRestorer(aInstance)
74 {
75 mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData);
76
77 #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
78 mLeaderWeight = mDeviceProperties.CalculateLeaderWeight();
79 #else
80 mLeaderWeight = kDefaultLeaderWeight;
81 #endif
82
83 mLeaderAloc.InitAsThreadOriginMeshLocal();
84
85 SetRouterId(kInvalidRouterId);
86
87 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
88 mSteeringData.Clear();
89 #endif
90 }
91
SetAlternateRloc16(uint16_t aRloc16)92 void MleRouter::SetAlternateRloc16(uint16_t aRloc16)
93 {
94 VerifyOrExit(aRloc16 != Mac::kShortAddrInvalid);
95
96 LogInfo("Setting alternate RLOC16 0x%04x", aRloc16);
97
98 Get<Mac::Mac>().SetAlternateShortAddress(aRloc16);
99 mAlternateRloc16Timeout = kAlternateRloc16Timeout;
100
101 exit:
102 return;
103 }
104
ClearAlternateRloc16(void)105 void MleRouter::ClearAlternateRloc16(void)
106 {
107 VerifyOrExit(Get<Mac::Mac>().GetAlternateShortAddress() != Mac::kShortAddrInvalid);
108
109 LogInfo("Clearing alternate RLOC16");
110 Get<Mac::Mac>().SetAlternateShortAddress(Mac::kShortAddrInvalid);
111
112 exit:
113 mAlternateRloc16Timeout = 0;
114 }
115
HandlePartitionChange(void)116 void MleRouter::HandlePartitionChange(void)
117 {
118 mPreviousPartitionId = mLeaderData.GetPartitionId();
119 mPreviousPartitionRouterIdSequence = mRouterTable.GetRouterIdSequence();
120 mPreviousPartitionIdTimeout = GetNetworkIdTimeout();
121
122 Get<AddressResolver>().Clear();
123 IgnoreError(Get<Tmf::Agent>().AbortTransaction(&MleRouter::HandleAddressSolicitResponse, this));
124 mRouterTable.Clear();
125 }
126
IsRouterEligible(void) const127 bool MleRouter::IsRouterEligible(void) const
128 {
129 bool rval = false;
130 const SecurityPolicy &secPolicy = Get<KeyManager>().GetSecurityPolicy();
131
132 VerifyOrExit(mRouterEligible && IsFullThreadDevice());
133
134 #if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
135 VerifyOrExit(secPolicy.mRoutersEnabled);
136 #else
137 if (secPolicy.mCommercialCommissioningEnabled)
138 {
139 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
140 VerifyOrExit(mCcmEnabled || secPolicy.mNonCcmRoutersEnabled);
141 #else
142 VerifyOrExit(secPolicy.mNonCcmRoutersEnabled);
143 #endif
144 }
145 if (!secPolicy.mRoutersEnabled)
146 {
147 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
148 VerifyOrExit(!mThreadVersionCheckEnabled ||
149 secPolicy.mVersionThresholdForRouting + SecurityPolicy::kVersionThresholdOffsetVersion <=
150 kThreadVersion);
151 #else
152 VerifyOrExit(secPolicy.mVersionThresholdForRouting + SecurityPolicy::kVersionThresholdOffsetVersion <=
153 kThreadVersion);
154 #endif
155 }
156 #endif
157
158 rval = true;
159
160 exit:
161 return rval;
162 }
163
SetRouterEligible(bool aEligible)164 Error MleRouter::SetRouterEligible(bool aEligible)
165 {
166 Error error = kErrorNone;
167
168 if (!IsFullThreadDevice())
169 {
170 VerifyOrExit(!aEligible, error = kErrorNotCapable);
171 }
172
173 VerifyOrExit(aEligible != mRouterEligible);
174
175 mRouterEligible = aEligible;
176
177 switch (mRole)
178 {
179 case kRoleDisabled:
180 case kRoleDetached:
181 break;
182
183 case kRoleChild:
184 if (mRouterEligible)
185 {
186 mRouterRoleTransition.StartTimeout();
187 }
188
189 Get<Mac::Mac>().SetBeaconEnabled(mRouterEligible);
190 break;
191
192 case kRoleRouter:
193 case kRoleLeader:
194 if (!mRouterEligible)
195 {
196 IgnoreError(BecomeDetached());
197 }
198
199 break;
200 }
201
202 exit:
203 return error;
204 }
205
HandleSecurityPolicyChanged(void)206 void MleRouter::HandleSecurityPolicyChanged(void)
207 {
208 // If we are currently router or leader and no longer eligible to
209 // be a router (due to security policy change), we start jitter
210 // timeout to downgrade.
211
212 VerifyOrExit(IsRouterOrLeader() && !IsRouterEligible());
213
214 VerifyOrExit(!mRouterRoleTransition.IsPending());
215
216 mRouterRoleTransition.StartTimeout();
217
218 if (IsLeader())
219 {
220 mRouterRoleTransition.IncreaseTimeout(kLeaderDowngradeExtraDelay);
221 }
222
223 exit:
224 return;
225 }
226
227 #if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
SetDeviceProperties(const DeviceProperties & aDeviceProperties)228 void MleRouter::SetDeviceProperties(const DeviceProperties &aDeviceProperties)
229 {
230 mDeviceProperties = aDeviceProperties;
231 mDeviceProperties.ClampWeightAdjustment();
232 SetLeaderWeight(mDeviceProperties.CalculateLeaderWeight());
233 }
234 #endif
235
BecomeRouter(ThreadStatusTlv::Status aStatus)236 Error MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
237 {
238 Error error = kErrorNone;
239
240 VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
241 VerifyOrExit(!IsRouterOrLeader(), error = kErrorNone);
242 VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
243
244 LogInfo("Attempt to become router");
245
246 Get<MeshForwarder>().SetRxOnWhenIdle(true);
247 mRouterRoleTransition.StopTimeout();
248
249 switch (mRole)
250 {
251 case kRoleDetached:
252 mRouterRoleRestorer.Start(mLastSavedRole);
253 break;
254
255 case kRoleChild:
256 SuccessOrExit(error = SendAddressSolicit(aStatus));
257 break;
258
259 default:
260 OT_ASSERT(false);
261 }
262
263 exit:
264 return error;
265 }
266
BecomeLeader(bool aCheckWeight)267 Error MleRouter::BecomeLeader(bool aCheckWeight)
268 {
269 Error error = kErrorNone;
270 Router *router;
271 uint32_t partitionId;
272 uint8_t leaderId;
273
274 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
275 VerifyOrExit(!Get<MeshCoP::ActiveDatasetManager>().IsPartiallyComplete(), error = kErrorInvalidState);
276 #else
277 VerifyOrExit(Get<MeshCoP::ActiveDatasetManager>().IsComplete(), error = kErrorInvalidState);
278 #endif
279 VerifyOrExit(!IsDisabled(), error = kErrorInvalidState);
280 VerifyOrExit(!IsLeader(), error = kErrorNone);
281 VerifyOrExit(IsRouterEligible(), error = kErrorNotCapable);
282
283 if (aCheckWeight && IsAttached())
284 {
285 VerifyOrExit(mLeaderWeight > mLeaderData.GetWeighting(), error = kErrorNotCapable);
286 }
287
288 mRouterTable.Clear();
289
290 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
291 {
292 uint8_t minId;
293 uint8_t maxId;
294
295 mRouterTable.GetRouterIdRange(minId, maxId);
296 partitionId = mPreferredLeaderPartitionId ? mPreferredLeaderPartitionId : Random::NonCrypto::GetUint32();
297 leaderId = (IsRouterIdValid(mPreviousRouterId) && minId <= mPreviousRouterId && mPreviousRouterId <= maxId)
298 ? mPreviousRouterId
299 : Random::NonCrypto::GetUint8InRange(minId, maxId + 1);
300 }
301 #else
302 partitionId = Random::NonCrypto::GetUint32();
303 leaderId = IsRouterIdValid(mPreviousRouterId) ? mPreviousRouterId
304 : Random::NonCrypto::GetUint8InRange(0, kMaxRouterId + 1);
305 #endif
306
307 SetLeaderData(partitionId, mLeaderWeight, leaderId);
308
309 router = mRouterTable.Allocate(leaderId);
310 OT_ASSERT(router != nullptr);
311
312 SetRouterId(leaderId);
313 router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
314
315 Get<NetworkData::Leader>().Reset();
316 Get<MeshCoP::Leader>().SetEmptyCommissionerData();
317
318 SetStateLeader(Rloc16FromRouterId(leaderId), kStartingAsLeader);
319
320 exit:
321 return error;
322 }
323
StopLeader(void)324 void MleRouter::StopLeader(void)
325 {
326 StopAdvertiseTrickleTimer();
327 Get<ThreadNetif>().UnsubscribeAllRoutersMulticast();
328 }
329
HandleDetachStart(void)330 void MleRouter::HandleDetachStart(void)
331 {
332 mRouterTable.ClearNeighbors();
333 StopLeader();
334 Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter);
335 }
336
HandleChildStart(AttachMode aMode)337 void MleRouter::HandleChildStart(AttachMode aMode)
338 {
339 mAddressSolicitRejected = false;
340
341 mRouterRoleTransition.StartTimeout();
342
343 StopLeader();
344 Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
345
346 if (mRouterEligible)
347 {
348 Get<Mac::Mac>().SetBeaconEnabled(true);
349 }
350
351 Get<ThreadNetif>().SubscribeAllRoutersMulticast();
352
353 VerifyOrExit(IsRouterIdValid(mPreviousRouterId));
354
355 switch (aMode)
356 {
357 case kDowngradeToReed:
358 SendAddressRelease();
359
360 if (HasChildren())
361 {
362 RemoveChildren();
363 }
364
365 SetRouterId(kInvalidRouterId);
366 break;
367
368 case kSamePartition:
369 if (HasChildren())
370 {
371 IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
372 }
373
374 break;
375
376 case kAnyPartition:
377 case kBetterParent:
378 case kSelectedParent:
379 // If attach was initiated due to receiving an MLE Announce
380 // message, all rx-on-when-idle devices will immediately
381 // attempt to attach as well. This aligns with the Thread 1.1
382 // specification (Section 4.8.1):
383 //
384 // "If the received value is newer and the channel and/or PAN
385 // ID in the Announce message differ from those currently in
386 // use, the receiving device attempts to attach using the
387 // channel and PAN ID received from the Announce message."
388 //
389 // Since parent-child relationships are unlikely to persist in
390 // the new partition, we remove all children here. The
391 // decision to become router is determined based on the new
392 // partition's status.
393
394 if (IsAnnounceAttach() && HasChildren())
395 {
396 RemoveChildren();
397 }
398
399 OT_FALL_THROUGH;
400
401 case kBetterPartition:
402 if (HasChildren() && mPreviousPartitionIdRouter != mLeaderData.GetPartitionId())
403 {
404 IgnoreError(BecomeRouter(ThreadStatusTlv::kParentPartitionChange));
405 }
406
407 break;
408 }
409
410 exit:
411
412 if (mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold &&
413 (!IsRouterIdValid(mPreviousRouterId) || !HasChildren()))
414 {
415 SetRouterId(kInvalidRouterId);
416 }
417 }
418
SetStateRouter(uint16_t aRloc16)419 void MleRouter::SetStateRouter(uint16_t aRloc16)
420 {
421 // The `aStartMode` is ignored when used with `kRoleRouter`
422 SetStateRouterOrLeader(kRoleRouter, aRloc16, /* aStartMode */ kStartingAsLeader);
423 }
424
SetStateLeader(uint16_t aRloc16,LeaderStartMode aStartMode)425 void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
426 {
427 SetStateRouterOrLeader(kRoleLeader, aRloc16, aStartMode);
428 }
429
SetStateRouterOrLeader(DeviceRole aRole,uint16_t aRloc16,LeaderStartMode aStartMode)430 void MleRouter::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStartMode aStartMode)
431 {
432 if (aRole == kRoleLeader)
433 {
434 IgnoreError(Get<MeshCoP::ActiveDatasetManager>().Restore());
435 IgnoreError(Get<MeshCoP::PendingDatasetManager>().Restore());
436 }
437
438 SetRloc16(aRloc16);
439
440 SetRole(aRole);
441
442 SetAttachState(kAttachStateIdle);
443 mAttachCounter = 0;
444 mAttachTimer.Stop();
445 mMessageTransmissionTimer.Stop();
446 StopAdvertiseTrickleTimer();
447 ResetAdvertiseInterval();
448
449 Get<ThreadNetif>().SubscribeAllRoutersMulticast();
450 mPreviousPartitionIdRouter = mLeaderData.GetPartitionId();
451 Get<Mac::Mac>().SetBeaconEnabled(true);
452 Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
453
454 if (aRole == kRoleLeader)
455 {
456 GetLeaderAloc(mLeaderAloc.GetAddress());
457 Get<ThreadNetif>().AddUnicastAddress(mLeaderAloc);
458 Get<NetworkData::Leader>().Start(aStartMode);
459 Get<MeshCoP::ActiveDatasetManager>().StartLeader();
460 Get<MeshCoP::PendingDatasetManager>().StartLeader();
461 Get<AddressResolver>().Clear();
462 }
463
464 // Remove children that do not have a matching RLOC16
465 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
466 {
467 if (RouterIdFromRloc16(child.GetRloc16()) != mRouterId)
468 {
469 RemoveNeighbor(child);
470 }
471 }
472
473 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
474 Get<Mac::Mac>().UpdateCsl();
475 #endif
476
477 LogNote("Partition ID 0x%lx", ToUlong(mLeaderData.GetPartitionId()));
478 }
479
HandleAdvertiseTrickleTimer(TrickleTimer & aTimer)480 void MleRouter::HandleAdvertiseTrickleTimer(TrickleTimer &aTimer)
481 {
482 aTimer.Get<MleRouter>().HandleAdvertiseTrickleTimer();
483 }
484
HandleAdvertiseTrickleTimer(void)485 void MleRouter::HandleAdvertiseTrickleTimer(void)
486 {
487 VerifyOrExit(IsRouterEligible(), mAdvertiseTrickleTimer.Stop());
488
489 SendMulticastAdvertisement();
490
491 exit:
492 return;
493 }
494
StopAdvertiseTrickleTimer(void)495 void MleRouter::StopAdvertiseTrickleTimer(void) { mAdvertiseTrickleTimer.Stop(); }
496
DetermineAdvertiseIntervalMax(void) const497 uint32_t MleRouter::DetermineAdvertiseIntervalMax(void) const
498 {
499 uint32_t interval;
500
501 #if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
502 interval = kAdvIntervalMaxLogRoutes;
503 #else
504 // Determine the interval based on the number of router neighbors
505 // with link quality 2 or higher.
506
507 interval = (Get<RouterTable>().GetNeighborCount(kLinkQuality2) + 1) * kAdvIntervalNeighborMultiplier;
508 interval = Clamp(interval, kAdvIntervalMaxLowerBound, kAdvIntervalMaxUpperBound);
509 #endif
510
511 return interval;
512 }
513
UpdateAdvertiseInterval(void)514 void MleRouter::UpdateAdvertiseInterval(void)
515 {
516 if (IsRouterOrLeader() && mAdvertiseTrickleTimer.IsRunning())
517 {
518 mAdvertiseTrickleTimer.SetIntervalMax(DetermineAdvertiseIntervalMax());
519 }
520 }
521
ResetAdvertiseInterval(void)522 void MleRouter::ResetAdvertiseInterval(void)
523 {
524 VerifyOrExit(IsRouterOrLeader());
525
526 if (!mAdvertiseTrickleTimer.IsRunning())
527 {
528 mAdvertiseTrickleTimer.Start(TrickleTimer::kModeTrickle, kAdvIntervalMin, DetermineAdvertiseIntervalMax());
529 }
530
531 mAdvertiseTrickleTimer.IndicateInconsistent();
532
533 exit:
534 return;
535 }
536
SendMulticastAdvertisement(void)537 void MleRouter::SendMulticastAdvertisement(void)
538 {
539 Ip6::Address destination;
540
541 destination.SetToLinkLocalAllNodesMulticast();
542 SendAdvertisement(destination);
543 }
544
ScheduleUnicastAdvertisementTo(const Router & aRouter)545 void MleRouter::ScheduleUnicastAdvertisementTo(const Router &aRouter)
546 {
547 Ip6::Address destination;
548
549 destination.SetToLinkLocalAddress(aRouter.GetExtAddress());
550 mDelayedSender.ScheduleAdvertisement(destination,
551 Random::NonCrypto::GetUint32InRange(0, kMaxUnicastAdvertisementDelay));
552 }
553
SendAdvertisement(const Ip6::Address & aDestination)554 void MleRouter::SendAdvertisement(const Ip6::Address &aDestination)
555 {
556 Error error = kErrorNone;
557 TxMessage *message = nullptr;
558
559 // Suppress MLE Advertisements when trying to attach to a better
560 // partition. Without this, a candidate parent might incorrectly
561 // interpret this advertisement (Source Address TLV containing an
562 // RLOC16 indicating device is acting as router) and reject the
563 // attaching device.
564
565 VerifyOrExit(!IsAttaching());
566
567 // Suppress MLE Advertisements when attempting to transition to
568 // router role. Advertisements as a REED while attaching to a new
569 // partition can cause existing children to detach
570 // unnecessarily.
571
572 VerifyOrExit(!mAddressSolicitPending);
573
574 VerifyOrExit((message = NewMleMessage(kCommandAdvertisement)) != nullptr, error = kErrorNoBufs);
575 SuccessOrExit(error = message->AppendSourceAddressTlv());
576 SuccessOrExit(error = message->AppendLeaderDataTlv());
577
578 switch (mRole)
579 {
580 case kRoleChild:
581 break;
582
583 case kRoleRouter:
584 case kRoleLeader:
585 SuccessOrExit(error = message->AppendRouteTlv());
586 break;
587
588 case kRoleDisabled:
589 case kRoleDetached:
590 OT_ASSERT(false);
591 }
592
593 SuccessOrExit(error = message->SendTo(aDestination));
594
595 Log(kMessageSend, kTypeAdvertisement, aDestination);
596
597 exit:
598 FreeMessageOnError(message, error);
599 LogSendError(kTypeAdvertisement, error);
600 }
601
SendLinkRequest(Router * aRouter)602 void MleRouter::SendLinkRequest(Router *aRouter)
603 {
604 static const uint8_t kDetachedTlvs[] = {Tlv::kAddress16, Tlv::kRoute};
605 static const uint8_t kRouterTlvs[] = {Tlv::kLinkMargin};
606 static const uint8_t kValidNeighborTlvs[] = {Tlv::kLinkMargin, Tlv::kRoute};
607
608 Error error = kErrorNone;
609 TxMessage *message = nullptr;
610 Ip6::Address destination;
611
612 destination.Clear();
613
614 VerifyOrExit((message = NewMleMessage(kCommandLinkRequest)) != nullptr, error = kErrorNoBufs);
615 SuccessOrExit(error = message->AppendVersionTlv());
616
617 switch (mRole)
618 {
619 case kRoleDetached:
620 SuccessOrExit(error = message->AppendTlvRequestTlv(kDetachedTlvs));
621 break;
622
623 case kRoleChild:
624 SuccessOrExit(error = message->AppendSourceAddressTlv());
625 SuccessOrExit(error = message->AppendLeaderDataTlv());
626 break;
627
628 case kRoleRouter:
629 case kRoleLeader:
630 if (aRouter == nullptr || !aRouter->IsStateValid())
631 {
632 SuccessOrExit(error = message->AppendTlvRequestTlv(kRouterTlvs));
633 }
634 else
635 {
636 SuccessOrExit(error = message->AppendTlvRequestTlv(kValidNeighborTlvs));
637 }
638
639 SuccessOrExit(error = message->AppendSourceAddressTlv());
640 SuccessOrExit(error = message->AppendLeaderDataTlv());
641 break;
642
643 case kRoleDisabled:
644 OT_ASSERT(false);
645 }
646
647 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
648 SuccessOrExit(error = message->AppendTimeRequestTlv());
649 #endif
650
651 if (aRouter == nullptr)
652 {
653 mRouterRoleRestorer.GenerateRandomChallenge();
654 SuccessOrExit(error = message->AppendChallengeTlv(mRouterRoleRestorer.GetChallenge()));
655 destination.SetToLinkLocalAllRoutersMulticast();
656 }
657 else
658 {
659 if (!aRouter->IsStateValid())
660 {
661 aRouter->GenerateChallenge();
662 SuccessOrExit(error = message->AppendChallengeTlv(aRouter->GetChallenge()));
663 }
664 else
665 {
666 TxChallenge challenge;
667
668 challenge.GenerateRandom();
669 SuccessOrExit(error = message->AppendChallengeTlv(challenge));
670 }
671
672 destination.SetToLinkLocalAddress(aRouter->GetExtAddress());
673 aRouter->RestartLinkAcceptTimeout();
674 }
675
676 SuccessOrExit(error = message->SendTo(destination));
677
678 Log(kMessageSend, kTypeLinkRequest, destination);
679
680 exit:
681 FreeMessageOnError(message, error);
682 }
683
HandleLinkRequest(RxInfo & aRxInfo)684 void MleRouter::HandleLinkRequest(RxInfo &aRxInfo)
685 {
686 Error error = kErrorNone;
687 Neighbor *neighbor = nullptr;
688 uint16_t version;
689 LeaderData leaderData;
690 uint16_t sourceAddress;
691 LinkAcceptInfo info;
692
693 Log(kMessageReceive, kTypeLinkRequest, aRxInfo.mMessageInfo.GetPeerAddr());
694
695 VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
696
697 VerifyOrExit(!IsAttaching(), error = kErrorInvalidState);
698
699 SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge));
700
701 SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
702
703 switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
704 {
705 case kErrorNone:
706 VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId(), error = kErrorInvalidState);
707 break;
708 case kErrorNotFound:
709 break;
710 default:
711 ExitNow(error = kErrorParse);
712 }
713
714 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(info.mExtAddress);
715
716 info.mLinkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
717
718 switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
719 {
720 case kErrorNone:
721 if (IsRouterRloc16(sourceAddress))
722 {
723 neighbor = mRouterTable.FindRouterByRloc16(sourceAddress);
724 VerifyOrExit(neighbor != nullptr, error = kErrorParse);
725
726 if (!neighbor->IsStateValid())
727 {
728 InitNeighbor(*neighbor, aRxInfo);
729 neighbor->SetState(Neighbor::kStateLinkRequest);
730 }
731 else
732 {
733 VerifyOrExit(neighbor->GetExtAddress() == info.mExtAddress);
734 }
735 }
736
737 break;
738
739 case kErrorNotFound:
740 // A missing source address indicates that the router was
741 // recently reset.
742 VerifyOrExit(aRxInfo.IsNeighborStateValid() && IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()),
743 error = kErrorDrop);
744 neighbor = aRxInfo.mNeighbor;
745 break;
746
747 default:
748 ExitNow(error = kErrorParse);
749 }
750
751 switch (aRxInfo.mMessage.ReadTlvRequestTlv(info.mRequestedTlvList))
752 {
753 case kErrorNone:
754 case kErrorNotFound:
755 break;
756 default:
757 ExitNow(error = kErrorParse);
758 }
759
760 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
761 if (neighbor != nullptr)
762 {
763 neighbor->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
764 }
765 #endif
766
767 #if OPENTHREAD_CONFIG_MULTI_RADIO
768 if (neighbor != nullptr)
769 {
770 neighbor->ClearLastRxFragmentTag();
771 }
772 #endif
773
774 aRxInfo.mClass = RxInfo::kPeerMessage;
775 ProcessKeySequence(aRxInfo);
776
777 if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast())
778 {
779 mDelayedSender.ScheduleLinkAccept(info, 1 + Random::NonCrypto::GetUint16InRange(0, kMaxLinkAcceptDelay));
780 }
781 else
782 {
783 error = SendLinkAccept(info);
784 }
785
786 exit:
787 LogProcessError(kTypeLinkRequest, error);
788 OT_UNUSED_VARIABLE(neighbor);
789 }
790
SendLinkAccept(const LinkAcceptInfo & aInfo)791 Error MleRouter::SendLinkAccept(const LinkAcceptInfo &aInfo)
792 {
793 static const uint8_t kRouterTlvs[] = {Tlv::kLinkMargin};
794
795 Error error = kErrorNone;
796 TxMessage *message = nullptr;
797 Command command = kCommandLinkAccept;
798 Router *router;
799 Ip6::Address destination;
800
801 VerifyOrExit(IsAttached());
802
803 router = mRouterTable.FindRouter(aInfo.mExtAddress);
804
805 if (router != nullptr)
806 {
807 if (router->IsStateLinkRequest())
808 {
809 command = kCommandLinkAcceptAndRequest;
810 router->SetLastHeard(TimerMilli::GetNow());
811 }
812 else
813 {
814 VerifyOrExit(router->IsStateValid());
815 }
816 }
817
818 VerifyOrExit((message = NewMleMessage(command)) != nullptr, error = kErrorNoBufs);
819 SuccessOrExit(error = message->AppendVersionTlv());
820 SuccessOrExit(error = message->AppendSourceAddressTlv());
821 SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge));
822 SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
823
824 SuccessOrExit(error = message->AppendLinkMarginTlv(aInfo.mLinkMargin));
825
826 if (router != nullptr)
827 {
828 SuccessOrExit(error = message->AppendLeaderDataTlv());
829 }
830
831 for (uint8_t tlvType : aInfo.mRequestedTlvList)
832 {
833 switch (tlvType)
834 {
835 case Tlv::kRoute:
836 SuccessOrExit(error = message->AppendRouteTlv(router));
837 break;
838
839 case Tlv::kAddress16:
840 VerifyOrExit(router != nullptr, error = kErrorDrop);
841 SuccessOrExit(error = message->AppendAddress16Tlv(router->GetRloc16()));
842 break;
843
844 case Tlv::kLinkMargin:
845 break;
846
847 default:
848 ExitNow(error = kErrorDrop);
849 }
850 }
851
852 if (command == kCommandLinkAcceptAndRequest)
853 {
854 router->GenerateChallenge();
855
856 SuccessOrExit(error = message->AppendChallengeTlv(router->GetChallenge()));
857 SuccessOrExit(error = message->AppendTlvRequestTlv(kRouterTlvs));
858 }
859
860 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
861 if (router != nullptr && router->IsTimeSyncEnabled())
862 {
863 message->SetTimeSync(true);
864 }
865 #endif
866
867 destination.SetToLinkLocalAddress(aInfo.mExtAddress);
868
869 SuccessOrExit(error = message->SendTo(destination));
870
871 Log(kMessageSend, (command == kCommandLinkAccept) ? kTypeLinkAccept : kTypeLinkAcceptAndRequest, destination);
872
873 exit:
874 FreeMessageOnError(message, error);
875 return error;
876 }
877
HandleLinkAccept(RxInfo & aRxInfo)878 void MleRouter::HandleLinkAccept(RxInfo &aRxInfo) { HandleLinkAcceptVariant(aRxInfo, kTypeLinkAccept); }
879
HandleLinkAcceptAndRequest(RxInfo & aRxInfo)880 void MleRouter::HandleLinkAcceptAndRequest(RxInfo &aRxInfo)
881 {
882 HandleLinkAcceptVariant(aRxInfo, kTypeLinkAcceptAndRequest);
883 }
884
HandleLinkAcceptVariant(RxInfo & aRxInfo,MessageType aMessageType)885 void MleRouter::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
886 {
887 // Handles "Link Accept" or "Link Accept And Request".
888
889 Error error = kErrorNone;
890 Router *router;
891 Neighbor::State neighborState;
892 uint16_t version;
893 RxChallenge response;
894 uint16_t sourceAddress;
895 uint32_t linkFrameCounter;
896 uint32_t mleFrameCounter;
897 uint8_t routerId;
898 uint16_t address16;
899 RouteTlv routeTlv;
900 LeaderData leaderData;
901 uint8_t linkMargin;
902 bool shouldUpdateRoutes = false;
903
904 SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
905
906 Log(kMessageReceive, aMessageType, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress);
907
908 VerifyOrExit(IsRouterRloc16(sourceAddress), error = kErrorParse);
909
910 routerId = RouterIdFromRloc16(sourceAddress);
911 router = mRouterTable.FindRouterById(routerId);
912 neighborState = (router != nullptr) ? router->GetState() : Neighbor::kStateInvalid;
913
914 SuccessOrExit(error = aRxInfo.mMessage.ReadResponseTlv(response));
915
916 switch (neighborState)
917 {
918 case Neighbor::kStateLinkRequest:
919 VerifyOrExit(response == router->GetChallenge(), error = kErrorSecurity);
920 break;
921
922 case Neighbor::kStateInvalid:
923 VerifyOrExit(mRouterRoleRestorer.IsActive() && (response == mRouterRoleRestorer.GetChallenge()),
924 error = kErrorSecurity);
925
926 OT_FALL_THROUGH;
927
928 case Neighbor::kStateValid:
929 break;
930
931 default:
932 ExitNow(error = kErrorSecurity);
933 }
934
935 // Remove stale neighbors
936 if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != sourceAddress)
937 {
938 RemoveNeighbor(*aRxInfo.mNeighbor);
939 }
940
941 SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
942
943 SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
944
945 switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMargin))
946 {
947 case kErrorNone:
948 break;
949 case kErrorNotFound:
950 // The Link Margin TLV may be omitted after a reset. We wait
951 // for MLE Advertisements to establish the routing cost to
952 // the neighbor
953 VerifyOrExit(IsDetached(), error = kErrorNotFound);
954 linkMargin = 0;
955 break;
956 default:
957 ExitNow(error = kErrorParse);
958 }
959
960 switch (mRole)
961 {
962 case kRoleDetached:
963 SuccessOrExit(error = Tlv::Find<Address16Tlv>(aRxInfo.mMessage, address16));
964 VerifyOrExit(GetRloc16() == address16, error = kErrorDrop);
965
966 SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
967 SetLeaderData(leaderData);
968
969 mRouterTable.Clear();
970 SuccessOrExit(error = aRxInfo.mMessage.ReadRouteTlv(routeTlv));
971 SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
972 router = mRouterTable.FindRouterById(routerId);
973 VerifyOrExit(router != nullptr);
974
975 if (GetLeaderRloc16() == GetRloc16())
976 {
977 SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset);
978 }
979 else
980 {
981 SetStateRouter(GetRloc16());
982 }
983
984 mRouterRoleRestorer.Stop();
985 mRetrieveNewNetworkData = true;
986 IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
987 shouldUpdateRoutes = true;
988
989 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
990 Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
991 #endif
992 break;
993
994 case kRoleChild:
995 VerifyOrExit(router != nullptr);
996 break;
997
998 case kRoleRouter:
999 case kRoleLeader:
1000 VerifyOrExit(router != nullptr);
1001
1002 SuccessOrExit(error = aRxInfo.mMessage.ReadLeaderDataTlv(leaderData));
1003 VerifyOrExit(leaderData.GetPartitionId() == mLeaderData.GetPartitionId());
1004
1005 if (mRetrieveNewNetworkData ||
1006 SerialNumber::IsGreater(leaderData.GetDataVersion(NetworkData::kFullSet),
1007 Get<NetworkData::Leader>().GetVersion(NetworkData::kFullSet)))
1008 {
1009 IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
1010 }
1011
1012 switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1013 {
1014 case kErrorNone:
1015 VerifyOrExit(routeTlv.IsRouterIdSet(routerId), error = kErrorParse);
1016
1017 if (mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
1018 {
1019 SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1020 router = mRouterTable.FindRouterById(routerId);
1021 OT_ASSERT(router != nullptr);
1022 }
1023 shouldUpdateRoutes = true;
1024 break;
1025
1026 case kErrorNotFound:
1027 break;
1028
1029 default:
1030 ExitNow(error = kErrorParse);
1031 }
1032
1033 if (routerId != mRouterId && !IsRouterIdValid(router->GetNextHop()))
1034 {
1035 ResetAdvertiseInterval();
1036 }
1037
1038 break;
1039
1040 case kRoleDisabled:
1041 OT_ASSERT(false);
1042 }
1043
1044 InitNeighbor(*router, aRxInfo);
1045 router->SetRloc16(sourceAddress);
1046 router->GetLinkFrameCounters().SetAll(linkFrameCounter);
1047 router->SetLinkAckFrameCounter(linkFrameCounter);
1048 router->SetMleFrameCounter(mleFrameCounter);
1049 router->SetVersion(version);
1050 router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
1051 DeviceMode::kModeFullNetworkData));
1052 router->SetLinkQualityOut(LinkQualityForLinkMargin(linkMargin));
1053 router->SetState(Neighbor::kStateValid);
1054 router->SetKeySequence(aRxInfo.mKeySequence);
1055 router->ClearLinkAcceptTimeout();
1056
1057 mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
1058
1059 mDelayedSender.RemoveScheduledLinkRequest(*router);
1060
1061 if (shouldUpdateRoutes)
1062 {
1063 mRouterTable.UpdateRoutes(routeTlv, routerId);
1064 }
1065
1066 aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
1067 ProcessKeySequence(aRxInfo);
1068
1069 if (aMessageType == kTypeLinkAcceptAndRequest)
1070 {
1071 LinkAcceptInfo info;
1072
1073 SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge));
1074
1075 switch (aRxInfo.mMessage.ReadTlvRequestTlv(info.mRequestedTlvList))
1076 {
1077 case kErrorNone:
1078 case kErrorNotFound:
1079 break;
1080 default:
1081 ExitNow(error = kErrorParse);
1082 }
1083
1084 info.mExtAddress = router->GetExtAddress();
1085 info.mLinkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
1086
1087 SuccessOrExit(error = SendLinkAccept(info));
1088 }
1089
1090 exit:
1091 LogProcessError(aMessageType, error);
1092 }
1093
ProcessRouteTlv(const RouteTlv & aRouteTlv,RxInfo & aRxInfo)1094 Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo)
1095 {
1096 // This method processes `aRouteTlv` read from an MLE message.
1097 //
1098 // During processing of Route TLV, the entries in the router table
1099 // may shuffle. This method ensures that the `aRxInfo.mNeighbor`
1100 // (which indicates the neighbor from which the MLE message was
1101 // received) is correctly updated to point to the same neighbor
1102 // (in case `mNeighbor` was pointing to a router entry from the
1103 // `RouterTable`).
1104
1105 Error error = kErrorNone;
1106 uint16_t neighborRloc16 = kInvalidRloc16;
1107
1108 if ((aRxInfo.mNeighbor != nullptr) && Get<RouterTable>().Contains(*aRxInfo.mNeighbor))
1109 {
1110 neighborRloc16 = aRxInfo.mNeighbor->GetRloc16();
1111 }
1112
1113 mRouterTable.UpdateRouterIdSet(aRouteTlv.GetRouterIdSequence(), aRouteTlv.GetRouterIdMask());
1114
1115 if (IsRouter() && !mRouterTable.IsAllocated(mRouterId))
1116 {
1117 IgnoreError(BecomeDetached());
1118 error = kErrorNoRoute;
1119 }
1120
1121 if (neighborRloc16 != kInvalidRloc16)
1122 {
1123 aRxInfo.mNeighbor = Get<NeighborTable>().FindNeighbor(neighborRloc16);
1124 }
1125
1126 return error;
1127 }
1128
ReadAndProcessRouteTlvOnFtdChild(RxInfo & aRxInfo,uint8_t aParentId)1129 Error MleRouter::ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId)
1130 {
1131 // This method reads and processes Route TLV from message on an
1132 // FTD child if message contains one. It returns `kErrorNone`
1133 // when successfully processed or if there is no Route TLV in
1134 // the message.
1135 //
1136 // It MUST be used only when device is acting as a child and
1137 // for a message received from device's current parent.
1138
1139 Error error = kErrorNone;
1140 RouteTlv routeTlv;
1141
1142 VerifyOrExit(IsFullThreadDevice());
1143
1144 switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1145 {
1146 case kErrorNone:
1147 SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1148 mRouterTable.UpdateRouterOnFtdChild(routeTlv, aParentId);
1149 mRequestRouteTlv = false;
1150 break;
1151 case kErrorNotFound:
1152 break;
1153 default:
1154 ExitNow(error = kErrorParse);
1155 }
1156
1157 exit:
1158 return error;
1159 }
1160
IsSingleton(void) const1161 bool MleRouter::IsSingleton(void) const
1162 {
1163 bool isSingleton = true;
1164
1165 VerifyOrExit(IsAttached() && IsRouterEligible());
1166 isSingleton = (mRouterTable.GetActiveRouterCount() <= 1);
1167
1168 exit:
1169 return isSingleton;
1170 }
1171
ComparePartitions(bool aSingletonA,const LeaderData & aLeaderDataA,bool aSingletonB,const LeaderData & aLeaderDataB)1172 int MleRouter::ComparePartitions(bool aSingletonA,
1173 const LeaderData &aLeaderDataA,
1174 bool aSingletonB,
1175 const LeaderData &aLeaderDataB)
1176 {
1177 int rval = 0;
1178
1179 rval = ThreeWayCompare(aLeaderDataA.GetWeighting(), aLeaderDataB.GetWeighting());
1180 VerifyOrExit(rval == 0);
1181
1182 // Not being a singleton is better.
1183 rval = ThreeWayCompare(!aSingletonA, !aSingletonB);
1184 VerifyOrExit(rval == 0);
1185
1186 rval = ThreeWayCompare(aLeaderDataA.GetPartitionId(), aLeaderDataB.GetPartitionId());
1187
1188 exit:
1189 return rval;
1190 }
1191
HandleAdvertisementOnFtd(RxInfo & aRxInfo,uint16_t aSourceAddress,const LeaderData & aLeaderData)1192 Error MleRouter::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, const LeaderData &aLeaderData)
1193 {
1194 // This method processes a received MLE Advertisement message on
1195 // an FTD device. It is called from `Mle::HandleAdvertisement()`
1196 // only when device is attached (in child, router, or leader roles)
1197 // and `IsFullThreadDevice()`.
1198 //
1199 // - `aSourceAddress` is the read value from `SourceAddressTlv`.
1200 // - `aLeaderData` is the read value from `LeaderDataTlv`.
1201
1202 Error error = kErrorNone;
1203 uint8_t linkMargin = Get<Mac::Mac>().ComputeLinkMargin(aRxInfo.mMessage.GetAverageRss());
1204 RouteTlv routeTlv;
1205 Router *router;
1206 uint8_t routerId;
1207 uint32_t delay;
1208
1209 switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
1210 {
1211 case kErrorNone:
1212 break;
1213 case kErrorNotFound:
1214 routeTlv.SetLength(0); // Mark that a Route TLV was not included.
1215 break;
1216 default:
1217 ExitNow(error = kErrorParse);
1218 }
1219
1220 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1221 // Handle Partition ID mismatch
1222
1223 if (aLeaderData.GetPartitionId() != mLeaderData.GetPartitionId())
1224 {
1225 LogNote("Different partition (peer:%lu, local:%lu)", ToUlong(aLeaderData.GetPartitionId()),
1226 ToUlong(mLeaderData.GetPartitionId()));
1227
1228 VerifyOrExit(linkMargin >= kPartitionMergeMinMargin, error = kErrorLinkMarginLow);
1229
1230 if (routeTlv.IsValid() && (mPreviousPartitionIdTimeout > 0) &&
1231 (aLeaderData.GetPartitionId() == mPreviousPartitionId))
1232 {
1233 VerifyOrExit(SerialNumber::IsGreater(routeTlv.GetRouterIdSequence(), mPreviousPartitionRouterIdSequence),
1234 error = kErrorDrop);
1235 }
1236
1237 if (IsChild() && (aRxInfo.mNeighbor == &mParent))
1238 {
1239 ExitNow();
1240 }
1241
1242 if (ComparePartitions(routeTlv.IsSingleton(), aLeaderData, IsSingleton(), mLeaderData) > 0
1243 #if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
1244 // Allow a better partition if it also enables time sync.
1245 && aRxInfo.mMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
1246 #endif
1247 )
1248 {
1249 Attach(kBetterPartition);
1250 }
1251
1252 ExitNow(error = kErrorDrop);
1253 }
1254
1255 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1256 // Handle Leader Router ID mismatch
1257
1258 if (aLeaderData.GetLeaderRouterId() != GetLeaderId())
1259 {
1260 VerifyOrExit(aRxInfo.IsNeighborStateValid());
1261
1262 if (!IsChild())
1263 {
1264 LogInfo("Leader ID mismatch");
1265 IgnoreError(BecomeDetached());
1266 error = kErrorDrop;
1267 }
1268
1269 ExitNow();
1270 }
1271
1272 VerifyOrExit(IsRouterRloc16(aSourceAddress) && routeTlv.IsValid());
1273 routerId = RouterIdFromRloc16(aSourceAddress);
1274
1275 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1276 Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
1277 #endif
1278
1279 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1280 // Process `RouteTlv`
1281
1282 if (aRxInfo.IsNeighborStateValid() && mRouterTable.IsRouteTlvIdSequenceMoreRecent(routeTlv))
1283 {
1284 SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
1285 }
1286
1287 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1288 // Update routers as a child
1289
1290 if (IsChild())
1291 {
1292 if (aRxInfo.mNeighbor == &mParent)
1293 {
1294 // MLE Advertisement from parent
1295 router = &mParent;
1296
1297 if (mParent.GetRloc16() != aSourceAddress)
1298 {
1299 IgnoreError(BecomeDetached());
1300 ExitNow(error = kErrorDetached);
1301 }
1302
1303 if (!mRouterRoleTransition.IsPending() && (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
1304 {
1305 mRouterRoleTransition.StartTimeout();
1306 }
1307
1308 mRouterTable.UpdateRouterOnFtdChild(routeTlv, routerId);
1309 }
1310 else
1311 {
1312 // MLE Advertisement not from parent, but from some other neighboring router
1313 router = mRouterTable.FindRouterById(routerId);
1314 VerifyOrExit(router != nullptr);
1315
1316 EstablishRouterLinkOnFtdChild(*router, aRxInfo, linkMargin);
1317 }
1318
1319 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
1320 router->SetSelectableAsParent(true);
1321 #endif
1322
1323 router->SetLastHeard(TimerMilli::GetNow());
1324
1325 ExitNow();
1326 }
1327
1328 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1329 // Update routers as a router or leader.
1330
1331 if (IsRouter() && ShouldDowngrade(routerId, routeTlv))
1332 {
1333 mRouterRoleTransition.StartTimeout();
1334 }
1335
1336 router = mRouterTable.FindRouterById(routerId);
1337 VerifyOrExit(router != nullptr);
1338
1339 if (!router->IsStateValid() && aRxInfo.IsNeighborStateValid() && Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
1340 {
1341 // The Adv is from a former child that is now acting as a router,
1342 // we copy the info from child entry and update the RLOC16.
1343
1344 *static_cast<Neighbor *>(router) = *aRxInfo.mNeighbor;
1345 router->SetRloc16(Rloc16FromRouterId(routerId));
1346 router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
1347 DeviceMode::kModeFullNetworkData));
1348
1349 mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
1350
1351 // Change the cache entries associated with the former child
1352 // from using the old RLOC16 to its new RLOC16.
1353 Get<AddressResolver>().ReplaceEntriesForRloc16(aRxInfo.mNeighbor->GetRloc16(), router->GetRloc16());
1354 }
1355
1356 // Send unicast link request if no link to router and no
1357 // unicast/multicast link request in progress
1358
1359 if (!router->IsStateValid() && !router->IsStateLinkRequest() && (linkMargin >= kLinkRequestMinMargin) &&
1360 routeTlv.IsRouterIdSet(mRouterId))
1361 {
1362 InitNeighbor(*router, aRxInfo);
1363 router->SetState(Neighbor::kStateLinkRequest);
1364 delay = Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter);
1365 mDelayedSender.ScheduleLinkRequest(*router, delay);
1366 ExitNow(error = kErrorNoRoute);
1367 }
1368
1369 router->SetLastHeard(TimerMilli::GetNow());
1370
1371 mRouterTable.UpdateRoutes(routeTlv, routerId);
1372
1373 exit:
1374 if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != aSourceAddress)
1375 {
1376 RemoveNeighbor(*aRxInfo.mNeighbor);
1377 }
1378
1379 return error;
1380 }
1381
EstablishRouterLinkOnFtdChild(Router & aRouter,RxInfo & aRxInfo,uint8_t aLinkMargin)1382 void MleRouter::EstablishRouterLinkOnFtdChild(Router &aRouter, RxInfo &aRxInfo, uint8_t aLinkMargin)
1383 {
1384 // Decide on an FTD child whether to establish a link with a
1385 // router upon receiving an advertisement from it.
1386
1387 uint8_t neighborCount;
1388 uint32_t minDelay;
1389 uint32_t maxDelay;
1390
1391 VerifyOrExit(!aRouter.IsStateValid() && !aRouter.IsStateLinkRequest());
1392
1393 // The first `mChildRouterLinks` are established quickly. After that,
1394 // the "gradual router link establishment" mechanism is used, which
1395 // allows `kExtraChildRouterLinks` additional router links to be
1396 // established, but it is done slowly and over a longer span of time.
1397 //
1398 // Gradual router link establishment conditions:
1399 // - The maximum `neighborCount` limit is not yet reached.
1400 // - We see Link Quality 2 or better.
1401 // - Always skipped in the first 5 minutes
1402 // (`kWaitDurationAfterAttach`) after the device attaches.
1403 // - The child randomly decides whether to perform/skip this (with a 5%
1404 // probability, `kProbabilityPercentage`).
1405 // - If the child decides to send Link Request, a longer random delay
1406 // window is used, [1.5-10] seconds.
1407 //
1408 // Even in a dense network, if the advertisement is received by 500 FTD
1409 // children with a 5% selection probability, on average, 25 nodes will
1410 // try to send a Link Request, which will be randomly spread over a
1411 // [1.5-10] second window.
1412 //
1413 // With a 5% probability, on average, it takes 20 trials (20 advertisement
1414 // receptions for an FTD child to send a Link Request). Advertisements
1415 // are, on average, ~32 seconds apart, so, on average, a child will try
1416 // to establish a link in `20 * 32 = 640` seconds (~10 minutes).
1417
1418 neighborCount = mRouterTable.GetNeighborCount(kLinkQuality1);
1419
1420 if (neighborCount < mChildRouterLinks)
1421 {
1422 minDelay = kMinLinkRequestDelayOnChild;
1423 maxDelay = kMaxLinkRequestDelayOnChild;
1424 }
1425 else
1426 {
1427 VerifyOrExit(neighborCount < mChildRouterLinks + GradualChildRouterLink::kExtraChildRouterLinks);
1428 VerifyOrExit(LinkQualityForLinkMargin(aLinkMargin) >= kLinkQuality2);
1429 VerifyOrExit(GetCurrentAttachDuration() > GradualChildRouterLink::kWaitDurationAfterAttach);
1430 VerifyOrExit(Random::NonCrypto::GetUint8InRange(0, 100) < GradualChildRouterLink::kProbabilityPercentage);
1431
1432 minDelay = GradualChildRouterLink::kMinLinkRequestDelay;
1433 maxDelay = GradualChildRouterLink::kMaxLinkRequestDelay;
1434 }
1435
1436 InitNeighbor(aRouter, aRxInfo);
1437 aRouter.SetState(Neighbor::kStateLinkRequest);
1438 mDelayedSender.ScheduleLinkRequest(aRouter, Random::NonCrypto::GetUint32InRange(minDelay, maxDelay));
1439
1440 exit:
1441 return;
1442 }
1443
HandleParentRequest(RxInfo & aRxInfo)1444 void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
1445 {
1446 Error error = kErrorNone;
1447 uint16_t version;
1448 uint8_t scanMask;
1449 Child *child;
1450 DeviceMode mode;
1451 uint16_t delay;
1452 ParentResponseInfo info;
1453
1454 Log(kMessageReceive, kTypeParentRequest, aRxInfo.mMessageInfo.GetPeerAddr());
1455
1456 VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
1457
1458 // A Router/REED MUST NOT send an MLE Parent Response if:
1459
1460 // 0. It is detached or attempting to another partition
1461 VerifyOrExit(!IsDetached() && !IsAttaching(), error = kErrorDrop);
1462
1463 // 1. It has no available Child capacity (if Max Child Count minus
1464 // Child Count would be equal to zero)
1465 // ==> verified below when allocating a child entry
1466
1467 // 2. It is disconnected from its Partition (that is, it has not
1468 // received an updated ID sequence number within LEADER_TIMEOUT
1469 // seconds)
1470 VerifyOrExit(mRouterTable.GetLeaderAge() < mNetworkIdTimeout, error = kErrorDrop);
1471
1472 // 3. Its current routing path cost to the Leader is infinite.
1473 VerifyOrExit(mRouterTable.GetPathCostToLeader() < kMaxRouteCost, error = kErrorDrop);
1474
1475 // 4. It is a REED and there are already `kMaxRouters` active routers in
1476 // the network (because Leader would reject any further address solicit).
1477 // ==> Verified below when checking the scan mask.
1478
1479 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(info.mChildExtAddress);
1480
1481 SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
1482
1483 SuccessOrExit(error = Tlv::Find<ScanMaskTlv>(aRxInfo.mMessage, scanMask));
1484
1485 switch (mRole)
1486 {
1487 case kRoleDisabled:
1488 case kRoleDetached:
1489 ExitNow();
1490
1491 case kRoleChild:
1492 VerifyOrExit(ScanMaskTlv::IsEndDeviceFlagSet(scanMask));
1493 VerifyOrExit(mRouterTable.GetActiveRouterCount() < kMaxRouters, error = kErrorDrop);
1494 break;
1495
1496 case kRoleRouter:
1497 case kRoleLeader:
1498 VerifyOrExit(ScanMaskTlv::IsRouterFlagSet(scanMask));
1499 break;
1500 }
1501
1502 SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(info.mRxChallenge));
1503
1504 child = mChildTable.FindChild(info.mChildExtAddress, Child::kInStateAnyExceptInvalid);
1505
1506 if (child == nullptr)
1507 {
1508 VerifyOrExit((child = mChildTable.GetNewChild()) != nullptr, error = kErrorNoBufs);
1509
1510 InitNeighbor(*child, aRxInfo);
1511 child->SetState(Neighbor::kStateParentRequest);
1512 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1513 child->SetTimeSyncEnabled(Tlv::Find<TimeRequestTlv>(aRxInfo.mMessage, nullptr, 0) == kErrorNone);
1514 #endif
1515 if (aRxInfo.mMessage.ReadModeTlv(mode) == kErrorNone)
1516 {
1517 child->SetDeviceMode(mode);
1518 child->SetVersion(version);
1519 }
1520 }
1521 else if (TimerMilli::GetNow() - child->GetLastHeard() < kParentRequestRouterTimeout - kParentRequestDuplicateMargin)
1522 {
1523 ExitNow(error = kErrorDuplicated);
1524 }
1525
1526 if (!child->IsStateValidOrRestoring())
1527 {
1528 child->SetLastHeard(TimerMilli::GetNow());
1529 child->SetTimeout(Time::MsecToSec(kChildIdRequestTimeout));
1530 }
1531
1532 aRxInfo.mClass = RxInfo::kPeerMessage;
1533 ProcessKeySequence(aRxInfo);
1534
1535 delay = 1 + Random::NonCrypto::GetUint16InRange(0, !ScanMaskTlv::IsEndDeviceFlagSet(scanMask)
1536 ? kParentResponseMaxDelayRouters
1537 : kParentResponseMaxDelayAll);
1538 mDelayedSender.ScheduleParentResponse(info, delay);
1539
1540 exit:
1541 LogProcessError(kTypeParentRequest, error);
1542 }
1543
HasNeighborWithGoodLinkQuality(void) const1544 bool MleRouter::HasNeighborWithGoodLinkQuality(void) const
1545 {
1546 bool haveNeighbor = true;
1547 uint8_t linkMargin;
1548
1549 linkMargin = Get<Mac::Mac>().ComputeLinkMargin(mParent.GetLinkInfo().GetLastRss());
1550
1551 if (linkMargin >= kLinkRequestMinMargin)
1552 {
1553 ExitNow();
1554 }
1555
1556 for (const Router &router : Get<RouterTable>())
1557 {
1558 if (!router.IsStateValid())
1559 {
1560 continue;
1561 }
1562
1563 linkMargin = Get<Mac::Mac>().ComputeLinkMargin(router.GetLinkInfo().GetLastRss());
1564
1565 if (linkMargin >= kLinkRequestMinMargin)
1566 {
1567 ExitNow();
1568 }
1569 }
1570
1571 haveNeighbor = false;
1572
1573 exit:
1574 return haveNeighbor;
1575 }
1576
HandleTimeTick(void)1577 void MleRouter::HandleTimeTick(void)
1578 {
1579 bool roleTransitionTimeoutExpired = false;
1580
1581 VerifyOrExit(IsFullThreadDevice(), Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter));
1582
1583 if (mPreviousPartitionIdTimeout > 0)
1584 {
1585 mPreviousPartitionIdTimeout--;
1586 }
1587
1588 if (mAlternateRloc16Timeout > 0)
1589 {
1590 mAlternateRloc16Timeout--;
1591
1592 if (mAlternateRloc16Timeout == 0)
1593 {
1594 ClearAlternateRloc16();
1595 }
1596 }
1597
1598 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1599 // Role transitions
1600
1601 roleTransitionTimeoutExpired = mRouterRoleTransition.HandleTimeTick();
1602
1603 switch (mRole)
1604 {
1605 case kRoleDetached:
1606 break;
1607
1608 case kRoleChild:
1609 if (roleTransitionTimeoutExpired)
1610 {
1611 if (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality())
1612 {
1613 IgnoreError(BecomeRouter(ThreadStatusTlv::kTooFewRouters));
1614 }
1615 else
1616 {
1617 InformPreviousChannel();
1618 }
1619
1620 if (!mAdvertiseTrickleTimer.IsRunning())
1621 {
1622 SendMulticastAdvertisement();
1623
1624 mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, kReedAdvIntervalMin, kReedAdvIntervalMax);
1625 }
1626
1627 ExitNow();
1628 }
1629
1630 OT_FALL_THROUGH;
1631
1632 case kRoleRouter:
1633 LogDebg("Leader age %lu", ToUlong(mRouterTable.GetLeaderAge()));
1634
1635 if ((mRouterTable.GetActiveRouterCount() > 0) && (mRouterTable.GetLeaderAge() >= mNetworkIdTimeout))
1636 {
1637 LogInfo("Leader age timeout");
1638 Attach(kSamePartition);
1639 }
1640
1641 if (roleTransitionTimeoutExpired && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
1642 {
1643 LogNote("Downgrade to REED");
1644 Attach(kDowngradeToReed);
1645 }
1646
1647 OT_FALL_THROUGH;
1648
1649 case kRoleLeader:
1650 if (roleTransitionTimeoutExpired && !IsRouterEligible())
1651 {
1652 LogInfo("No longer router eligible");
1653 IgnoreError(BecomeDetached());
1654 }
1655
1656 break;
1657
1658 case kRoleDisabled:
1659 OT_ASSERT(false);
1660 }
1661
1662 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1663 // Update `ChildTable`
1664
1665 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
1666 {
1667 uint32_t timeout = 0;
1668
1669 switch (child.GetState())
1670 {
1671 case Neighbor::kStateInvalid:
1672 case Neighbor::kStateChildIdRequest:
1673 continue;
1674
1675 case Neighbor::kStateParentRequest:
1676 case Neighbor::kStateValid:
1677 case Neighbor::kStateRestored:
1678 case Neighbor::kStateChildUpdateRequest:
1679 timeout = Time::SecToMsec(child.GetTimeout());
1680 break;
1681
1682 case Neighbor::kStateParentResponse:
1683 case Neighbor::kStateLinkRequest:
1684 OT_ASSERT(false);
1685 }
1686
1687 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1688 if (child.IsCslSynchronized() &&
1689 TimerMilli::GetNow() - child.GetCslLastHeard() >= Time::SecToMsec(child.GetCslTimeout()))
1690 {
1691 LogInfo("Child 0x%04x CSL synchronization expired", child.GetRloc16());
1692 child.SetCslSynchronized(false);
1693 Get<CslTxScheduler>().Update();
1694 }
1695 #endif
1696
1697 if (TimerMilli::GetNow() - child.GetLastHeard() >= timeout)
1698 {
1699 LogInfo("Child 0x%04x timeout expired", child.GetRloc16());
1700 RemoveNeighbor(child);
1701 }
1702 else if (IsRouterOrLeader() && child.IsStateRestored())
1703 {
1704 IgnoreError(SendChildUpdateRequestToChild(child));
1705 }
1706 }
1707
1708 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1709 // Update `RouterTable`
1710
1711 for (Router &router : Get<RouterTable>())
1712 {
1713 uint32_t age;
1714
1715 if (router.GetRloc16() == GetRloc16())
1716 {
1717 router.SetLastHeard(TimerMilli::GetNow());
1718 continue;
1719 }
1720
1721 age = TimerMilli::GetNow() - router.GetLastHeard();
1722
1723 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
1724 router.DecrementParentReselectTimeout();
1725
1726 if (age >= kMaxNeighborAge)
1727 {
1728 router.SetSelectableAsParent(false);
1729 }
1730 #endif
1731 if (router.IsStateValid())
1732 {
1733 // Neighbor router age and link recovery
1734 //
1735 // If the device is an FTD child and has more than
1736 // `mChildRouterLinks` neighbors, it uses a longer age,
1737 // `kMaxNeighborAgeOnChild`, and removes the neighboring
1738 // router upon expiration without trying to re-establish
1739 // its link with it.
1740 //
1741 // Otherwise, if the device itself is a router, or it is an
1742 // FTD child with `mChildRouterLinks` or fewer neighbors,
1743 // it uses a shorter `kMaxNeighborAge`. Upon expiration, it
1744 // tries to re-establish its link with the neighboring router.
1745
1746 if (IsChild() && (mRouterTable.GetNeighborCount(kLinkQuality1) > mChildRouterLinks))
1747 {
1748 if (age >= kMaxNeighborAgeOnChild)
1749 {
1750 LogInfo("No Adv from router 0x%04x - removing router", router.GetRloc16());
1751 mDelayedSender.RemoveScheduledLinkRequest(router);
1752 RemoveNeighbor(router);
1753 continue;
1754 }
1755 }
1756 else if (age >= kMaxNeighborAge)
1757 {
1758 // We send a Link Request every time tick (second), up to
1759 // max attempts. Each transmission is randomly delayed
1760 // (one-second window). After the last attempt, we wait for
1761 // the "Link Accept" timeout (~3 seconds) before removing the
1762 // neighboring router.
1763
1764 if (!mDelayedSender.HasAnyScheduledLinkRequest(router) && !router.IsWaitingForLinkAccept())
1765 {
1766 LogInfo("No Adv from router 0x%04x - sending Link Request", router.GetRloc16());
1767 router.SetLinkRequestAttemptsToMax();
1768 }
1769
1770 if (router.HasRemainingLinkRequestAttempts())
1771 {
1772 router.DecrementLinkRequestAttempts();
1773 mDelayedSender.ScheduleLinkRequest(
1774 router, Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter));
1775 }
1776 }
1777 }
1778
1779 if (router.IsWaitingForLinkAccept() && (router.DecrementLinkAcceptTimeout() == 0))
1780 {
1781 LogInfo("Router 0x%04x - Link Accept timeout expired", router.GetRloc16());
1782 RemoveNeighbor(router);
1783 continue;
1784 }
1785
1786 if (IsLeader() && (mRouterTable.FindNextHopOf(router) == nullptr) &&
1787 (mRouterTable.GetLinkCost(router) >= kMaxRouteCost) && (age >= kMaxLeaderToRouterTimeout))
1788 {
1789 LogInfo("Router 0x%04x ID timeout expired (no route)", router.GetRloc16());
1790 IgnoreError(mRouterTable.Release(router.GetRouterId()));
1791 }
1792 }
1793
1794 mRouterTable.HandleTimeTick();
1795
1796 SynchronizeChildNetworkData();
1797
1798 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1799 if (IsRouterOrLeader())
1800 {
1801 Get<TimeSync>().ProcessTimeSync();
1802 }
1803 #endif
1804
1805 exit:
1806 return;
1807 }
1808
SendParentResponse(const ParentResponseInfo & aInfo)1809 void MleRouter::SendParentResponse(const ParentResponseInfo &aInfo)
1810 {
1811 Error error = kErrorNone;
1812 TxMessage *message = nullptr;
1813 Child *child;
1814 Ip6::Address destination;
1815
1816 child = mChildTable.FindChild(aInfo.mChildExtAddress, Child::kInStateAnyExceptInvalid);
1817 VerifyOrExit(child != nullptr);
1818
1819 VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs);
1820 message->SetDirectTransmission();
1821
1822 SuccessOrExit(error = message->AppendSourceAddressTlv());
1823 SuccessOrExit(error = message->AppendLeaderDataTlv());
1824 SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
1825 SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge));
1826 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1827 if (child->IsTimeSyncEnabled())
1828 {
1829 SuccessOrExit(error = message->AppendTimeParameterTlv());
1830 }
1831 #endif
1832 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1833 if (child->IsThreadVersionCslCapable())
1834 {
1835 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
1836 }
1837 #endif
1838 child->GenerateChallenge();
1839 SuccessOrExit(error = message->AppendChallengeTlv(child->GetChallenge()));
1840 SuccessOrExit(error = message->AppendLinkMarginTlv(child->GetLinkInfo().GetLinkMargin()));
1841 SuccessOrExit(error = message->AppendConnectivityTlv());
1842 SuccessOrExit(error = message->AppendVersionTlv());
1843
1844 destination.SetToLinkLocalAddress(aInfo.mChildExtAddress);
1845
1846 SuccessOrExit(error = message->SendTo(destination));
1847
1848 Log(kMessageSend, kTypeParentResponse, destination);
1849
1850 exit:
1851 FreeMessageOnError(message, error);
1852 LogSendError(kTypeParentResponse, error);
1853 }
1854
GetMaxChildIpAddresses(void) const1855 uint8_t MleRouter::GetMaxChildIpAddresses(void) const
1856 {
1857 uint8_t num = kMaxChildIpAddresses;
1858
1859 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1860 if (mMaxChildIpAddresses != 0)
1861 {
1862 num = mMaxChildIpAddresses;
1863 }
1864 #endif
1865
1866 return num;
1867 }
1868
1869 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)1870 Error MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)
1871 {
1872 Error error = kErrorNone;
1873
1874 VerifyOrExit(aMaxIpAddresses <= kMaxChildIpAddresses, error = kErrorInvalidArgs);
1875
1876 mMaxChildIpAddresses = aMaxIpAddresses;
1877
1878 exit:
1879 return error;
1880 }
1881 #endif
1882
ProcessAddressRegistrationTlv(RxInfo & aRxInfo,Child & aChild)1883 Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
1884 {
1885 Error error;
1886 OffsetRange offsetRange;
1887 uint8_t count = 0;
1888 uint8_t storedCount = 0;
1889 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1890 Ip6::Address oldDua;
1891 #endif
1892 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1893 MlrManager::MlrAddressArray oldMlrRegisteredAddresses;
1894 #endif
1895
1896 OT_UNUSED_VARIABLE(storedCount);
1897
1898 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kAddressRegistration, offsetRange));
1899
1900 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1901 if (aChild.GetDomainUnicastAddress(oldDua) != kErrorNone)
1902 {
1903 oldDua.Clear();
1904 }
1905 #endif
1906
1907 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1908 if (aChild.HasAnyMlrRegisteredAddress())
1909 {
1910 OT_ASSERT(aChild.IsStateValid());
1911
1912 for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
1913 {
1914 if (!addrEntry.IsMulticastLargerThanRealmLocal())
1915 {
1916 continue;
1917 }
1918
1919 if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered)
1920 {
1921 IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry));
1922 }
1923 }
1924 }
1925 #endif
1926
1927 aChild.ClearIp6Addresses();
1928
1929 while (!offsetRange.IsEmpty())
1930 {
1931 uint8_t controlByte;
1932 Ip6::Address address;
1933
1934 // Read out the control byte (first byte in entry)
1935 SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, controlByte));
1936 offsetRange.AdvanceOffset(sizeof(uint8_t));
1937 count++;
1938
1939 address.Clear();
1940
1941 if (AddressRegistrationTlv::IsEntryCompressed(controlByte))
1942 {
1943 // Compressed entry contains IID with the 64-bit prefix
1944 // determined from 6LoWPAN context identifier (from
1945 // the control byte).
1946
1947 uint8_t contextId = AddressRegistrationTlv::GetContextId(controlByte);
1948 Lowpan::Context context;
1949
1950 IgnoreError(aRxInfo.mMessage.Read(offsetRange, address.GetIid()));
1951 offsetRange.AdvanceOffset(sizeof(Ip6::InterfaceIdentifier));
1952
1953 if (Get<NetworkData::Leader>().GetContext(contextId, context) != kErrorNone)
1954 {
1955 LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId,
1956 aChild.GetRloc16());
1957 continue;
1958 }
1959
1960 address.SetPrefix(context.mPrefix);
1961 }
1962 else
1963 {
1964 // Uncompressed entry contains the full IPv6 address.
1965
1966 IgnoreError(aRxInfo.mMessage.Read(offsetRange, address));
1967 offsetRange.AdvanceOffset(sizeof(Ip6::Address));
1968 }
1969
1970 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1971 if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
1972 {
1973 // Skip remaining address registration entries but keep logging
1974 // skipped addresses.
1975 error = kErrorNoBufs;
1976 }
1977 else
1978 #endif
1979 {
1980 // We try to accept/add as many IPv6 addresses as possible.
1981 // "Child ID/Update Response" will indicate the accepted
1982 // addresses.
1983 error = aChild.AddIp6Address(address);
1984 }
1985
1986 if (error == kErrorNone)
1987 {
1988 storedCount++;
1989 LogInfo("Child 0x%04x IPv6 address[%u]=%s", aChild.GetRloc16(), storedCount,
1990 address.ToString().AsCString());
1991 }
1992 else
1993 {
1994 LogWarn("Error %s adding IPv6 address %s to child 0x%04x", ErrorToString(error),
1995 address.ToString().AsCString(), aChild.GetRloc16());
1996 }
1997
1998 if (address.IsMulticast())
1999 {
2000 continue;
2001 }
2002
2003 // We check if the same address is in-use by another child, if so
2004 // remove it. This implements "last-in wins" duplicate address
2005 // resolution policy.
2006 //
2007 // Duplicate addresses can occur if a previously attached child
2008 // attaches to same parent again (after a reset, memory wipe) using
2009 // a new random extended address before the old entry in the child
2010 // table is timed out and then trying to register its globally unique
2011 // IPv6 address as the new child.
2012
2013 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
2014 {
2015 if (&child == &aChild)
2016 {
2017 continue;
2018 }
2019
2020 IgnoreError(child.RemoveIp6Address(address));
2021 }
2022
2023 // Clear EID-to-RLOC cache for the unicast address registered by the child.
2024 Get<AddressResolver>().RemoveEntryForAddress(address);
2025 }
2026 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2027 SignalDuaAddressEvent(aChild, oldDua);
2028 #endif
2029
2030 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2031 Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses);
2032 #endif
2033
2034 if (count == 0)
2035 {
2036 LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
2037 }
2038 else
2039 {
2040 LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count,
2041 (count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
2042 }
2043
2044 error = kErrorNone;
2045
2046 exit:
2047 return error;
2048 }
2049
2050 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
SignalDuaAddressEvent(const Child & aChild,const Ip6::Address & aOldDua) const2051 void MleRouter::SignalDuaAddressEvent(const Child &aChild, const Ip6::Address &aOldDua) const
2052 {
2053 DuaManager::ChildDuaAddressEvent event = DuaManager::kAddressUnchanged;
2054 Ip6::Address newDua;
2055
2056 if (aChild.GetDomainUnicastAddress(newDua) == kErrorNone)
2057 {
2058 if (aOldDua.IsUnspecified())
2059 {
2060 event = DuaManager::kAddressAdded;
2061 }
2062 else if (aOldDua != newDua)
2063 {
2064 event = DuaManager::kAddressChanged;
2065 }
2066 }
2067 else
2068 {
2069 // Child has no DUA address. If there was no old DUA, no need
2070 // to signal.
2071
2072 VerifyOrExit(!aOldDua.IsUnspecified());
2073
2074 event = DuaManager::kAddressRemoved;
2075 }
2076
2077 Get<DuaManager>().HandleChildDuaAddressEvent(aChild, event);
2078
2079 exit:
2080 return;
2081 }
2082 #endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2083
IsMessageMleSubType(const Message & aMessage)2084 bool MleRouter::IsMessageMleSubType(const Message &aMessage) { return aMessage.IsSubTypeMle(); }
2085
IsMessageChildUpdateRequest(const Message & aMessage)2086 bool MleRouter::IsMessageChildUpdateRequest(const Message &aMessage)
2087 {
2088 return aMessage.IsMleCommand(kCommandChildUpdateRequest);
2089 }
2090
HandleChildIdRequest(RxInfo & aRxInfo)2091 void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
2092 {
2093 Error error = kErrorNone;
2094 Mac::ExtAddress extAddr;
2095 uint16_t version;
2096 uint32_t linkFrameCounter;
2097 uint32_t mleFrameCounter;
2098 DeviceMode mode;
2099 uint32_t timeout;
2100 TlvList tlvList;
2101 MeshCoP::Timestamp timestamp;
2102 Child *child;
2103 Router *router;
2104 uint16_t supervisionInterval;
2105
2106 Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2107
2108 VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2109
2110 VerifyOrExit(IsAttached(), error = kErrorInvalidState);
2111
2112 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2113
2114 child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2115 VerifyOrExit(child != nullptr, error = kErrorAlready);
2116
2117 SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
2118
2119 SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge()));
2120
2121 Get<MeshForwarder>().RemoveMessagesForChild(*child, IsMessageMleSubType);
2122
2123 SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
2124
2125 SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2126
2127 SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
2128
2129 SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2130
2131 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2132 {
2133 case kErrorNone:
2134 tlvList.Add(Tlv::kSupervisionInterval);
2135 break;
2136 case kErrorNotFound:
2137 supervisionInterval = (version <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2138 break;
2139 default:
2140 ExitNow(error = kErrorParse);
2141 }
2142
2143 switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2144 {
2145 case kErrorNone:
2146 if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2147 {
2148 break;
2149 }
2150
2151 OT_FALL_THROUGH;
2152
2153 case kErrorNotFound:
2154 tlvList.Add(Tlv::kActiveDataset);
2155 break;
2156
2157 default:
2158 ExitNow(error = kErrorParse);
2159 }
2160
2161 switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2162 {
2163 case kErrorNone:
2164 if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2165 {
2166 break;
2167 }
2168
2169 OT_FALL_THROUGH;
2170
2171 case kErrorNotFound:
2172 tlvList.Add(Tlv::kPendingDataset);
2173 break;
2174
2175 default:
2176 ExitNow(error = kErrorParse);
2177 }
2178
2179 VerifyOrExit(tlvList.GetLength() <= Child::kMaxRequestTlvs, error = kErrorParse);
2180
2181 if (!mode.IsFullThreadDevice())
2182 {
2183 SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
2184 }
2185
2186 router = mRouterTable.FindRouter(extAddr);
2187
2188 if (router != nullptr)
2189 {
2190 RemoveNeighbor(*router);
2191 }
2192
2193 if (!child->IsStateValid())
2194 {
2195 child->SetState(Neighbor::kStateChildIdRequest);
2196 }
2197 else
2198 {
2199 RemoveNeighbor(*child);
2200 }
2201
2202 child->SetLastHeard(TimerMilli::GetNow());
2203 child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2204 child->SetLinkAckFrameCounter(linkFrameCounter);
2205 child->SetMleFrameCounter(mleFrameCounter);
2206 child->SetKeySequence(aRxInfo.mKeySequence);
2207 child->SetDeviceMode(mode);
2208 child->SetVersion(version);
2209 child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2210 child->SetTimeout(timeout);
2211 child->SetSupervisionInterval(supervisionInterval);
2212 #if OPENTHREAD_CONFIG_MULTI_RADIO
2213 child->ClearLastRxFragmentTag();
2214 #endif
2215
2216 child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType()));
2217
2218 // We already checked above that `tlvList` will fit in
2219 // `child` entry (with `Child::kMaxRequestTlvs` TLVs).
2220
2221 child->ClearRequestTlvs();
2222
2223 for (uint8_t index = 0; index < tlvList.GetLength(); index++)
2224 {
2225 child->SetRequestTlv(index, tlvList[index]);
2226 }
2227
2228 aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
2229 ProcessKeySequence(aRxInfo);
2230
2231 switch (mRole)
2232 {
2233 case kRoleChild:
2234 child->SetState(Neighbor::kStateChildIdRequest);
2235 IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
2236 break;
2237
2238 case kRoleRouter:
2239 case kRoleLeader:
2240 SuccessOrExit(error = SendChildIdResponse(*child));
2241 break;
2242
2243 case kRoleDisabled:
2244 case kRoleDetached:
2245 OT_ASSERT(false);
2246 }
2247
2248 exit:
2249 LogProcessError(kTypeChildIdRequest, error);
2250 }
2251
HandleChildUpdateRequestOnParent(RxInfo & aRxInfo)2252 void MleRouter::HandleChildUpdateRequestOnParent(RxInfo &aRxInfo)
2253 {
2254 Error error = kErrorNone;
2255 Mac::ExtAddress extAddr;
2256 DeviceMode mode;
2257 RxChallenge challenge;
2258 LeaderData leaderData;
2259 uint32_t timeout;
2260 uint16_t supervisionInterval;
2261 Child *child;
2262 DeviceMode oldMode;
2263 TlvList requestedTlvList;
2264 TlvList tlvList;
2265 bool childDidChange = false;
2266
2267 Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
2268
2269 SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2270
2271 switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
2272 {
2273 case kErrorNone:
2274 tlvList.Add(Tlv::kResponse);
2275 break;
2276 case kErrorNotFound:
2277 challenge.Clear();
2278 break;
2279 default:
2280 ExitNow(error = kErrorParse);
2281 }
2282
2283 tlvList.Add(Tlv::kSourceAddress);
2284
2285 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2286 child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2287
2288 if (child == nullptr)
2289 {
2290 // For invalid non-sleepy child, send Child Update Response with
2291 // Status TLV (error).
2292 if (mode.IsRxOnWhenIdle())
2293 {
2294 tlvList.Add(Tlv::kStatus);
2295 SendChildUpdateResponseToChild(nullptr, aRxInfo.mMessageInfo, tlvList, challenge);
2296 }
2297
2298 ExitNow();
2299 }
2300
2301 // Ignore "Child Update Request" from a child that is present in the
2302 // child table but it is not yet in valid state. For example, a
2303 // child which is being restored (due to parent reset) or is in the
2304 // middle of the attach process (in `kStateParentRequest` or
2305 // `kStateChildIdRequest`).
2306
2307 VerifyOrExit(child->IsStateValid());
2308
2309 oldMode = child->GetDeviceMode();
2310 child->SetDeviceMode(mode);
2311
2312 tlvList.Add(Tlv::kMode);
2313 tlvList.Add(Tlv::kLinkMargin);
2314
2315 // Parent MUST include Leader Data TLV in Child Update Response
2316 tlvList.Add(Tlv::kLeaderData);
2317
2318 if (!challenge.IsEmpty())
2319 {
2320 tlvList.Add(Tlv::kMleFrameCounter);
2321 tlvList.Add(Tlv::kLinkFrameCounter);
2322 }
2323
2324 switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2325 {
2326 case kErrorNone:
2327 tlvList.Add(Tlv::kAddressRegistration);
2328 break;
2329 case kErrorNotFound:
2330 break;
2331 default:
2332 ExitNow(error = kErrorParse);
2333 }
2334
2335 switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2336 {
2337 case kErrorNone:
2338 child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2339 break;
2340 case kErrorNotFound:
2341 break;
2342 default:
2343 ExitNow(error = kErrorParse);
2344 }
2345
2346 switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2347 {
2348 case kErrorNone:
2349 if (child->GetTimeout() != timeout)
2350 {
2351 child->SetTimeout(timeout);
2352 childDidChange = true;
2353 }
2354
2355 tlvList.Add(Tlv::kTimeout);
2356 break;
2357
2358 case kErrorNotFound:
2359 break;
2360
2361 default:
2362 ExitNow(error = kErrorParse);
2363 }
2364
2365 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2366 {
2367 case kErrorNone:
2368 tlvList.Add(Tlv::kSupervisionInterval);
2369 break;
2370
2371 case kErrorNotFound:
2372 supervisionInterval =
2373 (child->GetVersion() <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2374 break;
2375
2376 default:
2377 ExitNow(error = kErrorParse);
2378 }
2379
2380 child->SetSupervisionInterval(supervisionInterval);
2381
2382 switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
2383 {
2384 case kErrorNone:
2385 tlvList.AddElementsFrom(requestedTlvList);
2386 break;
2387 case kErrorNotFound:
2388 break;
2389 default:
2390 ExitNow(error = kErrorParse);
2391 }
2392
2393 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2394 if (child->IsCslSynchronized())
2395 {
2396 ChannelTlvValue cslChannelTlvValue;
2397 uint32_t cslTimeout;
2398
2399 switch (Tlv::Find<CslTimeoutTlv>(aRxInfo.mMessage, cslTimeout))
2400 {
2401 case kErrorNone:
2402 child->SetCslTimeout(cslTimeout);
2403 // MUST include CSL accuracy TLV when request includes CSL timeout
2404 tlvList.Add(Tlv::kCslClockAccuracy);
2405 break;
2406 case kErrorNotFound:
2407 break;
2408 default:
2409 ExitNow(error = kErrorNone);
2410 }
2411
2412 if (Tlv::Find<CslChannelTlv>(aRxInfo.mMessage, cslChannelTlvValue) == kErrorNone)
2413 {
2414 // Special value of zero is used to indicate that
2415 // CSL channel is not specified.
2416 child->SetCslChannel(static_cast<uint8_t>(cslChannelTlvValue.GetChannel()));
2417 }
2418 }
2419 #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2420
2421 child->SetLastHeard(TimerMilli::GetNow());
2422
2423 if (oldMode != child->GetDeviceMode())
2424 {
2425 LogNote("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
2426 child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
2427
2428 childDidChange = true;
2429
2430 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2431 if (child->IsRxOnWhenIdle())
2432 {
2433 // Clear CSL synchronization state
2434 child->SetCslSynchronized(false);
2435 }
2436 #endif
2437
2438 // The `IndirectSender::HandleChildModeChange()` needs to happen
2439 // after "Child Update" message is fully parsed to ensure that
2440 // any registered IPv6 addresses included in the "Child Update"
2441 // are added to the child.
2442
2443 Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
2444 }
2445
2446 if (childDidChange)
2447 {
2448 IgnoreError(mChildTable.StoreChild(*child));
2449 }
2450
2451 #if OPENTHREAD_CONFIG_MULTI_RADIO
2452 // We clear the fragment tag only if the "Child Update Request" is
2453 // from a detached child trying to restore its link with its
2454 // parent which is indicated by the presence of Challenge TLV in
2455 // the message.
2456 if (!challenge.IsEmpty())
2457 {
2458 child->ClearLastRxFragmentTag();
2459 }
2460 #endif
2461
2462 SendChildUpdateResponseToChild(child, aRxInfo.mMessageInfo, tlvList, challenge);
2463
2464 aRxInfo.mClass = RxInfo::kPeerMessage;
2465
2466 exit:
2467 LogProcessError(kTypeChildUpdateRequestOfChild, error);
2468 }
2469
HandleChildUpdateResponseOnParent(RxInfo & aRxInfo)2470 void MleRouter::HandleChildUpdateResponseOnParent(RxInfo &aRxInfo)
2471 {
2472 Error error = kErrorNone;
2473 uint16_t sourceAddress;
2474 uint32_t timeout;
2475 RxChallenge response;
2476 uint8_t status;
2477 uint32_t linkFrameCounter;
2478 uint32_t mleFrameCounter;
2479 LeaderData leaderData;
2480 Child *child;
2481
2482 if ((aRxInfo.mNeighbor == nullptr) || IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()) ||
2483 !Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
2484 {
2485 Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr());
2486 ExitNow(error = kErrorNotFound);
2487 }
2488
2489 child = static_cast<Child *>(aRxInfo.mNeighbor);
2490
2491 switch (aRxInfo.mMessage.ReadResponseTlv(response))
2492 {
2493 case kErrorNone:
2494 VerifyOrExit(response == child->GetChallenge(), error = kErrorSecurity);
2495 break;
2496 case kErrorNotFound:
2497 VerifyOrExit(child->IsStateValid(), error = kErrorSecurity);
2498 response.Clear();
2499 break;
2500 default:
2501 ExitNow(error = kErrorNone);
2502 }
2503
2504 Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
2505
2506 switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
2507 {
2508 case kErrorNone:
2509 if (child->GetRloc16() != sourceAddress)
2510 {
2511 RemoveNeighbor(*child);
2512 ExitNow();
2513 }
2514
2515 break;
2516
2517 case kErrorNotFound:
2518 break;
2519
2520 default:
2521 ExitNow(error = kErrorParse);
2522 }
2523
2524 switch (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status))
2525 {
2526 case kErrorNone:
2527 VerifyOrExit(status != StatusTlv::kError, RemoveNeighbor(*child));
2528 break;
2529 case kErrorNotFound:
2530 break;
2531 default:
2532 ExitNow(error = kErrorParse);
2533 }
2534
2535 switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
2536 {
2537 case kErrorNone:
2538 child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2539 child->SetLinkAckFrameCounter(linkFrameCounter);
2540 break;
2541 case kErrorNotFound:
2542 break;
2543 default:
2544 ExitNow(error = kErrorParse);
2545 }
2546
2547 switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
2548 {
2549 case kErrorNone:
2550 child->SetMleFrameCounter(mleFrameCounter);
2551 break;
2552 case kErrorNotFound:
2553 break;
2554 default:
2555 ExitNow(error = kErrorNone);
2556 }
2557
2558 switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2559 {
2560 case kErrorNone:
2561 child->SetTimeout(timeout);
2562 break;
2563 case kErrorNotFound:
2564 break;
2565 default:
2566 ExitNow(error = kErrorParse);
2567 }
2568
2569 {
2570 uint16_t supervisionInterval;
2571
2572 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2573 {
2574 case kErrorNone:
2575 child->SetSupervisionInterval(supervisionInterval);
2576 break;
2577 case kErrorNotFound:
2578 break;
2579 default:
2580 ExitNow(error = kErrorParse);
2581 }
2582 }
2583
2584 switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2585 {
2586 case kErrorNone:
2587 case kErrorNotFound:
2588 break;
2589 default:
2590 ExitNow(error = kErrorParse);
2591 }
2592
2593 switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2594 {
2595 case kErrorNone:
2596 child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2597 break;
2598 case kErrorNotFound:
2599 break;
2600 default:
2601 ExitNow(error = kErrorParse);
2602 }
2603
2604 SetChildStateToValid(*child);
2605 child->SetLastHeard(TimerMilli::GetNow());
2606 child->SetKeySequence(aRxInfo.mKeySequence);
2607 child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2608
2609 aRxInfo.mClass = response.IsEmpty() ? RxInfo::kPeerMessage : RxInfo::kAuthoritativeMessage;
2610
2611 exit:
2612 LogProcessError(kTypeChildUpdateResponseOfChild, error);
2613 }
2614
HandleDataRequest(RxInfo & aRxInfo)2615 void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
2616 {
2617 Error error = kErrorNone;
2618 TlvList tlvList;
2619 MeshCoP::Timestamp timestamp;
2620
2621 Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2622
2623 VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity);
2624
2625 SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2626
2627 switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2628 {
2629 case kErrorNone:
2630 if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2631 {
2632 break;
2633 }
2634
2635 OT_FALL_THROUGH;
2636
2637 case kErrorNotFound:
2638 tlvList.Add(Tlv::kActiveDataset);
2639 break;
2640
2641 default:
2642 ExitNow(error = kErrorParse);
2643 }
2644
2645 switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2646 {
2647 case kErrorNone:
2648 if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2649 {
2650 break;
2651 }
2652
2653 OT_FALL_THROUGH;
2654
2655 case kErrorNotFound:
2656 tlvList.Add(Tlv::kPendingDataset);
2657 break;
2658
2659 default:
2660 ExitNow(error = kErrorParse);
2661 }
2662
2663 aRxInfo.mClass = RxInfo::kPeerMessage;
2664 ProcessKeySequence(aRxInfo);
2665
2666 SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, &aRxInfo.mMessage);
2667
2668 exit:
2669 LogProcessError(kTypeDataRequest, error);
2670 }
2671
HandleNetworkDataUpdateRouter(void)2672 void MleRouter::HandleNetworkDataUpdateRouter(void)
2673 {
2674 uint16_t delay;
2675
2676 VerifyOrExit(IsRouterOrLeader());
2677
2678 if (IsLeader())
2679 {
2680 SendMulticastDataResponse();
2681 }
2682 else
2683 {
2684 delay = 1 + Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter);
2685 mDelayedSender.ScheduleMulticastDataResponse(delay);
2686 }
2687
2688 SynchronizeChildNetworkData();
2689
2690 exit:
2691 return;
2692 }
2693
SynchronizeChildNetworkData(void)2694 void MleRouter::SynchronizeChildNetworkData(void)
2695 {
2696 VerifyOrExit(IsRouterOrLeader());
2697
2698 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
2699 {
2700 if (child.IsRxOnWhenIdle())
2701 {
2702 continue;
2703 }
2704
2705 if (child.GetNetworkDataVersion() == Get<NetworkData::Leader>().GetVersion(child.GetNetworkDataType()))
2706 {
2707 continue;
2708 }
2709
2710 SuccessOrExit(SendChildUpdateRequestToChild(child));
2711 }
2712
2713 exit:
2714 return;
2715 }
2716
2717 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
SetSteeringData(const Mac::ExtAddress * aExtAddress)2718 void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress)
2719 {
2720 Mac::ExtAddress nullExtAddr;
2721 Mac::ExtAddress allowAnyExtAddr;
2722
2723 nullExtAddr.Clear();
2724 allowAnyExtAddr.Fill(0xff);
2725
2726 if ((aExtAddress == nullptr) || (*aExtAddress == nullExtAddr))
2727 {
2728 mSteeringData.Clear();
2729 }
2730 else if (*aExtAddress == allowAnyExtAddr)
2731 {
2732 mSteeringData.SetToPermitAllJoiners();
2733 }
2734 else
2735 {
2736 Mac::ExtAddress joinerId;
2737
2738 mSteeringData.Init();
2739 MeshCoP::ComputeJoinerId(*aExtAddress, joinerId);
2740 mSteeringData.UpdateBloomFilter(joinerId);
2741 }
2742 }
2743 #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2744
HandleDiscoveryRequest(RxInfo & aRxInfo)2745 void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
2746 {
2747 Error error = kErrorNone;
2748 Tlv::ParsedInfo tlvInfo;
2749 MeshCoP::DiscoveryRequestTlv discoveryRequestTlv;
2750 MeshCoP::ExtendedPanId extPanId;
2751 OffsetRange offsetRange;
2752 DiscoveryResponseInfo responseInfo;
2753
2754 Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2755
2756 discoveryRequestTlv.SetLength(0);
2757
2758 VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2759
2760 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange));
2761
2762 for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(tlvInfo.GetSize()))
2763 {
2764 SuccessOrExit(error = tlvInfo.ParseFrom(aRxInfo.mMessage, offsetRange));
2765
2766 if (tlvInfo.mIsExtended)
2767 {
2768 continue;
2769 }
2770
2771 switch (tlvInfo.mType)
2772 {
2773 case MeshCoP::Tlv::kDiscoveryRequest:
2774 SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryRequestTlv));
2775 VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse);
2776
2777 break;
2778
2779 case MeshCoP::Tlv::kExtendedPanId:
2780 SuccessOrExit(
2781 error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offsetRange.GetOffset(), extPanId));
2782 VerifyOrExit(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId() != extPanId, error = kErrorDrop);
2783
2784 break;
2785
2786 default:
2787 break;
2788 }
2789 }
2790
2791 if (discoveryRequestTlv.IsValid())
2792 {
2793 if (mDiscoveryRequestCallback.IsSet())
2794 {
2795 otThreadDiscoveryRequestInfo info;
2796
2797 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&info.mExtAddress));
2798 info.mVersion = discoveryRequestTlv.GetVersion();
2799 info.mIsJoiner = discoveryRequestTlv.IsJoiner();
2800
2801 mDiscoveryRequestCallback.Invoke(&info);
2802 }
2803
2804 if (discoveryRequestTlv.IsJoiner())
2805 {
2806 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2807 if (!mSteeringData.IsEmpty())
2808 {
2809 }
2810 else // if steering data is not set out of band, fall back to network data
2811 #endif
2812 {
2813 VerifyOrExit(Get<NetworkData::Leader>().IsJoiningAllowed(), error = kErrorSecurity);
2814 }
2815 }
2816 }
2817
2818 responseInfo.mPanId = aRxInfo.mMessage.GetPanId();
2819
2820 #if OPENTHREAD_CONFIG_MULTI_RADIO
2821 // Send the MLE Discovery Response message on same radio link
2822 // from which the "MLE Discover Request" message was received.
2823 responseInfo.mRadioType = aRxInfo.mMessage.GetRadioType();
2824 #endif
2825
2826 mDelayedSender.ScheduleDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), responseInfo,
2827 1 + Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter));
2828
2829 exit:
2830 LogProcessError(kTypeDiscoveryRequest, error);
2831 }
2832
SendDiscoveryResponse(const Ip6::Address & aDestination,const DiscoveryResponseInfo & aInfo)2833 Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const DiscoveryResponseInfo &aInfo)
2834 {
2835 Error error = kErrorNone;
2836 TxMessage *message;
2837 uint16_t startOffset;
2838 Tlv tlv;
2839 MeshCoP::DiscoveryResponseTlv discoveryResponseTlv;
2840
2841 VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
2842 message->SetDirectTransmission();
2843 message->SetPanId(aInfo.mPanId);
2844 #if OPENTHREAD_CONFIG_MULTI_RADIO
2845 message->SetRadioType(aInfo.mRadioType);
2846 #endif
2847
2848 tlv.SetType(Tlv::kDiscovery);
2849 SuccessOrExit(error = message->Append(tlv));
2850
2851 startOffset = message->GetLength();
2852
2853 discoveryResponseTlv.Init();
2854 discoveryResponseTlv.SetVersion(kThreadVersion);
2855
2856 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
2857 if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled)
2858 {
2859 SuccessOrExit(
2860 error = Tlv::Append<MeshCoP::CommissionerUdpPortTlv>(*message, Get<MeshCoP::BorderAgent>().GetUdpPort()));
2861
2862 discoveryResponseTlv.SetNativeCommissioner(true);
2863 }
2864 else
2865 #endif
2866 {
2867 discoveryResponseTlv.SetNativeCommissioner(false);
2868 }
2869
2870 if (Get<KeyManager>().GetSecurityPolicy().mCommercialCommissioningEnabled)
2871 {
2872 discoveryResponseTlv.SetCommercialCommissioningMode(true);
2873 }
2874
2875 SuccessOrExit(error = discoveryResponseTlv.AppendTo(*message));
2876
2877 SuccessOrExit(
2878 error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
2879
2880 SuccessOrExit(error = Tlv::Append<MeshCoP::NetworkNameTlv>(
2881 *message, Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsCString()));
2882
2883 SuccessOrExit(error = message->AppendSteeringDataTlv());
2884
2885 SuccessOrExit(
2886 error = Tlv::Append<MeshCoP::JoinerUdpPortTlv>(*message, Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()));
2887
2888 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)
2889 if (!Get<MeshCoP::NetworkNameManager>().IsDefaultDomainNameSet())
2890 {
2891 SuccessOrExit(error = Tlv::Append<MeshCoP::ThreadDomainNameTlv>(
2892 *message, Get<MeshCoP::NetworkNameManager>().GetDomainName().GetAsCString()));
2893 }
2894 #endif
2895
2896 tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
2897 message->Write(startOffset - sizeof(tlv), tlv);
2898
2899 SuccessOrExit(error = message->SendTo(aDestination));
2900
2901 Log(kMessageSend, kTypeDiscoveryResponse, aDestination);
2902
2903 exit:
2904 FreeMessageOnError(message, error);
2905 LogProcessError(kTypeDiscoveryResponse, error);
2906 return error;
2907 }
2908
SendChildIdResponse(Child & aChild)2909 Error MleRouter::SendChildIdResponse(Child &aChild)
2910 {
2911 Error error = kErrorNone;
2912 Ip6::Address destination;
2913 TxMessage *message;
2914
2915 VerifyOrExit((message = NewMleMessage(kCommandChildIdResponse)) != nullptr, error = kErrorNoBufs);
2916 SuccessOrExit(error = message->AppendSourceAddressTlv());
2917 SuccessOrExit(error = message->AppendLeaderDataTlv());
2918 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
2919
2920 if ((aChild.GetRloc16() == 0) || !HasMatchingRouterIdWith(aChild.GetRloc16()))
2921 {
2922 uint16_t rloc16;
2923
2924 // Pick next Child ID that is not being used
2925 do
2926 {
2927 mNextChildId++;
2928
2929 if (mNextChildId > kMaxChildId)
2930 {
2931 mNextChildId = kMinChildId;
2932 }
2933
2934 rloc16 = Get<Mac::Mac>().GetShortAddress() | mNextChildId;
2935
2936 } while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
2937
2938 aChild.SetRloc16(rloc16);
2939 }
2940
2941 SuccessOrExit(error = message->AppendAddress16Tlv(aChild.GetRloc16()));
2942
2943 for (uint8_t i = 0; i < Child::kMaxRequestTlvs; i++)
2944 {
2945 switch (aChild.GetRequestTlv(i))
2946 {
2947 case Tlv::kNetworkData:
2948 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
2949 break;
2950
2951 case Tlv::kRoute:
2952 SuccessOrExit(error = message->AppendRouteTlv());
2953 break;
2954
2955 case Tlv::kActiveDataset:
2956 SuccessOrExit(error = message->AppendActiveDatasetTlv());
2957 break;
2958
2959 case Tlv::kPendingDataset:
2960 SuccessOrExit(error = message->AppendPendingDatasetTlv());
2961 break;
2962
2963 case Tlv::kSupervisionInterval:
2964 SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild.GetSupervisionInterval()));
2965 break;
2966
2967 default:
2968 break;
2969 }
2970 }
2971
2972 if (!aChild.IsFullThreadDevice())
2973 {
2974 SuccessOrExit(error = message->AppendAddressRegistrationTlv(aChild));
2975 }
2976
2977 SetChildStateToValid(aChild);
2978
2979 if (!aChild.IsRxOnWhenIdle())
2980 {
2981 Get<IndirectSender>().SetChildUseShortAddress(aChild, false);
2982 }
2983
2984 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2985 if (aChild.IsTimeSyncEnabled())
2986 {
2987 message->SetTimeSync(true);
2988 }
2989 #endif
2990
2991 destination.SetToLinkLocalAddress(aChild.GetExtAddress());
2992 SuccessOrExit(error = message->SendTo(destination));
2993
2994 Log(kMessageSend, kTypeChildIdResponse, destination, aChild.GetRloc16());
2995
2996 exit:
2997 FreeMessageOnError(message, error);
2998 return error;
2999 }
3000
SendChildUpdateRequestToChild(Child & aChild)3001 Error MleRouter::SendChildUpdateRequestToChild(Child &aChild)
3002 {
3003 static const uint8_t kTlvs[] = {Tlv::kTimeout, Tlv::kAddressRegistration};
3004
3005 Error error = kErrorNone;
3006 Ip6::Address destination;
3007 TxMessage *message = nullptr;
3008
3009 if (!aChild.IsRxOnWhenIdle() && aChild.IsStateRestoring())
3010 {
3011 // No need to send the resync "Child Update Request"
3012 // to the sleepy child if there is one already
3013 // queued.
3014
3015 VerifyOrExit(!Get<IndirectSender>().HasQueuedMessageForSleepyChild(aChild, IsMessageChildUpdateRequest));
3016 }
3017
3018 Get<MeshForwarder>().RemoveMessagesForChild(aChild, IsMessageChildUpdateRequest);
3019
3020 VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
3021 SuccessOrExit(error = message->AppendSourceAddressTlv());
3022 SuccessOrExit(error = message->AppendLeaderDataTlv());
3023 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
3024 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3025
3026 if (aChild.IsStateValid())
3027 {
3028 SuccessOrExit(error = message->AppendLinkMarginTlv(aChild.GetLinkInfo().GetLinkMargin()));
3029 }
3030 else
3031 {
3032 SuccessOrExit(error = message->AppendTlvRequestTlv(kTlvs));
3033
3034 if (!aChild.IsStateRestored())
3035 {
3036 // A random challenge is generated and saved when `aChild`
3037 // is first initialized in `kStateRestored`. We will use
3038 // the saved challenge here. This prevents overwriting
3039 // the saved challenge when the child is also detached
3040 // and happens to send a "Parent Request" in the window
3041 // where the parent transitions to the router/leader role
3042 // and before the parent sends the "Child Update Request".
3043 // This ensures that the same random challenge is
3044 // included in both "Parent Response" and "Child Update
3045 // Response," guaranteeing proper acceptance of the
3046 // child's "Child ID request".
3047
3048 aChild.GenerateChallenge();
3049 }
3050
3051 SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge()));
3052 }
3053
3054 destination.SetToLinkLocalAddress(aChild.GetExtAddress());
3055 SuccessOrExit(error = message->SendTo(destination));
3056
3057 if (aChild.IsRxOnWhenIdle())
3058 {
3059 // only try to send a single Child Update Request message to an rx-on-when-idle child
3060 aChild.SetState(Child::kStateChildUpdateRequest);
3061 }
3062
3063 Log(kMessageSend, kTypeChildUpdateRequestOfChild, destination, aChild.GetRloc16());
3064
3065 exit:
3066 FreeMessageOnError(message, error);
3067 return error;
3068 }
3069
SendChildUpdateResponseToChild(Child * aChild,const Ip6::MessageInfo & aMessageInfo,const TlvList & aTlvList,const RxChallenge & aChallenge)3070 void MleRouter::SendChildUpdateResponseToChild(Child *aChild,
3071 const Ip6::MessageInfo &aMessageInfo,
3072 const TlvList &aTlvList,
3073 const RxChallenge &aChallenge)
3074 {
3075 Error error = kErrorNone;
3076 TxMessage *message;
3077
3078 VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs);
3079
3080 for (uint8_t tlvType : aTlvList)
3081 {
3082 // Add all TLV types that do not depend on `child`
3083
3084 switch (tlvType)
3085 {
3086 case Tlv::kStatus:
3087 SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError));
3088 break;
3089
3090 case Tlv::kLeaderData:
3091 SuccessOrExit(error = message->AppendLeaderDataTlv());
3092 break;
3093
3094 case Tlv::kResponse:
3095 SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
3096 break;
3097
3098 case Tlv::kSourceAddress:
3099 SuccessOrExit(error = message->AppendSourceAddressTlv());
3100 break;
3101
3102 case Tlv::kMleFrameCounter:
3103 SuccessOrExit(error = message->AppendMleFrameCounterTlv());
3104 break;
3105
3106 case Tlv::kLinkFrameCounter:
3107 SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
3108 break;
3109 }
3110
3111 // Make sure `child` is not null before adding TLV types
3112 // that can depend on it.
3113
3114 if (aChild == nullptr)
3115 {
3116 continue;
3117 }
3118
3119 switch (tlvType)
3120 {
3121 case Tlv::kAddressRegistration:
3122 SuccessOrExit(error = message->AppendAddressRegistrationTlv(*aChild));
3123 break;
3124
3125 case Tlv::kMode:
3126 SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode()));
3127 break;
3128
3129 case Tlv::kNetworkData:
3130 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild->GetNetworkDataType()));
3131 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3132 break;
3133
3134 case Tlv::kTimeout:
3135 SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
3136 break;
3137
3138 case Tlv::kLinkMargin:
3139 SuccessOrExit(error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin()));
3140 break;
3141
3142 case Tlv::kSupervisionInterval:
3143 SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild->GetSupervisionInterval()));
3144 break;
3145
3146 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
3147 case Tlv::kCslClockAccuracy:
3148 if (!aChild->IsRxOnWhenIdle())
3149 {
3150 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
3151 }
3152 break;
3153 #endif
3154 }
3155 }
3156
3157 SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
3158
3159 if (aChild == nullptr)
3160 {
3161 Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr());
3162 }
3163 else
3164 {
3165 Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr(), aChild->GetRloc16());
3166 }
3167
3168 exit:
3169 FreeMessageOnError(message, error);
3170 }
3171
SendMulticastDataResponse(void)3172 void MleRouter::SendMulticastDataResponse(void)
3173 {
3174 Ip6::Address destination;
3175 TlvList tlvList;
3176
3177 destination.SetToLinkLocalAllNodesMulticast();
3178 tlvList.Add(Tlv::kNetworkData);
3179 SendDataResponse(destination, tlvList);
3180 }
3181
SendDataResponse(const Ip6::Address & aDestination,const TlvList & aTlvList,const Message * aRequestMessage)3182 void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
3183 const TlvList &aTlvList,
3184 const Message *aRequestMessage)
3185 {
3186 OT_UNUSED_VARIABLE(aRequestMessage);
3187
3188 Error error = kErrorNone;
3189 TxMessage *message = nullptr;
3190 Neighbor *neighbor;
3191
3192 VerifyOrExit(IsAttached());
3193
3194 if (mRetrieveNewNetworkData)
3195 {
3196 LogInfo("Suppressing Data Response - waiting for new network data");
3197 ExitNow();
3198 }
3199
3200 VerifyOrExit((message = NewMleMessage(kCommandDataResponse)) != nullptr, error = kErrorNoBufs);
3201 SuccessOrExit(error = message->AppendSourceAddressTlv());
3202 SuccessOrExit(error = message->AppendLeaderDataTlv());
3203 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3204
3205 for (uint8_t tlvType : aTlvList)
3206 {
3207 switch (tlvType)
3208 {
3209 case Tlv::kNetworkData:
3210 neighbor = mNeighborTable.FindNeighbor(aDestination);
3211 SuccessOrExit(error = message->AppendNetworkDataTlv((neighbor != nullptr) ? neighbor->GetNetworkDataType()
3212 : NetworkData::kFullSet));
3213 break;
3214
3215 case Tlv::kActiveDataset:
3216 SuccessOrExit(error = message->AppendActiveDatasetTlv());
3217 break;
3218
3219 case Tlv::kPendingDataset:
3220 SuccessOrExit(error = message->AppendPendingDatasetTlv());
3221 break;
3222
3223 case Tlv::kRoute:
3224 SuccessOrExit(error = message->AppendRouteTlv());
3225 break;
3226
3227 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3228 case Tlv::kLinkMetricsReport:
3229 OT_ASSERT(aRequestMessage != nullptr);
3230 neighbor = mNeighborTable.FindNeighbor(aDestination);
3231 VerifyOrExit(neighbor != nullptr, error = kErrorInvalidState);
3232 SuccessOrExit(error = Get<LinkMetrics::Subject>().AppendReport(*message, *aRequestMessage, *neighbor));
3233 break;
3234 #endif
3235 }
3236 }
3237
3238 SuccessOrExit(error = message->SendTo(aDestination));
3239 Log(kMessageSend, kTypeDataResponse, aDestination);
3240
3241 exit:
3242 FreeMessageOnError(message, error);
3243 LogSendError(kTypeDataResponse, error);
3244 }
3245
RemoveRouterLink(Router & aRouter)3246 void MleRouter::RemoveRouterLink(Router &aRouter)
3247 {
3248 switch (mRole)
3249 {
3250 case kRoleChild:
3251 if (&aRouter == &mParent)
3252 {
3253 IgnoreError(BecomeDetached());
3254 }
3255 break;
3256
3257 case kRoleRouter:
3258 case kRoleLeader:
3259 mRouterTable.RemoveRouterLink(aRouter);
3260 break;
3261
3262 default:
3263 break;
3264 }
3265 }
3266
RemoveNeighbor(Neighbor & aNeighbor)3267 void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
3268 {
3269 VerifyOrExit(!aNeighbor.IsStateInvalid());
3270
3271 if (&aNeighbor == &mParent)
3272 {
3273 if (IsChild())
3274 {
3275 IgnoreError(BecomeDetached());
3276 }
3277 }
3278 else if (&aNeighbor == &GetParentCandidate())
3279 {
3280 ClearParentCandidate();
3281 }
3282 else if (IsChildRloc16(aNeighbor.GetRloc16()))
3283 {
3284 OT_ASSERT(mChildTable.Contains(aNeighbor));
3285
3286 if (aNeighbor.IsStateValidOrRestoring())
3287 {
3288 mNeighborTable.Signal(NeighborTable::kChildRemoved, aNeighbor);
3289 }
3290
3291 Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
3292
3293 if (aNeighbor.IsFullThreadDevice())
3294 {
3295 Get<AddressResolver>().RemoveEntriesForRloc16(aNeighbor.GetRloc16());
3296 }
3297
3298 mChildTable.RemoveStoredChild(static_cast<Child &>(aNeighbor));
3299 }
3300 else if (aNeighbor.IsStateValid())
3301 {
3302 OT_ASSERT(mRouterTable.Contains(aNeighbor));
3303
3304 mNeighborTable.Signal(NeighborTable::kRouterRemoved, aNeighbor);
3305 mRouterTable.RemoveRouterLink(static_cast<Router &>(aNeighbor));
3306 }
3307
3308 aNeighbor.GetLinkInfo().Clear();
3309 aNeighbor.SetState(Neighbor::kStateInvalid);
3310 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3311 aNeighbor.RemoveAllForwardTrackingSeriesInfo();
3312 #endif
3313
3314 exit:
3315 return;
3316 }
3317
SetPreferredRouterId(uint8_t aRouterId)3318 Error MleRouter::SetPreferredRouterId(uint8_t aRouterId)
3319 {
3320 Error error = kErrorNone;
3321
3322 VerifyOrExit(IsDetached() || IsDisabled(), error = kErrorInvalidState);
3323
3324 mPreviousRouterId = aRouterId;
3325
3326 exit:
3327 return error;
3328 }
3329
SetRouterId(uint8_t aRouterId)3330 void MleRouter::SetRouterId(uint8_t aRouterId)
3331 {
3332 mRouterId = aRouterId;
3333 mPreviousRouterId = mRouterId;
3334 }
3335
SendAddressSolicit(ThreadStatusTlv::Status aStatus)3336 Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
3337 {
3338 Error error = kErrorNone;
3339 Tmf::MessageInfo messageInfo(GetInstance());
3340 Coap::Message *message = nullptr;
3341
3342 VerifyOrExit(!mAddressSolicitPending);
3343
3344 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressSolicit);
3345 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3346
3347 SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3348
3349 if (IsRouterIdValid(mPreviousRouterId))
3350 {
3351 SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mPreviousRouterId)));
3352 }
3353
3354 SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
3355
3356 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3357 SuccessOrExit(error = Tlv::Append<XtalAccuracyTlv>(*message, otPlatTimeGetXtalAccuracy()));
3358 #endif
3359
3360 messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3361
3362 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this));
3363 mAddressSolicitPending = true;
3364
3365 Log(kMessageSend, kTypeAddressSolicit, messageInfo.GetPeerAddr());
3366
3367 exit:
3368 FreeMessageOnError(message, error);
3369 return error;
3370 }
3371
SendAddressRelease(void)3372 void MleRouter::SendAddressRelease(void)
3373 {
3374 Error error = kErrorNone;
3375 Tmf::MessageInfo messageInfo(GetInstance());
3376 Coap::Message *message;
3377
3378 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressRelease);
3379 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3380
3381 SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mRouterId)));
3382 SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3383
3384 messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3385
3386 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
3387
3388 Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr());
3389
3390 exit:
3391 FreeMessageOnError(message, error);
3392 LogSendError(kTypeAddressRelease, error);
3393 }
3394
HandleAddressSolicitResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aResult)3395 void MleRouter::HandleAddressSolicitResponse(void *aContext,
3396 otMessage *aMessage,
3397 const otMessageInfo *aMessageInfo,
3398 otError aResult)
3399 {
3400 static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(AsCoapMessagePtr(aMessage),
3401 AsCoreTypePtr(aMessageInfo), aResult);
3402 }
3403
HandleAddressSolicitResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)3404 void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage,
3405 const Ip6::MessageInfo *aMessageInfo,
3406 Error aResult)
3407 {
3408 uint8_t status;
3409 uint16_t rloc16;
3410 ThreadRouterMaskTlv routerMaskTlv;
3411 uint8_t routerId;
3412 Router *router;
3413
3414 mAddressSolicitPending = false;
3415
3416 VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
3417
3418 VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
3419
3420 Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
3421
3422 SuccessOrExit(Tlv::Find<ThreadStatusTlv>(*aMessage, status));
3423
3424 if (status != ThreadStatusTlv::kSuccess)
3425 {
3426 mAddressSolicitRejected = true;
3427
3428 if (IsRouterIdValid(mPreviousRouterId))
3429 {
3430 if (HasChildren())
3431 {
3432 RemoveChildren();
3433 }
3434
3435 SetRouterId(kInvalidRouterId);
3436 }
3437
3438 ExitNow();
3439 }
3440
3441 SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
3442 routerId = RouterIdFromRloc16(rloc16);
3443
3444 SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
3445 VerifyOrExit(routerMaskTlv.IsValid());
3446
3447 SetAlternateRloc16(GetRloc16());
3448
3449 SetRouterId(routerId);
3450
3451 SetStateRouter(Rloc16FromRouterId(mRouterId));
3452
3453 // We keep the router table next hop and cost as what we had as a
3454 // REED, i.e., our parent was the next hop towards all other
3455 // routers and we tracked its cost towards them. As an FTD child,
3456 // we may have established links with a subset of neighboring routers.
3457 // We ensure to clear these links to avoid using them (since will
3458 // be rejected by the neighbor).
3459
3460 mRouterTable.ClearNeighbors();
3461
3462 mRouterTable.UpdateRouterIdSet(routerMaskTlv.GetIdSequence(), routerMaskTlv.GetAssignedRouterIdMask());
3463
3464 router = mRouterTable.FindRouterById(routerId);
3465 VerifyOrExit(router != nullptr);
3466 router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
3467 router->SetNextHopToInvalid();
3468
3469 // Ensure we have our parent as a neighboring router, copying the
3470 // `mParent` entry.
3471
3472 router = mRouterTable.FindRouterById(mParent.GetRouterId());
3473 VerifyOrExit(router != nullptr);
3474 router->SetFrom(mParent);
3475 router->SetState(Neighbor::kStateValid);
3476 router->SetNextHopToInvalid();
3477
3478 // Ensure we have a next hop and cost towards leader.
3479 if (mRouterTable.GetPathCostToLeader() >= kMaxRouteCost)
3480 {
3481 Router *leader = mRouterTable.GetLeader();
3482
3483 OT_ASSERT(leader != nullptr);
3484 leader->SetNextHopAndCost(RouterIdFromRloc16(mParent.GetRloc16()), mParent.GetLeaderCost());
3485 }
3486
3487 // We send a unicast Link Request to our former parent if its
3488 // version is earlier than 1.3. This is to address a potential
3489 // compatibility issue with some non-OpenThread stacks which may
3490 // ignore MLE Advertisements from a former/existing child.
3491
3492 if (mParent.GetVersion() < kThreadVersion1p3)
3493 {
3494 SendLinkRequest(&mParent);
3495 }
3496
3497 // We send an Advertisement to inform our former parent of our
3498 // newly allocated Router ID. This will cause the parent to
3499 // reset its advertisement trickle timer which can help speed
3500 // up the dissemination of the new Router ID to other routers.
3501 // This can also help with quicker link establishment with our
3502 // former parent and other routers.
3503 SendMulticastAdvertisement();
3504
3505 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
3506 {
3507 IgnoreError(SendChildIdResponse(child));
3508 }
3509
3510 exit:
3511 InformPreviousChannel();
3512 }
3513
SetChildRouterLinks(uint8_t aChildRouterLinks)3514 Error MleRouter::SetChildRouterLinks(uint8_t aChildRouterLinks)
3515 {
3516 Error error = kErrorNone;
3517
3518 VerifyOrExit(IsDisabled(), error = kErrorInvalidState);
3519 mChildRouterLinks = aChildRouterLinks;
3520 exit:
3521 return error;
3522 }
3523
IsExpectedToBecomeRouterSoon(void) const3524 bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
3525 {
3526 static constexpr uint8_t kMaxDelay = 10;
3527
3528 return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
3529 ((mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay) ||
3530 mAddressSolicitPending);
3531 }
3532
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3533 template <> void MleRouter::HandleTmf<kUriAddressSolicit>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3534 {
3535 Error error = kErrorNone;
3536 ThreadStatusTlv::Status responseStatus = ThreadStatusTlv::kNoAddressAvailable;
3537 Router *router = nullptr;
3538 Mac::ExtAddress extAddress;
3539 uint16_t rloc16;
3540 uint8_t status;
3541
3542 VerifyOrExit(mRole == kRoleLeader, error = kErrorInvalidState);
3543
3544 VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
3545
3546 Log(kMessageReceive, kTypeAddressSolicit, aMessageInfo.GetPeerAddr());
3547
3548 SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3549 SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
3550
3551 switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
3552 {
3553 case kErrorNone:
3554 break;
3555 case kErrorNotFound:
3556 rloc16 = kInvalidRloc16;
3557 break;
3558 default:
3559 ExitNow(error = kErrorParse);
3560 }
3561
3562 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3563 {
3564 uint16_t xtalAccuracy;
3565
3566 SuccessOrExit(Tlv::Find<XtalAccuracyTlv>(aMessage, xtalAccuracy));
3567 VerifyOrExit(xtalAccuracy <= Get<TimeSync>().GetXtalThreshold());
3568 }
3569 #endif
3570
3571 router = mRouterTable.FindRouter(extAddress);
3572
3573 if (router != nullptr)
3574 {
3575 responseStatus = ThreadStatusTlv::kSuccess;
3576 ExitNow();
3577 }
3578
3579 switch (status)
3580 {
3581 case ThreadStatusTlv::kTooFewRouters:
3582 VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
3583 break;
3584
3585 case ThreadStatusTlv::kHaveChildIdRequest:
3586 case ThreadStatusTlv::kParentPartitionChange:
3587 break;
3588
3589 case ThreadStatusTlv::kBorderRouterRequest:
3590 if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
3591 (Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
3592 kRouterUpgradeBorderRouterRequestThreshold))
3593 {
3594 LogInfo("Rejecting BR %s router role req - have %u BR routers", extAddress.ToString().AsCString(),
3595 kRouterUpgradeBorderRouterRequestThreshold);
3596 ExitNow();
3597 }
3598 break;
3599
3600 default:
3601 responseStatus = ThreadStatusTlv::kUnrecognizedStatus;
3602 ExitNow();
3603 }
3604
3605 if (rloc16 != kInvalidRloc16)
3606 {
3607 router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16));
3608
3609 if (router != nullptr)
3610 {
3611 LogInfo("Router id %u requested and provided!", RouterIdFromRloc16(rloc16));
3612 }
3613 }
3614
3615 if (router == nullptr)
3616 {
3617 router = mRouterTable.Allocate();
3618 VerifyOrExit(router != nullptr);
3619 }
3620
3621 router->SetExtAddress(extAddress);
3622 responseStatus = ThreadStatusTlv::kSuccess;
3623
3624 exit:
3625 if (error == kErrorNone)
3626 {
3627 SendAddressSolicitResponse(aMessage, responseStatus, router, aMessageInfo);
3628 }
3629 }
3630
SendAddressSolicitResponse(const Coap::Message & aRequest,ThreadStatusTlv::Status aResponseStatus,const Router * aRouter,const Ip6::MessageInfo & aMessageInfo)3631 void MleRouter::SendAddressSolicitResponse(const Coap::Message &aRequest,
3632 ThreadStatusTlv::Status aResponseStatus,
3633 const Router *aRouter,
3634 const Ip6::MessageInfo &aMessageInfo)
3635 {
3636 Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
3637
3638 VerifyOrExit(message != nullptr);
3639
3640 SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aResponseStatus));
3641
3642 if (aRouter != nullptr)
3643 {
3644 ThreadRouterMaskTlv routerMaskTlv;
3645
3646 SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aRouter->GetRloc16()));
3647
3648 routerMaskTlv.Init();
3649 routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3650 mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask());
3651
3652 SuccessOrExit(routerMaskTlv.AppendTo(*message));
3653 }
3654
3655 SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
3656 message = nullptr;
3657
3658 Log(kMessageSend, kTypeAddressReply, aMessageInfo.GetPeerAddr());
3659
3660 // If assigning a new RLOC16 (e.g., on promotion of a child to
3661 // router role) we clear any address cache entries associated
3662 // with the old RLOC16 unless the sender is a direct child. For
3663 // direct children, we retain the cache entries to allow
3664 // association with the promoted router's new RLOC16 upon
3665 // receiving its Link Advertisement.
3666
3667 if ((aResponseStatus == ThreadStatusTlv::kSuccess) && (aRouter != nullptr))
3668 {
3669 uint16_t oldRloc16;
3670
3671 VerifyOrExit(IsRoutingLocator(aMessageInfo.GetPeerAddr()));
3672 oldRloc16 = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
3673
3674 VerifyOrExit(oldRloc16 != aRouter->GetRloc16());
3675 VerifyOrExit(!RouterIdMatch(oldRloc16, GetRloc16()));
3676 Get<AddressResolver>().RemoveEntriesForRloc16(oldRloc16);
3677 }
3678
3679 exit:
3680 FreeMessage(message);
3681 }
3682
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3683 template <> void MleRouter::HandleTmf<kUriAddressRelease>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3684 {
3685 uint16_t rloc16;
3686 Mac::ExtAddress extAddress;
3687 uint8_t routerId;
3688 Router *router;
3689
3690 VerifyOrExit(mRole == kRoleLeader);
3691
3692 VerifyOrExit(aMessage.IsConfirmablePostRequest());
3693
3694 Log(kMessageReceive, kTypeAddressRelease, aMessageInfo.GetPeerAddr());
3695
3696 SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16));
3697 SuccessOrExit(Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3698
3699 routerId = RouterIdFromRloc16(rloc16);
3700 router = mRouterTable.FindRouterById(routerId);
3701
3702 VerifyOrExit((router != nullptr) && (router->GetExtAddress() == extAddress));
3703
3704 IgnoreError(mRouterTable.Release(routerId));
3705
3706 SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
3707
3708 Log(kMessageSend, kTypeAddressReleaseReply, aMessageInfo.GetPeerAddr());
3709
3710 exit:
3711 return;
3712 }
3713
FillConnectivityTlv(ConnectivityTlv & aTlv)3714 void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
3715 {
3716 int8_t parentPriority = kParentPriorityMedium;
3717
3718 if (mParentPriority != kParentPriorityUnspecified)
3719 {
3720 parentPriority = mParentPriority;
3721 }
3722 else
3723 {
3724 uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
3725 uint16_t maxAllowed = mChildTable.GetMaxChildrenAllowed();
3726
3727 if ((maxAllowed - numChildren) < (maxAllowed / 3))
3728 {
3729 parentPriority = kParentPriorityLow;
3730 }
3731 else
3732 {
3733 parentPriority = kParentPriorityMedium;
3734 }
3735 }
3736
3737 aTlv.SetParentPriority(parentPriority);
3738
3739 aTlv.SetLinkQuality1(0);
3740 aTlv.SetLinkQuality2(0);
3741 aTlv.SetLinkQuality3(0);
3742
3743 if (IsChild())
3744 {
3745 aTlv.IncrementLinkQuality(mParent.GetLinkQualityIn());
3746 }
3747
3748 for (const Router &router : Get<RouterTable>())
3749 {
3750 if (router.GetRloc16() == GetRloc16())
3751 {
3752 continue;
3753 }
3754
3755 if (!router.IsStateValid())
3756 {
3757 continue;
3758 }
3759
3760 aTlv.IncrementLinkQuality(router.GetTwoWayLinkQuality());
3761 }
3762
3763 aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
3764 aTlv.SetLeaderCost(Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost));
3765 aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3766 aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
3767 aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
3768 }
3769
ShouldDowngrade(uint8_t aNeighborId,const RouteTlv & aRouteTlv) const3770 bool MleRouter::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
3771 {
3772 // Determine whether all conditions are satisfied for the router
3773 // to downgrade after receiving info for a neighboring router
3774 // with Router ID `aNeighborId` along with its `aRouteTlv`.
3775
3776 bool shouldDowngrade = false;
3777 uint8_t activeRouterCount = mRouterTable.GetActiveRouterCount();
3778 uint8_t count;
3779
3780 VerifyOrExit(IsRouter());
3781 VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
3782
3783 VerifyOrExit(!mRouterRoleTransition.IsPending());
3784
3785 VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
3786
3787 // Check that we have at least `kMinDowngradeNeighbors`
3788 // neighboring routers with two-way link quality of 2 or better.
3789
3790 count = 0;
3791
3792 for (const Router &router : mRouterTable)
3793 {
3794 if (!router.IsStateValid() || (router.GetTwoWayLinkQuality() < kLinkQuality2))
3795 {
3796 continue;
3797 }
3798
3799 count++;
3800
3801 if (count >= kMinDowngradeNeighbors)
3802 {
3803 break;
3804 }
3805 }
3806
3807 VerifyOrExit(count >= kMinDowngradeNeighbors);
3808
3809 // Check that we have fewer children than three times the number
3810 // of excess routers (defined as the difference between number of
3811 // active routers and `mRouterDowngradeThreshold`).
3812
3813 count = activeRouterCount - mRouterDowngradeThreshold;
3814 VerifyOrExit(mChildTable.GetNumChildren(Child::kInStateValid) < count * 3);
3815
3816 // Check that the neighbor has as good or better-quality links to
3817 // same routers.
3818
3819 VerifyOrExit(NeighborHasComparableConnectivity(aRouteTlv, aNeighborId));
3820
3821 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3822 // Check if we are eligible to be router due to being a BR.
3823 VerifyOrExit(!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter());
3824 #endif
3825
3826 shouldDowngrade = true;
3827
3828 exit:
3829 return shouldDowngrade;
3830 }
3831
NeighborHasComparableConnectivity(const RouteTlv & aRouteTlv,uint8_t aNeighborId) const3832 bool MleRouter::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const
3833 {
3834 // Check whether the neighboring router with Router ID `aNeighborId`
3835 // (along with its `aRouteTlv`) has as good or better-quality links
3836 // to all our neighboring routers which have a two-way link quality
3837 // of two or better.
3838
3839 bool isComparable = true;
3840
3841 for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId;
3842 index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
3843 {
3844 const Router *router;
3845 LinkQuality localLinkQuality;
3846 LinkQuality peerLinkQuality;
3847
3848 if ((routerId == mRouterId) || (routerId == aNeighborId))
3849 {
3850 continue;
3851 }
3852
3853 router = mRouterTable.FindRouterById(routerId);
3854
3855 if ((router == nullptr) || !router->IsStateValid())
3856 {
3857 continue;
3858 }
3859
3860 localLinkQuality = router->GetTwoWayLinkQuality();
3861
3862 if (localLinkQuality < kLinkQuality2)
3863 {
3864 continue;
3865 }
3866
3867 // `router` is our neighbor with two-way link quality of
3868 // at least two. Check that `aRouteTlv` has as good or
3869 // better-quality link to it as well.
3870
3871 if (!aRouteTlv.IsRouterIdSet(routerId))
3872 {
3873 ExitNow(isComparable = false);
3874 }
3875
3876 peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index));
3877
3878 if (peerLinkQuality < localLinkQuality)
3879 {
3880 ExitNow(isComparable = false);
3881 }
3882 }
3883
3884 exit:
3885 return isComparable;
3886 }
3887
SetChildStateToValid(Child & aChild)3888 void MleRouter::SetChildStateToValid(Child &aChild)
3889 {
3890 VerifyOrExit(!aChild.IsStateValid());
3891
3892 aChild.SetState(Neighbor::kStateValid);
3893 IgnoreError(mChildTable.StoreChild(aChild));
3894
3895 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
3896 Get<MlrManager>().UpdateProxiedSubscriptions(aChild, MlrManager::MlrAddressArray());
3897 #endif
3898
3899 mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
3900
3901 exit:
3902 return;
3903 }
3904
HasChildren(void)3905 bool MleRouter::HasChildren(void) { return mChildTable.HasChildren(Child::kInStateValidOrAttaching); }
3906
RemoveChildren(void)3907 void MleRouter::RemoveChildren(void)
3908 {
3909 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
3910 {
3911 RemoveNeighbor(child);
3912 }
3913 }
3914
SetAssignParentPriority(int8_t aParentPriority)3915 Error MleRouter::SetAssignParentPriority(int8_t aParentPriority)
3916 {
3917 Error error = kErrorNone;
3918
3919 VerifyOrExit(aParentPriority <= kParentPriorityHigh && aParentPriority >= kParentPriorityUnspecified,
3920 error = kErrorInvalidArgs);
3921
3922 mParentPriority = aParentPriority;
3923
3924 exit:
3925 return error;
3926 }
3927
GetMaxChildTimeout(uint32_t & aTimeout) const3928 Error MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
3929 {
3930 Error error = kErrorNotFound;
3931
3932 aTimeout = 0;
3933
3934 VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
3935
3936 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
3937 {
3938 if (child.IsFullThreadDevice())
3939 {
3940 continue;
3941 }
3942
3943 if (child.GetTimeout() > aTimeout)
3944 {
3945 aTimeout = child.GetTimeout();
3946 }
3947
3948 error = kErrorNone;
3949 }
3950
3951 exit:
3952 return error;
3953 }
3954
3955 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
SendTimeSync(void)3956 Error MleRouter::SendTimeSync(void)
3957 {
3958 Error error = kErrorNone;
3959 Ip6::Address destination;
3960 TxMessage *message = nullptr;
3961
3962 VerifyOrExit((message = NewMleMessage(kCommandTimeSync)) != nullptr, error = kErrorNoBufs);
3963
3964 message->SetTimeSync(true);
3965
3966 destination.SetToLinkLocalAllNodesMulticast();
3967 SuccessOrExit(error = message->SendTo(destination));
3968
3969 Log(kMessageSend, kTypeTimeSync, destination);
3970
3971 exit:
3972 FreeMessageOnError(message, error);
3973 return error;
3974 }
3975 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3976
3977 //----------------------------------------------------------------------------------------------------------------------
3978 // RouterRoleTransition
3979
RouterRoleTransition(void)3980 MleRouter::RouterRoleTransition::RouterRoleTransition(void)
3981 : mTimeout(0)
3982 , mJitter(kRouterSelectionJitter)
3983 {
3984 }
3985
StartTimeout(void)3986 void MleRouter::RouterRoleTransition::StartTimeout(void)
3987 {
3988 mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter);
3989 }
3990
HandleTimeTick(void)3991 bool MleRouter::RouterRoleTransition::HandleTimeTick(void)
3992 {
3993 bool expired = false;
3994
3995 VerifyOrExit(mTimeout > 0);
3996 mTimeout--;
3997 expired = (mTimeout == 0);
3998
3999 exit:
4000 return expired;
4001 }
4002
4003 //----------------------------------------------------------------------------------------------------------------------
4004 // RouterRoleRestorer
4005
RouterRoleRestorer(Instance & aInstance)4006 MleRouter::RouterRoleRestorer::RouterRoleRestorer(Instance &aInstance)
4007 : InstanceLocator(aInstance)
4008 , mAttempts(0)
4009 {
4010 }
4011
Start(DeviceRole aPreviousRole)4012 void MleRouter::RouterRoleRestorer::Start(DeviceRole aPreviousRole)
4013 {
4014 // If the device was previously the leader or had more than
4015 // `kMinCriticalChildrenCount` children, we use more link
4016 // request attempts.
4017
4018 mAttempts = 0;
4019
4020 switch (aPreviousRole)
4021 {
4022 case kRoleRouter:
4023 if (Get<MleRouter>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount)
4024 {
4025 mAttempts = kMaxTxCount;
4026 break;
4027 }
4028
4029 OT_FALL_THROUGH;
4030
4031 case kRoleLeader:
4032 mAttempts = kMaxCriticalTxCount;
4033 break;
4034
4035 case kRoleChild:
4036 case kRoleDetached:
4037 case kRoleDisabled:
4038 break;
4039 }
4040
4041 SendMulticastLinkRequest();
4042 }
4043
HandleTimer(void)4044 void MleRouter::RouterRoleRestorer::HandleTimer(void)
4045 {
4046 if (mAttempts > 0)
4047 {
4048 mAttempts--;
4049 }
4050
4051 SendMulticastLinkRequest();
4052 }
4053
SendMulticastLinkRequest(void)4054 void MleRouter::RouterRoleRestorer::SendMulticastLinkRequest(void)
4055 {
4056 uint32_t delay;
4057
4058 VerifyOrExit(Get<Mle>().IsDetached(), mAttempts = 0);
4059
4060 if (mAttempts == 0)
4061 {
4062 IgnoreError(Get<Mle>().BecomeDetached());
4063 ExitNow();
4064 }
4065
4066 Get<MleRouter>().SendLinkRequest(nullptr);
4067
4068 delay = (mAttempts == 1) ? kLinkRequestTimeout
4069 : Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
4070
4071 Get<Mle>().mAttachTimer.Start(delay);
4072
4073 exit:
4074 return;
4075 }
4076
4077 } // namespace Mle
4078 } // namespace ot
4079
4080 #endif // OPENTHREAD_FTD
4081