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