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