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 (router.IsStateValid() && (age >= kMaxNeighborAge))
1724 {
1725 bool sendLinkRequest = true;
1726
1727 // Once router age expires, we send Link Request every
1728 // time tick (second), up to `kMaxTxCount`. Each rx is
1729 // randomly delayed (one second window). After the last
1730 // attempt, we wait for the "Link Accept" timeout
1731 // (~3 seconds), before the router is removed.
1732
1733 if (!router.IsWaitingForLinkAccept())
1734 {
1735 LogInfo("No Adv from router 0x%04x - sending Link Request", router.GetRloc16());
1736 }
1737 else
1738 {
1739 sendLinkRequest = (age < kMaxNeighborAge + kMaxTxCount * TimeMilli::kOneSecondInMsec);
1740 }
1741
1742 if (sendLinkRequest)
1743 {
1744 mDelayedSender.ScheduleLinkRequest(
1745 router, Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter));
1746 }
1747 }
1748
1749 #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
1750 router.DecrementParentReselectTimeout();
1751
1752 if (age >= kMaxNeighborAge)
1753 {
1754 router.SetSelectableAsParent(false);
1755 }
1756 #endif
1757
1758 if (router.IsWaitingForLinkAccept() && (router.DecrementLinkAcceptTimeout() == 0))
1759 {
1760 LogInfo("Router 0x%04x - Link Accept timeout expired", router.GetRloc16());
1761 RemoveNeighbor(router);
1762 continue;
1763 }
1764
1765 if (IsLeader() && (mRouterTable.FindNextHopOf(router) == nullptr) &&
1766 (mRouterTable.GetLinkCost(router) >= kMaxRouteCost) && (age >= kMaxLeaderToRouterTimeout))
1767 {
1768 LogInfo("Router 0x%04x ID timeout expired (no route)", router.GetRloc16());
1769 IgnoreError(mRouterTable.Release(router.GetRouterId()));
1770 }
1771 }
1772
1773 mRouterTable.HandleTimeTick();
1774
1775 SynchronizeChildNetworkData();
1776
1777 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1778 if (IsRouterOrLeader())
1779 {
1780 Get<TimeSync>().ProcessTimeSync();
1781 }
1782 #endif
1783
1784 exit:
1785 return;
1786 }
1787
SendParentResponse(const ParentResponseInfo & aInfo)1788 void MleRouter::SendParentResponse(const ParentResponseInfo &aInfo)
1789 {
1790 Error error = kErrorNone;
1791 TxMessage *message = nullptr;
1792 Child *child;
1793 Ip6::Address destination;
1794
1795 child = mChildTable.FindChild(aInfo.mChildExtAddress, Child::kInStateAnyExceptInvalid);
1796 VerifyOrExit(child != nullptr);
1797
1798 VerifyOrExit((message = NewMleMessage(kCommandParentResponse)) != nullptr, error = kErrorNoBufs);
1799 message->SetDirectTransmission();
1800
1801 SuccessOrExit(error = message->AppendSourceAddressTlv());
1802 SuccessOrExit(error = message->AppendLeaderDataTlv());
1803 SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs());
1804 SuccessOrExit(error = message->AppendResponseTlv(aInfo.mRxChallenge));
1805 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1806 if (child->IsTimeSyncEnabled())
1807 {
1808 SuccessOrExit(error = message->AppendTimeParameterTlv());
1809 }
1810 #endif
1811 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1812 if (child->IsThreadVersionCslCapable())
1813 {
1814 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
1815 }
1816 #endif
1817 child->GenerateChallenge();
1818 SuccessOrExit(error = message->AppendChallengeTlv(child->GetChallenge()));
1819 SuccessOrExit(error = message->AppendLinkMarginTlv(child->GetLinkInfo().GetLinkMargin()));
1820 SuccessOrExit(error = message->AppendConnectivityTlv());
1821 SuccessOrExit(error = message->AppendVersionTlv());
1822
1823 destination.SetToLinkLocalAddress(aInfo.mChildExtAddress);
1824
1825 SuccessOrExit(error = message->SendTo(destination));
1826
1827 Log(kMessageSend, kTypeParentResponse, destination);
1828
1829 exit:
1830 FreeMessageOnError(message, error);
1831 LogSendError(kTypeParentResponse, error);
1832 }
1833
GetMaxChildIpAddresses(void) const1834 uint8_t MleRouter::GetMaxChildIpAddresses(void) const
1835 {
1836 uint8_t num = kMaxChildIpAddresses;
1837
1838 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1839 if (mMaxChildIpAddresses != 0)
1840 {
1841 num = mMaxChildIpAddresses;
1842 }
1843 #endif
1844
1845 return num;
1846 }
1847
1848 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)1849 Error MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses)
1850 {
1851 Error error = kErrorNone;
1852
1853 VerifyOrExit(aMaxIpAddresses <= kMaxChildIpAddresses, error = kErrorInvalidArgs);
1854
1855 mMaxChildIpAddresses = aMaxIpAddresses;
1856
1857 exit:
1858 return error;
1859 }
1860 #endif
1861
ProcessAddressRegistrationTlv(RxInfo & aRxInfo,Child & aChild)1862 Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
1863 {
1864 Error error;
1865 OffsetRange offsetRange;
1866 uint8_t count = 0;
1867 uint8_t storedCount = 0;
1868 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1869 Ip6::Address oldDua;
1870 #endif
1871 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1872 MlrManager::MlrAddressArray oldMlrRegisteredAddresses;
1873 #endif
1874
1875 OT_UNUSED_VARIABLE(storedCount);
1876
1877 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kAddressRegistration, offsetRange));
1878
1879 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
1880 if (aChild.GetDomainUnicastAddress(oldDua) != kErrorNone)
1881 {
1882 oldDua.Clear();
1883 }
1884 #endif
1885
1886 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
1887 if (aChild.HasAnyMlrRegisteredAddress())
1888 {
1889 OT_ASSERT(aChild.IsStateValid());
1890
1891 for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses())
1892 {
1893 if (!addrEntry.IsMulticastLargerThanRealmLocal())
1894 {
1895 continue;
1896 }
1897
1898 if (addrEntry.GetMlrState(aChild) == kMlrStateRegistered)
1899 {
1900 IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry));
1901 }
1902 }
1903 }
1904 #endif
1905
1906 aChild.ClearIp6Addresses();
1907
1908 while (!offsetRange.IsEmpty())
1909 {
1910 uint8_t controlByte;
1911 Ip6::Address address;
1912
1913 // Read out the control byte (first byte in entry)
1914 SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, controlByte));
1915 offsetRange.AdvanceOffset(sizeof(uint8_t));
1916 count++;
1917
1918 address.Clear();
1919
1920 if (AddressRegistrationTlv::IsEntryCompressed(controlByte))
1921 {
1922 // Compressed entry contains IID with the 64-bit prefix
1923 // determined from 6LoWPAN context identifier (from
1924 // the control byte).
1925
1926 uint8_t contextId = AddressRegistrationTlv::GetContextId(controlByte);
1927 Lowpan::Context context;
1928
1929 IgnoreError(aRxInfo.mMessage.Read(offsetRange, address.GetIid()));
1930 offsetRange.AdvanceOffset(sizeof(Ip6::InterfaceIdentifier));
1931
1932 if (Get<NetworkData::Leader>().GetContext(contextId, context) != kErrorNone)
1933 {
1934 LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId,
1935 aChild.GetRloc16());
1936 continue;
1937 }
1938
1939 address.SetPrefix(context.mPrefix);
1940 }
1941 else
1942 {
1943 // Uncompressed entry contains the full IPv6 address.
1944
1945 IgnoreError(aRxInfo.mMessage.Read(offsetRange, address));
1946 offsetRange.AdvanceOffset(sizeof(Ip6::Address));
1947 }
1948
1949 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
1950 if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses)
1951 {
1952 // Skip remaining address registration entries but keep logging
1953 // skipped addresses.
1954 error = kErrorNoBufs;
1955 }
1956 else
1957 #endif
1958 {
1959 // We try to accept/add as many IPv6 addresses as possible.
1960 // "Child ID/Update Response" will indicate the accepted
1961 // addresses.
1962 error = aChild.AddIp6Address(address);
1963 }
1964
1965 if (error == kErrorNone)
1966 {
1967 storedCount++;
1968 LogInfo("Child 0x%04x IPv6 address[%u]=%s", aChild.GetRloc16(), storedCount,
1969 address.ToString().AsCString());
1970 }
1971 else
1972 {
1973 LogWarn("Error %s adding IPv6 address %s to child 0x%04x", ErrorToString(error),
1974 address.ToString().AsCString(), aChild.GetRloc16());
1975 }
1976
1977 if (address.IsMulticast())
1978 {
1979 continue;
1980 }
1981
1982 // We check if the same address is in-use by another child, if so
1983 // remove it. This implements "last-in wins" duplicate address
1984 // resolution policy.
1985 //
1986 // Duplicate addresses can occur if a previously attached child
1987 // attaches to same parent again (after a reset, memory wipe) using
1988 // a new random extended address before the old entry in the child
1989 // table is timed out and then trying to register its globally unique
1990 // IPv6 address as the new child.
1991
1992 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
1993 {
1994 if (&child == &aChild)
1995 {
1996 continue;
1997 }
1998
1999 IgnoreError(child.RemoveIp6Address(address));
2000 }
2001
2002 // Clear EID-to-RLOC cache for the unicast address registered by the child.
2003 Get<AddressResolver>().RemoveEntryForAddress(address);
2004 }
2005 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2006 SignalDuaAddressEvent(aChild, oldDua);
2007 #endif
2008
2009 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
2010 Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses);
2011 #endif
2012
2013 if (count == 0)
2014 {
2015 LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
2016 }
2017 else
2018 {
2019 LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count,
2020 (count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
2021 }
2022
2023 error = kErrorNone;
2024
2025 exit:
2026 return error;
2027 }
2028
2029 #if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
SignalDuaAddressEvent(const Child & aChild,const Ip6::Address & aOldDua) const2030 void MleRouter::SignalDuaAddressEvent(const Child &aChild, const Ip6::Address &aOldDua) const
2031 {
2032 DuaManager::ChildDuaAddressEvent event = DuaManager::kAddressUnchanged;
2033 Ip6::Address newDua;
2034
2035 if (aChild.GetDomainUnicastAddress(newDua) == kErrorNone)
2036 {
2037 if (aOldDua.IsUnspecified())
2038 {
2039 event = DuaManager::kAddressAdded;
2040 }
2041 else if (aOldDua != newDua)
2042 {
2043 event = DuaManager::kAddressChanged;
2044 }
2045 }
2046 else
2047 {
2048 // Child has no DUA address. If there was no old DUA, no need
2049 // to signal.
2050
2051 VerifyOrExit(!aOldDua.IsUnspecified());
2052
2053 event = DuaManager::kAddressRemoved;
2054 }
2055
2056 Get<DuaManager>().HandleChildDuaAddressEvent(aChild, event);
2057
2058 exit:
2059 return;
2060 }
2061 #endif // OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
2062
IsMessageMleSubType(const Message & aMessage)2063 bool MleRouter::IsMessageMleSubType(const Message &aMessage) { return aMessage.IsSubTypeMle(); }
2064
IsMessageChildUpdateRequest(const Message & aMessage)2065 bool MleRouter::IsMessageChildUpdateRequest(const Message &aMessage)
2066 {
2067 return aMessage.IsMleCommand(kCommandChildUpdateRequest);
2068 }
2069
HandleChildIdRequest(RxInfo & aRxInfo)2070 void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
2071 {
2072 Error error = kErrorNone;
2073 Mac::ExtAddress extAddr;
2074 uint16_t version;
2075 uint32_t linkFrameCounter;
2076 uint32_t mleFrameCounter;
2077 DeviceMode mode;
2078 uint32_t timeout;
2079 TlvList tlvList;
2080 MeshCoP::Timestamp timestamp;
2081 Child *child;
2082 Router *router;
2083 uint16_t supervisionInterval;
2084
2085 Log(kMessageReceive, kTypeChildIdRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2086
2087 VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2088
2089 VerifyOrExit(IsAttached(), error = kErrorInvalidState);
2090
2091 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2092
2093 child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2094 VerifyOrExit(child != nullptr, error = kErrorAlready);
2095
2096 SuccessOrExit(error = aRxInfo.mMessage.ReadVersionTlv(version));
2097
2098 SuccessOrExit(error = aRxInfo.mMessage.ReadAndMatchResponseTlvWith(child->GetChallenge()));
2099
2100 Get<MeshForwarder>().RemoveMessagesForChild(*child, IsMessageMleSubType);
2101
2102 SuccessOrExit(error = aRxInfo.mMessage.ReadFrameCounterTlvs(linkFrameCounter, mleFrameCounter));
2103
2104 SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2105
2106 SuccessOrExit(error = Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout));
2107
2108 SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2109
2110 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2111 {
2112 case kErrorNone:
2113 tlvList.Add(Tlv::kSupervisionInterval);
2114 break;
2115 case kErrorNotFound:
2116 supervisionInterval = (version <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2117 break;
2118 default:
2119 ExitNow(error = kErrorParse);
2120 }
2121
2122 switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2123 {
2124 case kErrorNone:
2125 if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2126 {
2127 break;
2128 }
2129
2130 OT_FALL_THROUGH;
2131
2132 case kErrorNotFound:
2133 tlvList.Add(Tlv::kActiveDataset);
2134 break;
2135
2136 default:
2137 ExitNow(error = kErrorParse);
2138 }
2139
2140 switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2141 {
2142 case kErrorNone:
2143 if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2144 {
2145 break;
2146 }
2147
2148 OT_FALL_THROUGH;
2149
2150 case kErrorNotFound:
2151 tlvList.Add(Tlv::kPendingDataset);
2152 break;
2153
2154 default:
2155 ExitNow(error = kErrorParse);
2156 }
2157
2158 VerifyOrExit(tlvList.GetLength() <= Child::kMaxRequestTlvs, error = kErrorParse);
2159
2160 if (!mode.IsFullThreadDevice())
2161 {
2162 SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
2163 }
2164
2165 router = mRouterTable.FindRouter(extAddr);
2166
2167 if (router != nullptr)
2168 {
2169 RemoveNeighbor(*router);
2170 }
2171
2172 if (!child->IsStateValid())
2173 {
2174 child->SetState(Neighbor::kStateChildIdRequest);
2175 }
2176 else
2177 {
2178 RemoveNeighbor(*child);
2179 }
2180
2181 child->SetLastHeard(TimerMilli::GetNow());
2182 child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2183 child->SetLinkAckFrameCounter(linkFrameCounter);
2184 child->SetMleFrameCounter(mleFrameCounter);
2185 child->SetKeySequence(aRxInfo.mKeySequence);
2186 child->SetDeviceMode(mode);
2187 child->SetVersion(version);
2188 child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2189 child->SetTimeout(timeout);
2190 child->SetSupervisionInterval(supervisionInterval);
2191 #if OPENTHREAD_CONFIG_MULTI_RADIO
2192 child->ClearLastRxFragmentTag();
2193 #endif
2194
2195 child->SetNetworkDataVersion(mLeaderData.GetDataVersion(mode.GetNetworkDataType()));
2196
2197 // We already checked above that `tlvList` will fit in
2198 // `child` entry (with `Child::kMaxRequestTlvs` TLVs).
2199
2200 child->ClearRequestTlvs();
2201
2202 for (uint8_t index = 0; index < tlvList.GetLength(); index++)
2203 {
2204 child->SetRequestTlv(index, tlvList[index]);
2205 }
2206
2207 aRxInfo.mClass = RxInfo::kAuthoritativeMessage;
2208 ProcessKeySequence(aRxInfo);
2209
2210 switch (mRole)
2211 {
2212 case kRoleChild:
2213 child->SetState(Neighbor::kStateChildIdRequest);
2214 IgnoreError(BecomeRouter(ThreadStatusTlv::kHaveChildIdRequest));
2215 break;
2216
2217 case kRoleRouter:
2218 case kRoleLeader:
2219 SuccessOrExit(error = SendChildIdResponse(*child));
2220 break;
2221
2222 case kRoleDisabled:
2223 case kRoleDetached:
2224 OT_ASSERT(false);
2225 }
2226
2227 exit:
2228 LogProcessError(kTypeChildIdRequest, error);
2229 }
2230
HandleChildUpdateRequestOnParent(RxInfo & aRxInfo)2231 void MleRouter::HandleChildUpdateRequestOnParent(RxInfo &aRxInfo)
2232 {
2233 Error error = kErrorNone;
2234 Mac::ExtAddress extAddr;
2235 DeviceMode mode;
2236 RxChallenge challenge;
2237 LeaderData leaderData;
2238 uint32_t timeout;
2239 uint16_t supervisionInterval;
2240 Child *child;
2241 DeviceMode oldMode;
2242 TlvList requestedTlvList;
2243 TlvList tlvList;
2244 bool childDidChange = false;
2245
2246 Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
2247
2248 SuccessOrExit(error = aRxInfo.mMessage.ReadModeTlv(mode));
2249
2250 switch (aRxInfo.mMessage.ReadChallengeTlv(challenge))
2251 {
2252 case kErrorNone:
2253 tlvList.Add(Tlv::kResponse);
2254 break;
2255 case kErrorNotFound:
2256 challenge.Clear();
2257 break;
2258 default:
2259 ExitNow(error = kErrorParse);
2260 }
2261
2262 tlvList.Add(Tlv::kSourceAddress);
2263
2264 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
2265 child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
2266
2267 if (child == nullptr)
2268 {
2269 // For invalid non-sleepy child, send Child Update Response with
2270 // Status TLV (error).
2271 if (mode.IsRxOnWhenIdle())
2272 {
2273 tlvList.Add(Tlv::kStatus);
2274 SendChildUpdateResponseToChild(nullptr, aRxInfo.mMessageInfo, tlvList, challenge);
2275 }
2276
2277 ExitNow();
2278 }
2279
2280 // Ignore "Child Update Request" from a child that is present in the
2281 // child table but it is not yet in valid state. For example, a
2282 // child which is being restored (due to parent reset) or is in the
2283 // middle of the attach process (in `kStateParentRequest` or
2284 // `kStateChildIdRequest`).
2285
2286 VerifyOrExit(child->IsStateValid());
2287
2288 oldMode = child->GetDeviceMode();
2289 child->SetDeviceMode(mode);
2290
2291 tlvList.Add(Tlv::kMode);
2292 tlvList.Add(Tlv::kLinkMargin);
2293
2294 // Parent MUST include Leader Data TLV in Child Update Response
2295 tlvList.Add(Tlv::kLeaderData);
2296
2297 if (!challenge.IsEmpty())
2298 {
2299 tlvList.Add(Tlv::kMleFrameCounter);
2300 tlvList.Add(Tlv::kLinkFrameCounter);
2301 }
2302
2303 switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2304 {
2305 case kErrorNone:
2306 tlvList.Add(Tlv::kAddressRegistration);
2307 break;
2308 case kErrorNotFound:
2309 break;
2310 default:
2311 ExitNow(error = kErrorParse);
2312 }
2313
2314 switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2315 {
2316 case kErrorNone:
2317 child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2318 break;
2319 case kErrorNotFound:
2320 break;
2321 default:
2322 ExitNow(error = kErrorParse);
2323 }
2324
2325 switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2326 {
2327 case kErrorNone:
2328 if (child->GetTimeout() != timeout)
2329 {
2330 child->SetTimeout(timeout);
2331 childDidChange = true;
2332 }
2333
2334 tlvList.Add(Tlv::kTimeout);
2335 break;
2336
2337 case kErrorNotFound:
2338 break;
2339
2340 default:
2341 ExitNow(error = kErrorParse);
2342 }
2343
2344 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2345 {
2346 case kErrorNone:
2347 tlvList.Add(Tlv::kSupervisionInterval);
2348 break;
2349
2350 case kErrorNotFound:
2351 supervisionInterval =
2352 (child->GetVersion() <= kThreadVersion1p3) ? kChildSupervisionDefaultIntervalForOlderVersion : 0;
2353 break;
2354
2355 default:
2356 ExitNow(error = kErrorParse);
2357 }
2358
2359 child->SetSupervisionInterval(supervisionInterval);
2360
2361 switch (aRxInfo.mMessage.ReadTlvRequestTlv(requestedTlvList))
2362 {
2363 case kErrorNone:
2364 tlvList.AddElementsFrom(requestedTlvList);
2365 break;
2366 case kErrorNotFound:
2367 break;
2368 default:
2369 ExitNow(error = kErrorParse);
2370 }
2371
2372 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2373 if (child->IsCslSynchronized())
2374 {
2375 ChannelTlvValue cslChannelTlvValue;
2376 uint32_t cslTimeout;
2377
2378 switch (Tlv::Find<CslTimeoutTlv>(aRxInfo.mMessage, cslTimeout))
2379 {
2380 case kErrorNone:
2381 child->SetCslTimeout(cslTimeout);
2382 // MUST include CSL accuracy TLV when request includes CSL timeout
2383 tlvList.Add(Tlv::kCslClockAccuracy);
2384 break;
2385 case kErrorNotFound:
2386 break;
2387 default:
2388 ExitNow(error = kErrorNone);
2389 }
2390
2391 if (Tlv::Find<CslChannelTlv>(aRxInfo.mMessage, cslChannelTlvValue) == kErrorNone)
2392 {
2393 // Special value of zero is used to indicate that
2394 // CSL channel is not specified.
2395 child->SetCslChannel(static_cast<uint8_t>(cslChannelTlvValue.GetChannel()));
2396 }
2397 }
2398 #endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2399
2400 child->SetLastHeard(TimerMilli::GetNow());
2401
2402 if (oldMode != child->GetDeviceMode())
2403 {
2404 LogNote("Child 0x%04x mode change 0x%02x -> 0x%02x [%s]", child->GetRloc16(), oldMode.Get(),
2405 child->GetDeviceMode().Get(), child->GetDeviceMode().ToString().AsCString());
2406
2407 childDidChange = true;
2408
2409 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
2410 if (child->IsRxOnWhenIdle())
2411 {
2412 // Clear CSL synchronization state
2413 child->SetCslSynchronized(false);
2414 }
2415 #endif
2416
2417 // The `IndirectSender::HandleChildModeChange()` needs to happen
2418 // after "Child Update" message is fully parsed to ensure that
2419 // any registered IPv6 addresses included in the "Child Update"
2420 // are added to the child.
2421
2422 Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
2423 }
2424
2425 if (childDidChange)
2426 {
2427 IgnoreError(mChildTable.StoreChild(*child));
2428 }
2429
2430 #if OPENTHREAD_CONFIG_MULTI_RADIO
2431 // We clear the fragment tag only if the "Child Update Request" is
2432 // from a detached child trying to restore its link with its
2433 // parent which is indicated by the presence of Challenge TLV in
2434 // the message.
2435 if (!challenge.IsEmpty())
2436 {
2437 child->ClearLastRxFragmentTag();
2438 }
2439 #endif
2440
2441 SendChildUpdateResponseToChild(child, aRxInfo.mMessageInfo, tlvList, challenge);
2442
2443 aRxInfo.mClass = RxInfo::kPeerMessage;
2444
2445 exit:
2446 LogProcessError(kTypeChildUpdateRequestOfChild, error);
2447 }
2448
HandleChildUpdateResponseOnParent(RxInfo & aRxInfo)2449 void MleRouter::HandleChildUpdateResponseOnParent(RxInfo &aRxInfo)
2450 {
2451 Error error = kErrorNone;
2452 uint16_t sourceAddress;
2453 uint32_t timeout;
2454 RxChallenge response;
2455 uint8_t status;
2456 uint32_t linkFrameCounter;
2457 uint32_t mleFrameCounter;
2458 LeaderData leaderData;
2459 Child *child;
2460
2461 if ((aRxInfo.mNeighbor == nullptr) || IsRouterRloc16(aRxInfo.mNeighbor->GetRloc16()) ||
2462 !Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
2463 {
2464 Log(kMessageReceive, kTypeChildUpdateResponseOfUnknownChild, aRxInfo.mMessageInfo.GetPeerAddr());
2465 ExitNow(error = kErrorNotFound);
2466 }
2467
2468 child = static_cast<Child *>(aRxInfo.mNeighbor);
2469
2470 switch (aRxInfo.mMessage.ReadResponseTlv(response))
2471 {
2472 case kErrorNone:
2473 VerifyOrExit(response == child->GetChallenge(), error = kErrorSecurity);
2474 break;
2475 case kErrorNotFound:
2476 VerifyOrExit(child->IsStateValid(), error = kErrorSecurity);
2477 response.Clear();
2478 break;
2479 default:
2480 ExitNow(error = kErrorNone);
2481 }
2482
2483 Log(kMessageReceive, kTypeChildUpdateResponseOfChild, aRxInfo.mMessageInfo.GetPeerAddr(), child->GetRloc16());
2484
2485 switch (Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress))
2486 {
2487 case kErrorNone:
2488 if (child->GetRloc16() != sourceAddress)
2489 {
2490 RemoveNeighbor(*child);
2491 ExitNow();
2492 }
2493
2494 break;
2495
2496 case kErrorNotFound:
2497 break;
2498
2499 default:
2500 ExitNow(error = kErrorParse);
2501 }
2502
2503 switch (Tlv::Find<StatusTlv>(aRxInfo.mMessage, status))
2504 {
2505 case kErrorNone:
2506 VerifyOrExit(status != StatusTlv::kError, RemoveNeighbor(*child));
2507 break;
2508 case kErrorNotFound:
2509 break;
2510 default:
2511 ExitNow(error = kErrorParse);
2512 }
2513
2514 switch (Tlv::Find<LinkFrameCounterTlv>(aRxInfo.mMessage, linkFrameCounter))
2515 {
2516 case kErrorNone:
2517 child->GetLinkFrameCounters().SetAll(linkFrameCounter);
2518 child->SetLinkAckFrameCounter(linkFrameCounter);
2519 break;
2520 case kErrorNotFound:
2521 break;
2522 default:
2523 ExitNow(error = kErrorParse);
2524 }
2525
2526 switch (Tlv::Find<MleFrameCounterTlv>(aRxInfo.mMessage, mleFrameCounter))
2527 {
2528 case kErrorNone:
2529 child->SetMleFrameCounter(mleFrameCounter);
2530 break;
2531 case kErrorNotFound:
2532 break;
2533 default:
2534 ExitNow(error = kErrorNone);
2535 }
2536
2537 switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
2538 {
2539 case kErrorNone:
2540 child->SetTimeout(timeout);
2541 break;
2542 case kErrorNotFound:
2543 break;
2544 default:
2545 ExitNow(error = kErrorParse);
2546 }
2547
2548 {
2549 uint16_t supervisionInterval;
2550
2551 switch (Tlv::Find<SupervisionIntervalTlv>(aRxInfo.mMessage, supervisionInterval))
2552 {
2553 case kErrorNone:
2554 child->SetSupervisionInterval(supervisionInterval);
2555 break;
2556 case kErrorNotFound:
2557 break;
2558 default:
2559 ExitNow(error = kErrorParse);
2560 }
2561 }
2562
2563 switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
2564 {
2565 case kErrorNone:
2566 case kErrorNotFound:
2567 break;
2568 default:
2569 ExitNow(error = kErrorParse);
2570 }
2571
2572 switch (aRxInfo.mMessage.ReadLeaderDataTlv(leaderData))
2573 {
2574 case kErrorNone:
2575 child->SetNetworkDataVersion(leaderData.GetDataVersion(child->GetNetworkDataType()));
2576 break;
2577 case kErrorNotFound:
2578 break;
2579 default:
2580 ExitNow(error = kErrorParse);
2581 }
2582
2583 SetChildStateToValid(*child);
2584 child->SetLastHeard(TimerMilli::GetNow());
2585 child->SetKeySequence(aRxInfo.mKeySequence);
2586 child->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
2587
2588 aRxInfo.mClass = response.IsEmpty() ? RxInfo::kPeerMessage : RxInfo::kAuthoritativeMessage;
2589
2590 exit:
2591 LogProcessError(kTypeChildUpdateResponseOfChild, error);
2592 }
2593
HandleDataRequest(RxInfo & aRxInfo)2594 void MleRouter::HandleDataRequest(RxInfo &aRxInfo)
2595 {
2596 Error error = kErrorNone;
2597 TlvList tlvList;
2598 MeshCoP::Timestamp timestamp;
2599
2600 Log(kMessageReceive, kTypeDataRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2601
2602 VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity);
2603
2604 SuccessOrExit(error = aRxInfo.mMessage.ReadTlvRequestTlv(tlvList));
2605
2606 switch (Tlv::Find<ActiveTimestampTlv>(aRxInfo.mMessage, timestamp))
2607 {
2608 case kErrorNone:
2609 if (timestamp == Get<MeshCoP::ActiveDatasetManager>().GetTimestamp())
2610 {
2611 break;
2612 }
2613
2614 OT_FALL_THROUGH;
2615
2616 case kErrorNotFound:
2617 tlvList.Add(Tlv::kActiveDataset);
2618 break;
2619
2620 default:
2621 ExitNow(error = kErrorParse);
2622 }
2623
2624 switch (Tlv::Find<PendingTimestampTlv>(aRxInfo.mMessage, timestamp))
2625 {
2626 case kErrorNone:
2627 if (timestamp == Get<MeshCoP::PendingDatasetManager>().GetTimestamp())
2628 {
2629 break;
2630 }
2631
2632 OT_FALL_THROUGH;
2633
2634 case kErrorNotFound:
2635 tlvList.Add(Tlv::kPendingDataset);
2636 break;
2637
2638 default:
2639 ExitNow(error = kErrorParse);
2640 }
2641
2642 aRxInfo.mClass = RxInfo::kPeerMessage;
2643 ProcessKeySequence(aRxInfo);
2644
2645 SendDataResponse(aRxInfo.mMessageInfo.GetPeerAddr(), tlvList, &aRxInfo.mMessage);
2646
2647 exit:
2648 LogProcessError(kTypeDataRequest, error);
2649 }
2650
HandleNetworkDataUpdateRouter(void)2651 void MleRouter::HandleNetworkDataUpdateRouter(void)
2652 {
2653 uint16_t delay;
2654
2655 VerifyOrExit(IsRouterOrLeader());
2656
2657 if (IsLeader())
2658 {
2659 SendMulticastDataResponse();
2660 }
2661 else
2662 {
2663 delay = 1 + Random::NonCrypto::GetUint16InRange(0, kUnsolicitedDataResponseJitter);
2664 mDelayedSender.ScheduleMulticastDataResponse(delay);
2665 }
2666
2667 SynchronizeChildNetworkData();
2668
2669 exit:
2670 return;
2671 }
2672
SynchronizeChildNetworkData(void)2673 void MleRouter::SynchronizeChildNetworkData(void)
2674 {
2675 VerifyOrExit(IsRouterOrLeader());
2676
2677 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
2678 {
2679 if (child.IsRxOnWhenIdle())
2680 {
2681 continue;
2682 }
2683
2684 if (child.GetNetworkDataVersion() == Get<NetworkData::Leader>().GetVersion(child.GetNetworkDataType()))
2685 {
2686 continue;
2687 }
2688
2689 SuccessOrExit(SendChildUpdateRequestToChild(child));
2690 }
2691
2692 exit:
2693 return;
2694 }
2695
2696 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
SetSteeringData(const Mac::ExtAddress * aExtAddress)2697 void MleRouter::SetSteeringData(const Mac::ExtAddress *aExtAddress)
2698 {
2699 Mac::ExtAddress nullExtAddr;
2700 Mac::ExtAddress allowAnyExtAddr;
2701
2702 nullExtAddr.Clear();
2703 allowAnyExtAddr.Fill(0xff);
2704
2705 if ((aExtAddress == nullptr) || (*aExtAddress == nullExtAddr))
2706 {
2707 mSteeringData.Clear();
2708 }
2709 else if (*aExtAddress == allowAnyExtAddr)
2710 {
2711 mSteeringData.SetToPermitAllJoiners();
2712 }
2713 else
2714 {
2715 Mac::ExtAddress joinerId;
2716
2717 mSteeringData.Init();
2718 MeshCoP::ComputeJoinerId(*aExtAddress, joinerId);
2719 mSteeringData.UpdateBloomFilter(joinerId);
2720 }
2721 }
2722 #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2723
HandleDiscoveryRequest(RxInfo & aRxInfo)2724 void MleRouter::HandleDiscoveryRequest(RxInfo &aRxInfo)
2725 {
2726 Error error = kErrorNone;
2727 Tlv::ParsedInfo tlvInfo;
2728 MeshCoP::DiscoveryRequestTlv discoveryRequestTlv;
2729 MeshCoP::ExtendedPanId extPanId;
2730 OffsetRange offsetRange;
2731 DiscoveryResponseInfo responseInfo;
2732
2733 Log(kMessageReceive, kTypeDiscoveryRequest, aRxInfo.mMessageInfo.GetPeerAddr());
2734
2735 discoveryRequestTlv.SetLength(0);
2736
2737 VerifyOrExit(IsRouterEligible(), error = kErrorInvalidState);
2738
2739 SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange));
2740
2741 for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(tlvInfo.GetSize()))
2742 {
2743 SuccessOrExit(error = tlvInfo.ParseFrom(aRxInfo.mMessage, offsetRange));
2744
2745 if (tlvInfo.mIsExtended)
2746 {
2747 continue;
2748 }
2749
2750 switch (tlvInfo.mType)
2751 {
2752 case MeshCoP::Tlv::kDiscoveryRequest:
2753 SuccessOrExit(error = aRxInfo.mMessage.Read(offsetRange, discoveryRequestTlv));
2754 VerifyOrExit(discoveryRequestTlv.IsValid(), error = kErrorParse);
2755
2756 break;
2757
2758 case MeshCoP::Tlv::kExtendedPanId:
2759 SuccessOrExit(
2760 error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offsetRange.GetOffset(), extPanId));
2761 VerifyOrExit(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId() != extPanId, error = kErrorDrop);
2762
2763 break;
2764
2765 default:
2766 break;
2767 }
2768 }
2769
2770 if (discoveryRequestTlv.IsValid())
2771 {
2772 if (mDiscoveryRequestCallback.IsSet())
2773 {
2774 otThreadDiscoveryRequestInfo info;
2775
2776 aRxInfo.mMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(AsCoreType(&info.mExtAddress));
2777 info.mVersion = discoveryRequestTlv.GetVersion();
2778 info.mIsJoiner = discoveryRequestTlv.IsJoiner();
2779
2780 mDiscoveryRequestCallback.Invoke(&info);
2781 }
2782
2783 if (discoveryRequestTlv.IsJoiner())
2784 {
2785 #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
2786 if (!mSteeringData.IsEmpty())
2787 {
2788 }
2789 else // if steering data is not set out of band, fall back to network data
2790 #endif
2791 {
2792 VerifyOrExit(Get<NetworkData::Leader>().IsJoiningAllowed(), error = kErrorSecurity);
2793 }
2794 }
2795 }
2796
2797 responseInfo.mPanId = aRxInfo.mMessage.GetPanId();
2798
2799 #if OPENTHREAD_CONFIG_MULTI_RADIO
2800 // Send the MLE Discovery Response message on same radio link
2801 // from which the "MLE Discover Request" message was received.
2802 responseInfo.mRadioType = aRxInfo.mMessage.GetRadioType();
2803 #endif
2804
2805 mDelayedSender.ScheduleDiscoveryResponse(aRxInfo.mMessageInfo.GetPeerAddr(), responseInfo,
2806 1 + Random::NonCrypto::GetUint16InRange(0, kDiscoveryMaxJitter));
2807
2808 exit:
2809 LogProcessError(kTypeDiscoveryRequest, error);
2810 }
2811
SendDiscoveryResponse(const Ip6::Address & aDestination,const DiscoveryResponseInfo & aInfo)2812 Error MleRouter::SendDiscoveryResponse(const Ip6::Address &aDestination, const DiscoveryResponseInfo &aInfo)
2813 {
2814 Error error = kErrorNone;
2815 TxMessage *message;
2816 uint16_t startOffset;
2817 Tlv tlv;
2818 MeshCoP::DiscoveryResponseTlv discoveryResponseTlv;
2819
2820 VerifyOrExit((message = NewMleMessage(kCommandDiscoveryResponse)) != nullptr, error = kErrorNoBufs);
2821 message->SetDirectTransmission();
2822 message->SetPanId(aInfo.mPanId);
2823 #if OPENTHREAD_CONFIG_MULTI_RADIO
2824 message->SetRadioType(aInfo.mRadioType);
2825 #endif
2826
2827 tlv.SetType(Tlv::kDiscovery);
2828 SuccessOrExit(error = message->Append(tlv));
2829
2830 startOffset = message->GetLength();
2831
2832 discoveryResponseTlv.Init();
2833 discoveryResponseTlv.SetVersion(kThreadVersion);
2834
2835 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
2836 if (Get<KeyManager>().GetSecurityPolicy().mNativeCommissioningEnabled)
2837 {
2838 SuccessOrExit(
2839 error = Tlv::Append<MeshCoP::CommissionerUdpPortTlv>(*message, Get<MeshCoP::BorderAgent>().GetUdpPort()));
2840
2841 discoveryResponseTlv.SetNativeCommissioner(true);
2842 }
2843 else
2844 #endif
2845 {
2846 discoveryResponseTlv.SetNativeCommissioner(false);
2847 }
2848
2849 if (Get<KeyManager>().GetSecurityPolicy().mCommercialCommissioningEnabled)
2850 {
2851 discoveryResponseTlv.SetCommercialCommissioningMode(true);
2852 }
2853
2854 SuccessOrExit(error = discoveryResponseTlv.AppendTo(*message));
2855
2856 SuccessOrExit(
2857 error = Tlv::Append<MeshCoP::ExtendedPanIdTlv>(*message, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
2858
2859 SuccessOrExit(error = Tlv::Append<MeshCoP::NetworkNameTlv>(
2860 *message, Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsCString()));
2861
2862 SuccessOrExit(error = message->AppendSteeringDataTlv());
2863
2864 SuccessOrExit(
2865 error = Tlv::Append<MeshCoP::JoinerUdpPortTlv>(*message, Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()));
2866
2867 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)
2868 if (!Get<MeshCoP::NetworkNameManager>().IsDefaultDomainNameSet())
2869 {
2870 SuccessOrExit(error = Tlv::Append<MeshCoP::ThreadDomainNameTlv>(
2871 *message, Get<MeshCoP::NetworkNameManager>().GetDomainName().GetAsCString()));
2872 }
2873 #endif
2874
2875 tlv.SetLength(static_cast<uint8_t>(message->GetLength() - startOffset));
2876 message->Write(startOffset - sizeof(tlv), tlv);
2877
2878 SuccessOrExit(error = message->SendTo(aDestination));
2879
2880 Log(kMessageSend, kTypeDiscoveryResponse, aDestination);
2881
2882 exit:
2883 FreeMessageOnError(message, error);
2884 LogProcessError(kTypeDiscoveryResponse, error);
2885 return error;
2886 }
2887
SendChildIdResponse(Child & aChild)2888 Error MleRouter::SendChildIdResponse(Child &aChild)
2889 {
2890 Error error = kErrorNone;
2891 Ip6::Address destination;
2892 TxMessage *message;
2893
2894 VerifyOrExit((message = NewMleMessage(kCommandChildIdResponse)) != nullptr, error = kErrorNoBufs);
2895 SuccessOrExit(error = message->AppendSourceAddressTlv());
2896 SuccessOrExit(error = message->AppendLeaderDataTlv());
2897 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
2898
2899 if ((aChild.GetRloc16() == 0) || !HasMatchingRouterIdWith(aChild.GetRloc16()))
2900 {
2901 uint16_t rloc16;
2902
2903 // Pick next Child ID that is not being used
2904 do
2905 {
2906 mNextChildId++;
2907
2908 if (mNextChildId > kMaxChildId)
2909 {
2910 mNextChildId = kMinChildId;
2911 }
2912
2913 rloc16 = Get<Mac::Mac>().GetShortAddress() | mNextChildId;
2914
2915 } while (mChildTable.FindChild(rloc16, Child::kInStateAnyExceptInvalid) != nullptr);
2916
2917 aChild.SetRloc16(rloc16);
2918 }
2919
2920 SuccessOrExit(error = message->AppendAddress16Tlv(aChild.GetRloc16()));
2921
2922 for (uint8_t i = 0; i < Child::kMaxRequestTlvs; i++)
2923 {
2924 switch (aChild.GetRequestTlv(i))
2925 {
2926 case Tlv::kNetworkData:
2927 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
2928 break;
2929
2930 case Tlv::kRoute:
2931 SuccessOrExit(error = message->AppendRouteTlv());
2932 break;
2933
2934 case Tlv::kActiveDataset:
2935 SuccessOrExit(error = message->AppendActiveDatasetTlv());
2936 break;
2937
2938 case Tlv::kPendingDataset:
2939 SuccessOrExit(error = message->AppendPendingDatasetTlv());
2940 break;
2941
2942 case Tlv::kSupervisionInterval:
2943 SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild.GetSupervisionInterval()));
2944 break;
2945
2946 default:
2947 break;
2948 }
2949 }
2950
2951 if (!aChild.IsFullThreadDevice())
2952 {
2953 SuccessOrExit(error = message->AppendAddressRegistrationTlv(aChild));
2954 }
2955
2956 SetChildStateToValid(aChild);
2957
2958 if (!aChild.IsRxOnWhenIdle())
2959 {
2960 Get<IndirectSender>().SetChildUseShortAddress(aChild, false);
2961 }
2962
2963 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
2964 if (aChild.IsTimeSyncEnabled())
2965 {
2966 message->SetTimeSync(true);
2967 }
2968 #endif
2969
2970 destination.SetToLinkLocalAddress(aChild.GetExtAddress());
2971 SuccessOrExit(error = message->SendTo(destination));
2972
2973 Log(kMessageSend, kTypeChildIdResponse, destination, aChild.GetRloc16());
2974
2975 exit:
2976 FreeMessageOnError(message, error);
2977 return error;
2978 }
2979
SendChildUpdateRequestToChild(Child & aChild)2980 Error MleRouter::SendChildUpdateRequestToChild(Child &aChild)
2981 {
2982 static const uint8_t kTlvs[] = {Tlv::kTimeout, Tlv::kAddressRegistration};
2983
2984 Error error = kErrorNone;
2985 Ip6::Address destination;
2986 TxMessage *message = nullptr;
2987
2988 if (!aChild.IsRxOnWhenIdle() && aChild.IsStateRestoring())
2989 {
2990 // No need to send the resync "Child Update Request"
2991 // to the sleepy child if there is one already
2992 // queued.
2993
2994 VerifyOrExit(!Get<IndirectSender>().HasQueuedMessageForSleepyChild(aChild, IsMessageChildUpdateRequest));
2995 }
2996
2997 Get<MeshForwarder>().RemoveMessagesForChild(aChild, IsMessageChildUpdateRequest);
2998
2999 VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
3000 SuccessOrExit(error = message->AppendSourceAddressTlv());
3001 SuccessOrExit(error = message->AppendLeaderDataTlv());
3002 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild.GetNetworkDataType()));
3003 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3004
3005 if (aChild.IsStateValid())
3006 {
3007 SuccessOrExit(error = message->AppendLinkMarginTlv(aChild.GetLinkInfo().GetLinkMargin()));
3008 }
3009 else
3010 {
3011 SuccessOrExit(error = message->AppendTlvRequestTlv(kTlvs));
3012
3013 if (!aChild.IsStateRestored())
3014 {
3015 // A random challenge is generated and saved when `aChild`
3016 // is first initialized in `kStateRestored`. We will use
3017 // the saved challenge here. This prevents overwriting
3018 // the saved challenge when the child is also detached
3019 // and happens to send a "Parent Request" in the window
3020 // where the parent transitions to the router/leader role
3021 // and before the parent sends the "Child Update Request".
3022 // This ensures that the same random challenge is
3023 // included in both "Parent Response" and "Child Update
3024 // Response," guaranteeing proper acceptance of the
3025 // child's "Child ID request".
3026
3027 aChild.GenerateChallenge();
3028 }
3029
3030 SuccessOrExit(error = message->AppendChallengeTlv(aChild.GetChallenge()));
3031 }
3032
3033 destination.SetToLinkLocalAddress(aChild.GetExtAddress());
3034 SuccessOrExit(error = message->SendTo(destination));
3035
3036 if (aChild.IsRxOnWhenIdle())
3037 {
3038 // only try to send a single Child Update Request message to an rx-on-when-idle child
3039 aChild.SetState(Child::kStateChildUpdateRequest);
3040 }
3041
3042 Log(kMessageSend, kTypeChildUpdateRequestOfChild, destination, aChild.GetRloc16());
3043
3044 exit:
3045 FreeMessageOnError(message, error);
3046 return error;
3047 }
3048
SendChildUpdateResponseToChild(Child * aChild,const Ip6::MessageInfo & aMessageInfo,const TlvList & aTlvList,const RxChallenge & aChallenge)3049 void MleRouter::SendChildUpdateResponseToChild(Child *aChild,
3050 const Ip6::MessageInfo &aMessageInfo,
3051 const TlvList &aTlvList,
3052 const RxChallenge &aChallenge)
3053 {
3054 Error error = kErrorNone;
3055 TxMessage *message;
3056
3057 VerifyOrExit((message = NewMleMessage(kCommandChildUpdateResponse)) != nullptr, error = kErrorNoBufs);
3058
3059 for (uint8_t tlvType : aTlvList)
3060 {
3061 // Add all TLV types that do not depend on `child`
3062
3063 switch (tlvType)
3064 {
3065 case Tlv::kStatus:
3066 SuccessOrExit(error = message->AppendStatusTlv(StatusTlv::kError));
3067 break;
3068
3069 case Tlv::kLeaderData:
3070 SuccessOrExit(error = message->AppendLeaderDataTlv());
3071 break;
3072
3073 case Tlv::kResponse:
3074 SuccessOrExit(error = message->AppendResponseTlv(aChallenge));
3075 break;
3076
3077 case Tlv::kSourceAddress:
3078 SuccessOrExit(error = message->AppendSourceAddressTlv());
3079 break;
3080
3081 case Tlv::kMleFrameCounter:
3082 SuccessOrExit(error = message->AppendMleFrameCounterTlv());
3083 break;
3084
3085 case Tlv::kLinkFrameCounter:
3086 SuccessOrExit(error = message->AppendLinkFrameCounterTlv());
3087 break;
3088 }
3089
3090 // Make sure `child` is not null before adding TLV types
3091 // that can depend on it.
3092
3093 if (aChild == nullptr)
3094 {
3095 continue;
3096 }
3097
3098 switch (tlvType)
3099 {
3100 case Tlv::kAddressRegistration:
3101 SuccessOrExit(error = message->AppendAddressRegistrationTlv(*aChild));
3102 break;
3103
3104 case Tlv::kMode:
3105 SuccessOrExit(error = message->AppendModeTlv(aChild->GetDeviceMode()));
3106 break;
3107
3108 case Tlv::kNetworkData:
3109 SuccessOrExit(error = message->AppendNetworkDataTlv(aChild->GetNetworkDataType()));
3110 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3111 break;
3112
3113 case Tlv::kTimeout:
3114 SuccessOrExit(error = message->AppendTimeoutTlv(aChild->GetTimeout()));
3115 break;
3116
3117 case Tlv::kLinkMargin:
3118 SuccessOrExit(error = message->AppendLinkMarginTlv(aChild->GetLinkInfo().GetLinkMargin()));
3119 break;
3120
3121 case Tlv::kSupervisionInterval:
3122 SuccessOrExit(error = message->AppendSupervisionIntervalTlv(aChild->GetSupervisionInterval()));
3123 break;
3124
3125 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
3126 case Tlv::kCslClockAccuracy:
3127 if (!aChild->IsRxOnWhenIdle())
3128 {
3129 SuccessOrExit(error = message->AppendCslClockAccuracyTlv());
3130 }
3131 break;
3132 #endif
3133 }
3134 }
3135
3136 SuccessOrExit(error = message->SendTo(aMessageInfo.GetPeerAddr()));
3137
3138 if (aChild == nullptr)
3139 {
3140 Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr());
3141 }
3142 else
3143 {
3144 Log(kMessageSend, kTypeChildUpdateResponseOfChild, aMessageInfo.GetPeerAddr(), aChild->GetRloc16());
3145 }
3146
3147 exit:
3148 FreeMessageOnError(message, error);
3149 }
3150
SendMulticastDataResponse(void)3151 void MleRouter::SendMulticastDataResponse(void)
3152 {
3153 Ip6::Address destination;
3154 TlvList tlvList;
3155
3156 destination.SetToLinkLocalAllNodesMulticast();
3157 tlvList.Add(Tlv::kNetworkData);
3158 SendDataResponse(destination, tlvList);
3159 }
3160
SendDataResponse(const Ip6::Address & aDestination,const TlvList & aTlvList,const Message * aRequestMessage)3161 void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
3162 const TlvList &aTlvList,
3163 const Message *aRequestMessage)
3164 {
3165 OT_UNUSED_VARIABLE(aRequestMessage);
3166
3167 Error error = kErrorNone;
3168 TxMessage *message = nullptr;
3169 Neighbor *neighbor;
3170
3171 VerifyOrExit(IsAttached());
3172
3173 if (mRetrieveNewNetworkData)
3174 {
3175 LogInfo("Suppressing Data Response - waiting for new network data");
3176 ExitNow();
3177 }
3178
3179 VerifyOrExit((message = NewMleMessage(kCommandDataResponse)) != nullptr, error = kErrorNoBufs);
3180 SuccessOrExit(error = message->AppendSourceAddressTlv());
3181 SuccessOrExit(error = message->AppendLeaderDataTlv());
3182 SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
3183
3184 for (uint8_t tlvType : aTlvList)
3185 {
3186 switch (tlvType)
3187 {
3188 case Tlv::kNetworkData:
3189 neighbor = mNeighborTable.FindNeighbor(aDestination);
3190 SuccessOrExit(error = message->AppendNetworkDataTlv((neighbor != nullptr) ? neighbor->GetNetworkDataType()
3191 : NetworkData::kFullSet));
3192 break;
3193
3194 case Tlv::kActiveDataset:
3195 SuccessOrExit(error = message->AppendActiveDatasetTlv());
3196 break;
3197
3198 case Tlv::kPendingDataset:
3199 SuccessOrExit(error = message->AppendPendingDatasetTlv());
3200 break;
3201
3202 case Tlv::kRoute:
3203 SuccessOrExit(error = message->AppendRouteTlv());
3204 break;
3205
3206 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3207 case Tlv::kLinkMetricsReport:
3208 OT_ASSERT(aRequestMessage != nullptr);
3209 neighbor = mNeighborTable.FindNeighbor(aDestination);
3210 VerifyOrExit(neighbor != nullptr, error = kErrorInvalidState);
3211 SuccessOrExit(error = Get<LinkMetrics::Subject>().AppendReport(*message, *aRequestMessage, *neighbor));
3212 break;
3213 #endif
3214 }
3215 }
3216
3217 SuccessOrExit(error = message->SendTo(aDestination));
3218 Log(kMessageSend, kTypeDataResponse, aDestination);
3219
3220 exit:
3221 FreeMessageOnError(message, error);
3222 LogSendError(kTypeDataResponse, error);
3223 }
3224
RemoveRouterLink(Router & aRouter)3225 void MleRouter::RemoveRouterLink(Router &aRouter)
3226 {
3227 switch (mRole)
3228 {
3229 case kRoleChild:
3230 if (&aRouter == &mParent)
3231 {
3232 IgnoreError(BecomeDetached());
3233 }
3234 break;
3235
3236 case kRoleRouter:
3237 case kRoleLeader:
3238 mRouterTable.RemoveRouterLink(aRouter);
3239 break;
3240
3241 default:
3242 break;
3243 }
3244 }
3245
RemoveNeighbor(Neighbor & aNeighbor)3246 void MleRouter::RemoveNeighbor(Neighbor &aNeighbor)
3247 {
3248 VerifyOrExit(!aNeighbor.IsStateInvalid());
3249
3250 if (&aNeighbor == &mParent)
3251 {
3252 if (IsChild())
3253 {
3254 IgnoreError(BecomeDetached());
3255 }
3256 }
3257 else if (&aNeighbor == &GetParentCandidate())
3258 {
3259 ClearParentCandidate();
3260 }
3261 else if (IsChildRloc16(aNeighbor.GetRloc16()))
3262 {
3263 OT_ASSERT(mChildTable.Contains(aNeighbor));
3264
3265 if (aNeighbor.IsStateValidOrRestoring())
3266 {
3267 mNeighborTable.Signal(NeighborTable::kChildRemoved, aNeighbor);
3268 }
3269
3270 Get<IndirectSender>().ClearAllMessagesForSleepyChild(static_cast<Child &>(aNeighbor));
3271
3272 if (aNeighbor.IsFullThreadDevice())
3273 {
3274 Get<AddressResolver>().RemoveEntriesForRloc16(aNeighbor.GetRloc16());
3275 }
3276
3277 mChildTable.RemoveStoredChild(static_cast<Child &>(aNeighbor));
3278 }
3279 else if (aNeighbor.IsStateValid())
3280 {
3281 OT_ASSERT(mRouterTable.Contains(aNeighbor));
3282
3283 mNeighborTable.Signal(NeighborTable::kRouterRemoved, aNeighbor);
3284 mRouterTable.RemoveRouterLink(static_cast<Router &>(aNeighbor));
3285 }
3286
3287 aNeighbor.GetLinkInfo().Clear();
3288 aNeighbor.SetState(Neighbor::kStateInvalid);
3289 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
3290 aNeighbor.RemoveAllForwardTrackingSeriesInfo();
3291 #endif
3292
3293 exit:
3294 return;
3295 }
3296
SetPreferredRouterId(uint8_t aRouterId)3297 Error MleRouter::SetPreferredRouterId(uint8_t aRouterId)
3298 {
3299 Error error = kErrorNone;
3300
3301 VerifyOrExit(IsDetached() || IsDisabled(), error = kErrorInvalidState);
3302
3303 mPreviousRouterId = aRouterId;
3304
3305 exit:
3306 return error;
3307 }
3308
SetRouterId(uint8_t aRouterId)3309 void MleRouter::SetRouterId(uint8_t aRouterId)
3310 {
3311 mRouterId = aRouterId;
3312 mPreviousRouterId = mRouterId;
3313 }
3314
SendAddressSolicit(ThreadStatusTlv::Status aStatus)3315 Error MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
3316 {
3317 Error error = kErrorNone;
3318 Tmf::MessageInfo messageInfo(GetInstance());
3319 Coap::Message *message = nullptr;
3320
3321 VerifyOrExit(!mAddressSolicitPending);
3322
3323 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressSolicit);
3324 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3325
3326 SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3327
3328 if (IsRouterIdValid(mPreviousRouterId))
3329 {
3330 SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mPreviousRouterId)));
3331 }
3332
3333 SuccessOrExit(error = Tlv::Append<ThreadStatusTlv>(*message, aStatus));
3334
3335 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3336 SuccessOrExit(error = Tlv::Append<XtalAccuracyTlv>(*message, otPlatTimeGetXtalAccuracy()));
3337 #endif
3338
3339 messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3340
3341 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, &HandleAddressSolicitResponse, this));
3342 mAddressSolicitPending = true;
3343
3344 Log(kMessageSend, kTypeAddressSolicit, messageInfo.GetPeerAddr());
3345
3346 exit:
3347 FreeMessageOnError(message, error);
3348 return error;
3349 }
3350
SendAddressRelease(void)3351 void MleRouter::SendAddressRelease(void)
3352 {
3353 Error error = kErrorNone;
3354 Tmf::MessageInfo messageInfo(GetInstance());
3355 Coap::Message *message;
3356
3357 message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriAddressRelease);
3358 VerifyOrExit(message != nullptr, error = kErrorNoBufs);
3359
3360 SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, Rloc16FromRouterId(mRouterId)));
3361 SuccessOrExit(error = Tlv::Append<ThreadExtMacAddressTlv>(*message, Get<Mac::Mac>().GetExtAddress()));
3362
3363 messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc();
3364
3365 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
3366
3367 Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr());
3368
3369 exit:
3370 FreeMessageOnError(message, error);
3371 LogSendError(kTypeAddressRelease, error);
3372 }
3373
HandleAddressSolicitResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aResult)3374 void MleRouter::HandleAddressSolicitResponse(void *aContext,
3375 otMessage *aMessage,
3376 const otMessageInfo *aMessageInfo,
3377 otError aResult)
3378 {
3379 static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(AsCoapMessagePtr(aMessage),
3380 AsCoreTypePtr(aMessageInfo), aResult);
3381 }
3382
HandleAddressSolicitResponse(Coap::Message * aMessage,const Ip6::MessageInfo * aMessageInfo,Error aResult)3383 void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage,
3384 const Ip6::MessageInfo *aMessageInfo,
3385 Error aResult)
3386 {
3387 uint8_t status;
3388 uint16_t rloc16;
3389 ThreadRouterMaskTlv routerMaskTlv;
3390 uint8_t routerId;
3391 Router *router;
3392
3393 mAddressSolicitPending = false;
3394
3395 VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
3396
3397 VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
3398
3399 Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
3400
3401 SuccessOrExit(Tlv::Find<ThreadStatusTlv>(*aMessage, status));
3402
3403 if (status != ThreadStatusTlv::kSuccess)
3404 {
3405 mAddressSolicitRejected = true;
3406
3407 if (IsRouterIdValid(mPreviousRouterId))
3408 {
3409 if (HasChildren())
3410 {
3411 RemoveChildren();
3412 }
3413
3414 SetRouterId(kInvalidRouterId);
3415 }
3416
3417 ExitNow();
3418 }
3419
3420 SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(*aMessage, rloc16));
3421 routerId = RouterIdFromRloc16(rloc16);
3422
3423 SuccessOrExit(Tlv::FindTlv(*aMessage, routerMaskTlv));
3424 VerifyOrExit(routerMaskTlv.IsValid());
3425
3426 SetAlternateRloc16(GetRloc16());
3427
3428 SetRouterId(routerId);
3429
3430 SetStateRouter(Rloc16FromRouterId(mRouterId));
3431
3432 // We keep the router table next hop and cost as what we had as a
3433 // REED, i.e., our parent was the next hop towards all other
3434 // routers and we tracked its cost towards them. As an FTD child,
3435 // we may have established links with a subset of neighboring routers.
3436 // We ensure to clear these links to avoid using them (since will
3437 // be rejected by the neighbor).
3438
3439 mRouterTable.ClearNeighbors();
3440
3441 mRouterTable.UpdateRouterIdSet(routerMaskTlv.GetIdSequence(), routerMaskTlv.GetAssignedRouterIdMask());
3442
3443 router = mRouterTable.FindRouterById(routerId);
3444 VerifyOrExit(router != nullptr);
3445 router->SetExtAddress(Get<Mac::Mac>().GetExtAddress());
3446 router->SetNextHopToInvalid();
3447
3448 // Ensure we have our parent as a neighboring router, copying the
3449 // `mParent` entry.
3450
3451 router = mRouterTable.FindRouterById(mParent.GetRouterId());
3452 VerifyOrExit(router != nullptr);
3453 router->SetFrom(mParent);
3454 router->SetState(Neighbor::kStateValid);
3455 router->SetNextHopToInvalid();
3456
3457 // Ensure we have a next hop and cost towards leader.
3458 if (mRouterTable.GetPathCostToLeader() >= kMaxRouteCost)
3459 {
3460 Router *leader = mRouterTable.GetLeader();
3461
3462 OT_ASSERT(leader != nullptr);
3463 leader->SetNextHopAndCost(RouterIdFromRloc16(mParent.GetRloc16()), mParent.GetLeaderCost());
3464 }
3465
3466 // We send a unicast Link Request to our former parent if its
3467 // version is earlier than 1.3. This is to address a potential
3468 // compatibility issue with some non-OpenThread stacks which may
3469 // ignore MLE Advertisements from a former/existing child.
3470
3471 if (mParent.GetVersion() < kThreadVersion1p3)
3472 {
3473 SendLinkRequest(&mParent);
3474 }
3475
3476 // We send an Advertisement to inform our former parent of our
3477 // newly allocated Router ID. This will cause the parent to
3478 // reset its advertisement trickle timer which can help speed
3479 // up the dissemination of the new Router ID to other routers.
3480 // This can also help with quicker link establishment with our
3481 // former parent and other routers.
3482 SendMulticastAdvertisement();
3483
3484 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
3485 {
3486 IgnoreError(SendChildIdResponse(child));
3487 }
3488
3489 exit:
3490 InformPreviousChannel();
3491 }
3492
SetChildRouterLinks(uint8_t aChildRouterLinks)3493 Error MleRouter::SetChildRouterLinks(uint8_t aChildRouterLinks)
3494 {
3495 Error error = kErrorNone;
3496
3497 VerifyOrExit(IsDisabled(), error = kErrorInvalidState);
3498 mChildRouterLinks = aChildRouterLinks;
3499 exit:
3500 return error;
3501 }
3502
IsExpectedToBecomeRouterSoon(void) const3503 bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
3504 {
3505 static constexpr uint8_t kMaxDelay = 10;
3506
3507 return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
3508 ((mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay) ||
3509 mAddressSolicitPending);
3510 }
3511
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3512 template <> void MleRouter::HandleTmf<kUriAddressSolicit>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3513 {
3514 Error error = kErrorNone;
3515 ThreadStatusTlv::Status responseStatus = ThreadStatusTlv::kNoAddressAvailable;
3516 Router *router = nullptr;
3517 Mac::ExtAddress extAddress;
3518 uint16_t rloc16;
3519 uint8_t status;
3520
3521 VerifyOrExit(mRole == kRoleLeader, error = kErrorInvalidState);
3522
3523 VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
3524
3525 Log(kMessageReceive, kTypeAddressSolicit, aMessageInfo.GetPeerAddr());
3526
3527 SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3528 SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, status));
3529
3530 switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
3531 {
3532 case kErrorNone:
3533 break;
3534 case kErrorNotFound:
3535 rloc16 = kInvalidRloc16;
3536 break;
3537 default:
3538 ExitNow(error = kErrorParse);
3539 }
3540
3541 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3542 {
3543 uint16_t xtalAccuracy;
3544
3545 SuccessOrExit(Tlv::Find<XtalAccuracyTlv>(aMessage, xtalAccuracy));
3546 VerifyOrExit(xtalAccuracy <= Get<TimeSync>().GetXtalThreshold());
3547 }
3548 #endif
3549
3550 router = mRouterTable.FindRouter(extAddress);
3551
3552 if (router != nullptr)
3553 {
3554 responseStatus = ThreadStatusTlv::kSuccess;
3555 ExitNow();
3556 }
3557
3558 switch (status)
3559 {
3560 case ThreadStatusTlv::kTooFewRouters:
3561 VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
3562 break;
3563
3564 case ThreadStatusTlv::kHaveChildIdRequest:
3565 case ThreadStatusTlv::kParentPartitionChange:
3566 break;
3567
3568 case ThreadStatusTlv::kBorderRouterRequest:
3569 if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
3570 (Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
3571 kRouterUpgradeBorderRouterRequestThreshold))
3572 {
3573 LogInfo("Rejecting BR %s router role req - have %u BR routers", extAddress.ToString().AsCString(),
3574 kRouterUpgradeBorderRouterRequestThreshold);
3575 ExitNow();
3576 }
3577 break;
3578
3579 default:
3580 responseStatus = ThreadStatusTlv::kUnrecognizedStatus;
3581 ExitNow();
3582 }
3583
3584 if (rloc16 != kInvalidRloc16)
3585 {
3586 router = mRouterTable.Allocate(RouterIdFromRloc16(rloc16));
3587
3588 if (router != nullptr)
3589 {
3590 LogInfo("Router id %u requested and provided!", RouterIdFromRloc16(rloc16));
3591 }
3592 }
3593
3594 if (router == nullptr)
3595 {
3596 router = mRouterTable.Allocate();
3597 VerifyOrExit(router != nullptr);
3598 }
3599
3600 router->SetExtAddress(extAddress);
3601 responseStatus = ThreadStatusTlv::kSuccess;
3602
3603 exit:
3604 if (error == kErrorNone)
3605 {
3606 SendAddressSolicitResponse(aMessage, responseStatus, router, aMessageInfo);
3607 }
3608 }
3609
SendAddressSolicitResponse(const Coap::Message & aRequest,ThreadStatusTlv::Status aResponseStatus,const Router * aRouter,const Ip6::MessageInfo & aMessageInfo)3610 void MleRouter::SendAddressSolicitResponse(const Coap::Message &aRequest,
3611 ThreadStatusTlv::Status aResponseStatus,
3612 const Router *aRouter,
3613 const Ip6::MessageInfo &aMessageInfo)
3614 {
3615 Coap::Message *message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
3616
3617 VerifyOrExit(message != nullptr);
3618
3619 SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aResponseStatus));
3620
3621 if (aRouter != nullptr)
3622 {
3623 ThreadRouterMaskTlv routerMaskTlv;
3624
3625 SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aRouter->GetRloc16()));
3626
3627 routerMaskTlv.Init();
3628 routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3629 mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask());
3630
3631 SuccessOrExit(routerMaskTlv.AppendTo(*message));
3632 }
3633
3634 SuccessOrExit(Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
3635 message = nullptr;
3636
3637 Log(kMessageSend, kTypeAddressReply, aMessageInfo.GetPeerAddr());
3638
3639 // If assigning a new RLOC16 (e.g., on promotion of a child to
3640 // router role) we clear any address cache entries associated
3641 // with the old RLOC16 unless the sender is a direct child. For
3642 // direct children, we retain the cache entries to allow
3643 // association with the promoted router's new RLOC16 upon
3644 // receiving its Link Advertisement.
3645
3646 if ((aResponseStatus == ThreadStatusTlv::kSuccess) && (aRouter != nullptr))
3647 {
3648 uint16_t oldRloc16;
3649
3650 VerifyOrExit(IsRoutingLocator(aMessageInfo.GetPeerAddr()));
3651 oldRloc16 = aMessageInfo.GetPeerAddr().GetIid().GetLocator();
3652
3653 VerifyOrExit(oldRloc16 != aRouter->GetRloc16());
3654 VerifyOrExit(!RouterIdMatch(oldRloc16, GetRloc16()));
3655 Get<AddressResolver>().RemoveEntriesForRloc16(oldRloc16);
3656 }
3657
3658 exit:
3659 FreeMessage(message);
3660 }
3661
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)3662 template <> void MleRouter::HandleTmf<kUriAddressRelease>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
3663 {
3664 uint16_t rloc16;
3665 Mac::ExtAddress extAddress;
3666 uint8_t routerId;
3667 Router *router;
3668
3669 VerifyOrExit(mRole == kRoleLeader);
3670
3671 VerifyOrExit(aMessage.IsConfirmablePostRequest());
3672
3673 Log(kMessageReceive, kTypeAddressRelease, aMessageInfo.GetPeerAddr());
3674
3675 SuccessOrExit(Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16));
3676 SuccessOrExit(Tlv::Find<ThreadExtMacAddressTlv>(aMessage, extAddress));
3677
3678 routerId = RouterIdFromRloc16(rloc16);
3679 router = mRouterTable.FindRouterById(routerId);
3680
3681 VerifyOrExit((router != nullptr) && (router->GetExtAddress() == extAddress));
3682
3683 IgnoreError(mRouterTable.Release(routerId));
3684
3685 SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo));
3686
3687 Log(kMessageSend, kTypeAddressReleaseReply, aMessageInfo.GetPeerAddr());
3688
3689 exit:
3690 return;
3691 }
3692
FillConnectivityTlv(ConnectivityTlv & aTlv)3693 void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
3694 {
3695 int8_t parentPriority = kParentPriorityMedium;
3696
3697 if (mParentPriority != kParentPriorityUnspecified)
3698 {
3699 parentPriority = mParentPriority;
3700 }
3701 else
3702 {
3703 uint16_t numChildren = mChildTable.GetNumChildren(Child::kInStateValid);
3704 uint16_t maxAllowed = mChildTable.GetMaxChildrenAllowed();
3705
3706 if ((maxAllowed - numChildren) < (maxAllowed / 3))
3707 {
3708 parentPriority = kParentPriorityLow;
3709 }
3710 else
3711 {
3712 parentPriority = kParentPriorityMedium;
3713 }
3714 }
3715
3716 aTlv.SetParentPriority(parentPriority);
3717
3718 aTlv.SetLinkQuality1(0);
3719 aTlv.SetLinkQuality2(0);
3720 aTlv.SetLinkQuality3(0);
3721
3722 if (IsChild())
3723 {
3724 aTlv.IncrementLinkQuality(mParent.GetLinkQualityIn());
3725 }
3726
3727 for (const Router &router : Get<RouterTable>())
3728 {
3729 if (router.GetRloc16() == GetRloc16())
3730 {
3731 continue;
3732 }
3733
3734 if (!router.IsStateValid())
3735 {
3736 continue;
3737 }
3738
3739 aTlv.IncrementLinkQuality(router.GetTwoWayLinkQuality());
3740 }
3741
3742 aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
3743 aTlv.SetLeaderCost(Min(mRouterTable.GetPathCostToLeader(), kMaxRouteCost));
3744 aTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
3745 aTlv.SetSedBufferSize(OPENTHREAD_CONFIG_DEFAULT_SED_BUFFER_SIZE);
3746 aTlv.SetSedDatagramCount(OPENTHREAD_CONFIG_DEFAULT_SED_DATAGRAM_COUNT);
3747 }
3748
ShouldDowngrade(uint8_t aNeighborId,const RouteTlv & aRouteTlv) const3749 bool MleRouter::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
3750 {
3751 // Determine whether all conditions are satisfied for the router
3752 // to downgrade after receiving info for a neighboring router
3753 // with Router ID `aNeighborId` along with its `aRouteTlv`.
3754
3755 bool shouldDowngrade = false;
3756 uint8_t activeRouterCount = mRouterTable.GetActiveRouterCount();
3757 uint8_t count;
3758
3759 VerifyOrExit(IsRouter());
3760 VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
3761
3762 VerifyOrExit(!mRouterRoleTransition.IsPending());
3763
3764 VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
3765
3766 // Check that we have at least `kMinDowngradeNeighbors`
3767 // neighboring routers with two-way link quality of 2 or better.
3768
3769 count = 0;
3770
3771 for (const Router &router : mRouterTable)
3772 {
3773 if (!router.IsStateValid() || (router.GetTwoWayLinkQuality() < kLinkQuality2))
3774 {
3775 continue;
3776 }
3777
3778 count++;
3779
3780 if (count >= kMinDowngradeNeighbors)
3781 {
3782 break;
3783 }
3784 }
3785
3786 VerifyOrExit(count >= kMinDowngradeNeighbors);
3787
3788 // Check that we have fewer children than three times the number
3789 // of excess routers (defined as the difference between number of
3790 // active routers and `mRouterDowngradeThreshold`).
3791
3792 count = activeRouterCount - mRouterDowngradeThreshold;
3793 VerifyOrExit(mChildTable.GetNumChildren(Child::kInStateValid) < count * 3);
3794
3795 // Check that the neighbor has as good or better-quality links to
3796 // same routers.
3797
3798 VerifyOrExit(NeighborHasComparableConnectivity(aRouteTlv, aNeighborId));
3799
3800 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3801 // Check if we are eligible to be router due to being a BR.
3802 VerifyOrExit(!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter());
3803 #endif
3804
3805 shouldDowngrade = true;
3806
3807 exit:
3808 return shouldDowngrade;
3809 }
3810
NeighborHasComparableConnectivity(const RouteTlv & aRouteTlv,uint8_t aNeighborId) const3811 bool MleRouter::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const
3812 {
3813 // Check whether the neighboring router with Router ID `aNeighborId`
3814 // (along with its `aRouteTlv`) has as good or better-quality links
3815 // to all our neighboring routers which have a two-way link quality
3816 // of two or better.
3817
3818 bool isComparable = true;
3819
3820 for (uint8_t routerId = 0, index = 0; routerId <= kMaxRouterId;
3821 index += aRouteTlv.IsRouterIdSet(routerId) ? 1 : 0, routerId++)
3822 {
3823 const Router *router;
3824 LinkQuality localLinkQuality;
3825 LinkQuality peerLinkQuality;
3826
3827 if ((routerId == mRouterId) || (routerId == aNeighborId))
3828 {
3829 continue;
3830 }
3831
3832 router = mRouterTable.FindRouterById(routerId);
3833
3834 if ((router == nullptr) || !router->IsStateValid())
3835 {
3836 continue;
3837 }
3838
3839 localLinkQuality = router->GetTwoWayLinkQuality();
3840
3841 if (localLinkQuality < kLinkQuality2)
3842 {
3843 continue;
3844 }
3845
3846 // `router` is our neighbor with two-way link quality of
3847 // at least two. Check that `aRouteTlv` has as good or
3848 // better-quality link to it as well.
3849
3850 if (!aRouteTlv.IsRouterIdSet(routerId))
3851 {
3852 ExitNow(isComparable = false);
3853 }
3854
3855 peerLinkQuality = Min(aRouteTlv.GetLinkQualityIn(index), aRouteTlv.GetLinkQualityOut(index));
3856
3857 if (peerLinkQuality < localLinkQuality)
3858 {
3859 ExitNow(isComparable = false);
3860 }
3861 }
3862
3863 exit:
3864 return isComparable;
3865 }
3866
SetChildStateToValid(Child & aChild)3867 void MleRouter::SetChildStateToValid(Child &aChild)
3868 {
3869 VerifyOrExit(!aChild.IsStateValid());
3870
3871 aChild.SetState(Neighbor::kStateValid);
3872 IgnoreError(mChildTable.StoreChild(aChild));
3873
3874 #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
3875 Get<MlrManager>().UpdateProxiedSubscriptions(aChild, MlrManager::MlrAddressArray());
3876 #endif
3877
3878 mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
3879
3880 exit:
3881 return;
3882 }
3883
HasChildren(void)3884 bool MleRouter::HasChildren(void) { return mChildTable.HasChildren(Child::kInStateValidOrAttaching); }
3885
RemoveChildren(void)3886 void MleRouter::RemoveChildren(void)
3887 {
3888 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
3889 {
3890 RemoveNeighbor(child);
3891 }
3892 }
3893
SetAssignParentPriority(int8_t aParentPriority)3894 Error MleRouter::SetAssignParentPriority(int8_t aParentPriority)
3895 {
3896 Error error = kErrorNone;
3897
3898 VerifyOrExit(aParentPriority <= kParentPriorityHigh && aParentPriority >= kParentPriorityUnspecified,
3899 error = kErrorInvalidArgs);
3900
3901 mParentPriority = aParentPriority;
3902
3903 exit:
3904 return error;
3905 }
3906
GetMaxChildTimeout(uint32_t & aTimeout) const3907 Error MleRouter::GetMaxChildTimeout(uint32_t &aTimeout) const
3908 {
3909 Error error = kErrorNotFound;
3910
3911 aTimeout = 0;
3912
3913 VerifyOrExit(IsRouterOrLeader(), error = kErrorInvalidState);
3914
3915 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
3916 {
3917 if (child.IsFullThreadDevice())
3918 {
3919 continue;
3920 }
3921
3922 if (child.GetTimeout() > aTimeout)
3923 {
3924 aTimeout = child.GetTimeout();
3925 }
3926
3927 error = kErrorNone;
3928 }
3929
3930 exit:
3931 return error;
3932 }
3933
3934 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
SendTimeSync(void)3935 Error MleRouter::SendTimeSync(void)
3936 {
3937 Error error = kErrorNone;
3938 Ip6::Address destination;
3939 TxMessage *message = nullptr;
3940
3941 VerifyOrExit((message = NewMleMessage(kCommandTimeSync)) != nullptr, error = kErrorNoBufs);
3942
3943 message->SetTimeSync(true);
3944
3945 destination.SetToLinkLocalAllNodesMulticast();
3946 SuccessOrExit(error = message->SendTo(destination));
3947
3948 Log(kMessageSend, kTypeTimeSync, destination);
3949
3950 exit:
3951 FreeMessageOnError(message, error);
3952 return error;
3953 }
3954 #endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
3955
3956 //----------------------------------------------------------------------------------------------------------------------
3957 // RouterRoleTransition
3958
RouterRoleTransition(void)3959 MleRouter::RouterRoleTransition::RouterRoleTransition(void)
3960 : mTimeout(0)
3961 , mJitter(kRouterSelectionJitter)
3962 {
3963 }
3964
StartTimeout(void)3965 void MleRouter::RouterRoleTransition::StartTimeout(void)
3966 {
3967 mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter);
3968 }
3969
HandleTimeTick(void)3970 bool MleRouter::RouterRoleTransition::HandleTimeTick(void)
3971 {
3972 bool expired = false;
3973
3974 VerifyOrExit(mTimeout > 0);
3975 mTimeout--;
3976 expired = (mTimeout == 0);
3977
3978 exit:
3979 return expired;
3980 }
3981
3982 //----------------------------------------------------------------------------------------------------------------------
3983 // RouterRoleRestorer
3984
RouterRoleRestorer(Instance & aInstance)3985 MleRouter::RouterRoleRestorer::RouterRoleRestorer(Instance &aInstance)
3986 : InstanceLocator(aInstance)
3987 , mAttempts(0)
3988 {
3989 }
3990
Start(DeviceRole aPreviousRole)3991 void MleRouter::RouterRoleRestorer::Start(DeviceRole aPreviousRole)
3992 {
3993 // If the device was previously the leader or had more than
3994 // `kMinCriticalChildrenCount` children, we use more link
3995 // request attempts.
3996
3997 mAttempts = 0;
3998
3999 switch (aPreviousRole)
4000 {
4001 case kRoleRouter:
4002 if (Get<MleRouter>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount)
4003 {
4004 mAttempts = kMaxTxCount;
4005 break;
4006 }
4007
4008 OT_FALL_THROUGH;
4009
4010 case kRoleLeader:
4011 mAttempts = kMaxCriticalTxCount;
4012 break;
4013
4014 case kRoleChild:
4015 case kRoleDetached:
4016 case kRoleDisabled:
4017 break;
4018 }
4019
4020 SendMulticastLinkRequest();
4021 }
4022
HandleTimer(void)4023 void MleRouter::RouterRoleRestorer::HandleTimer(void)
4024 {
4025 if (mAttempts > 0)
4026 {
4027 mAttempts--;
4028 }
4029
4030 SendMulticastLinkRequest();
4031 }
4032
SendMulticastLinkRequest(void)4033 void MleRouter::RouterRoleRestorer::SendMulticastLinkRequest(void)
4034 {
4035 uint32_t delay;
4036
4037 VerifyOrExit(Get<Mle>().IsDetached(), mAttempts = 0);
4038
4039 if (mAttempts == 0)
4040 {
4041 IgnoreError(Get<Mle>().BecomeDetached());
4042 ExitNow();
4043 }
4044
4045 Get<MleRouter>().SendLinkRequest(nullptr);
4046
4047 delay = (mAttempts == 1) ? kLinkRequestTimeout
4048 : Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
4049
4050 Get<Mle>().mAttachTimer.Start(delay);
4051
4052 exit:
4053 return;
4054 }
4055
4056 } // namespace Mle
4057 } // namespace ot
4058
4059 #endif // OPENTHREAD_FTD
4060