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