@@ -131,7 +131,7 @@ void Mle::UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason)
131131 // Take action based on the current role, the new `mRouterRoleAllowed`,
132132 // and the reason for the change.
133133
134- if (IsChild () && mRouterRoleAllowed && (aReason == kReasonConfigParameterChanged ))
134+ if (IsChild () && mRouterRoleAllowed && (aReason == kReasonConfigParameterChanged ) && ShouldUpgrade () )
135135 {
136136 StartRouterRoleUpgradeTransition ();
137137 }
@@ -343,11 +343,12 @@ void Mle::HandleChildStart(void)
343343{
344344 mAddressSolicitRejected = false ;
345345
346- if (IsRouterRoleAllowed ())
346+ if (ShouldUpgrade ())
347347 {
348348 // As a REED, re-start the timer to check for a role upgrade when re-attaching as a Child
349349 StartRouterRoleUpgradeTransition ();
350350 }
351+ // If the REED shouldn't upgrade, then it may begin sending advertisements on the next time tick.
351352
352353 StopLeader ();
353354 Get<TimeTicker>().RegisterReceiver (TimeTicker::kMle );
@@ -1310,7 +1311,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
13101311 ExitNow (error = kErrorDetached );
13111312 }
13121313
1313- if (mRouterTable . GetActiveRouterCount () < mRouterUpgradeThreshold )
1314+ if (ShouldUpgrade () )
13141315 {
13151316 if (!IsRouterRoleTransitioning ())
13161317 {
@@ -1348,7 +1349,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
13481349 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13491350 // Update routers as a router or leader.
13501351
1351- if (ShouldDowngrade (routerId, routeTlv))
1352+ if (ShouldBeginDowngradeTimer (routerId, routeTlv))
13521353 {
13531354 // Downgrade conditions have been met after an advertisement from another active router
13541355 StartRouterRoleDowngradeTransition ();
@@ -1623,7 +1624,7 @@ void Mle::HandleTimeTick(void)
16231624 else if (IsRouterRoleUpgradePending ())
16241625 {
16251626 // An upgrade should be performed, if the conditions to upgrade still apply
1626- if (mRouterTable . GetActiveRouterCount () < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality ())
1627+ if (ShouldUpgrade () && HasNeighborWithGoodLinkQuality ())
16271628 {
16281629 IgnoreError (BecomeRouter (kReasonTooFewRouters ));
16291630 // Any attempt to become a router will also clear the current role transition
@@ -1649,7 +1650,7 @@ void Mle::HandleTimeTick(void)
16491650 if (mRouterRoleTransition .IsDowngradePending ())
16501651 {
16511652 bool roleAllowed = IsRouterRoleAllowed ();
1652- bool shouldRouterDowngrade = IsRouter () && mRouterTable . GetActiveRouterCount () > mRouterDowngradeThreshold ;
1653+ bool shouldRouterDowngrade = ShouldRouterDowngrade () ;
16531654 if (!roleAllowed || shouldRouterDowngrade)
16541655 {
16551656 if (IsRouter ())
@@ -3830,71 +3831,90 @@ void Mle::FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const
38303831 aTlvValue.InitFrom (connectivity);
38313832}
38323833
3833- bool Mle::ShouldDowngrade (uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
3834+ bool Mle::ShouldBeginDowngradeTimer (uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
38343835{
38353836 // Determine whether all conditions are satisfied for the router
38363837 // to downgrade after receiving info for a neighboring router
38373838 // with Router ID `aNeighborId` along with its `aRouteTlv`.
38383839
3839- bool shouldDowngrade = false ;
3840- uint8_t activeRouterCount = mRouterTable .GetActiveRouterCount ();
3841- uint8_t count;
3840+ bool shouldDowngrade = false ;
38423841
3843- VerifyOrExit (IsRouter ());
38443842 VerifyOrExit (mRouterTable .IsAllocated (aNeighborId));
3845- VerifyOrExit (!mBlockDowngrade );
38463843
38473844 // Return false, to let an existing downgrade transition continue
38483845 VerifyOrExit (!mRouterRoleTransition .IsDowngrading ());
38493846
3847+ VerifyOrExit (ShouldRouterDowngrade ());
3848+
3849+ // Check that the neighbor has as good or better-quality links to the same routers.
3850+ VerifyOrExit (NeighborHasComparableConnectivity (aNeighborId, aRouteTlv));
3851+
3852+ #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3853+ // Check if we are eligible to be router due to being a BR.
3854+ VerifyOrExit (!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter ());
3855+ #endif
3856+
3857+ shouldDowngrade = true ;
3858+
3859+ exit:
3860+ return shouldDowngrade;
3861+ }
3862+
3863+ bool Mle::ShouldRouterDowngrade (void ) const
3864+ {
3865+ uint8_t count;
3866+ uint8_t excessRouters;
3867+ bool shouldDowngrade = false ;
3868+ uint8_t activeRouterCount = mRouterTable .GetActiveRouterCount ();
3869+
3870+ // Only kRoleRouter may downgrade.
3871+ // kRoleLeader may not downgrade due to these conditions, and other roles are not applicable.
3872+ VerifyOrExit (IsRouter ());
3873+
3874+ VerifyOrExit (!mBlockDowngrade );
38503875 VerifyOrExit (activeRouterCount > mRouterDowngradeThreshold );
38513876
3877+ excessRouters = (activeRouterCount > mRouterDowngradeThreshold ) ? activeRouterCount - mRouterDowngradeThreshold : 0 ;
3878+ VerifyOrExit (mChildTable .GetNumChildren (Child::kInStateValid ) < excessRouters * 3 );
3879+
38523880 // Check that we have at least `kMinDowngradeNeighbors`
38533881 // neighboring routers with two-way link quality of 2 or better.
3854-
38553882 count = 0 ;
3856-
38573883 for (const Router &router : mRouterTable )
38583884 {
38593885 if (!router.IsStateValid () || (router.GetTwoWayLinkQuality () < kLinkQuality2 ))
38603886 {
38613887 continue ;
38623888 }
3863-
38643889 count++;
3865-
38663890 if (count >= kMinDowngradeNeighbors )
38673891 {
38683892 break ;
38693893 }
38703894 }
3871-
38723895 VerifyOrExit (count >= kMinDowngradeNeighbors );
38733896
3874- // Check that we have fewer children than three times the number
3875- // of excess routers (defined as the difference between number of
3876- // active routers and `mRouterDowngradeThreshold`).
3877-
3878- count = activeRouterCount - mRouterDowngradeThreshold ;
3879- VerifyOrExit (mChildTable .GetNumChildren (Child::kInStateValid ) < count * 3 );
3880-
3881- // Check that the neighbor has as good or better-quality links to
3882- // same routers.
3897+ shouldDowngrade = true ;
3898+ exit:
3899+ return shouldDowngrade;
3900+ }
38833901
3884- VerifyOrExit (NeighborHasComparableConnectivity (aRouteTlv, aNeighborId));
3902+ bool Mle::ShouldUpgrade (void ) const
3903+ {
3904+ bool shouldUpgrade = false ;
38853905
3886- #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
3887- // Check if we are eligible to be router due to being a BR.
3888- VerifyOrExit (!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter ());
3889- #endif
3906+ VerifyOrExit (IsRouterRoleAllowed ());
38903907
3891- shouldDowngrade = true ;
3908+ if (mRouterTable .GetActiveRouterCount () < mRouterUpgradeThreshold )
3909+ {
3910+ shouldUpgrade = true ;
3911+ }
38923912
38933913exit:
3894- return shouldDowngrade ;
3914+ return shouldUpgrade ;
38953915}
38963916
3897- bool Mle::NeighborHasComparableConnectivity (const RouteTlv &aRouteTlv, uint8_t aNeighborId ) const
3917+ bool Mle::NeighborHasComparableConnectivity (uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
38983918{
38993919 // Check whether the neighboring router with Router ID `aNeighborId`
39003920 // (along with its `aRouteTlv`) has as good or better-quality links
0 commit comments