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