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