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