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