diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index ae405a27f..ee34cee92 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -119,6 +119,21 @@ public: */ Error SetEnabled(bool aEnabled); + /** + * This method requests the Border Routing Manager to stop. + * + * If Border Routing Manager is running, calling this method immediately stops it and triggers the preparation + * and sending of a final Router Advertisement (RA) message on infrastructure interface which deprecates and/or + * removes any previously advertised PIO/RIO prefixes. If Routing Manager is not running (or not enabled), no + * action is taken. + * + * Note that this method does not change whether the Routing Manager is enabled or disabled (see `SetEnabled()`). + * It stops the Routing Manager temporarily. After calling this method if the device role gets changes (device + * gets attached) and/or the infra interface state gets changed, the Routing Manager may be started again. + * + */ + void RequestStop(void) { Stop(); } + /** * This method gets the preference used when advertising Route Info Options (e.g., for discovered OMR prefixes) in * Router Advertisement messages sent over the infrastructure link. diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 1d9900c05..e71096f22 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -4295,7 +4295,8 @@ uint64_t Mle::CalcParentCslMetric(const Mac::CslAccuracy &aCslAccuracy) Error Mle::DetachGracefully(otDetachGracefullyCallback aCallback, void *aContext) { - Error error = kErrorNone; + Error error = kErrorNone; + uint32_t timeout = kDetachGracefullyTimeout; VerifyOrExit(!IsDetachingGracefully(), error = kErrorBusy); @@ -4304,27 +4305,36 @@ Error Mle::DetachGracefully(otDetachGracefullyCallback aCallback, void *aContext mDetachGracefullyCallback = aCallback; mDetachGracefullyContext = aContext; - if (IsChild() || IsRouter()) +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + Get().RequestStop(); +#endif + + switch (mRole) { - mDetachGracefullyTimer.Start(kDetachGracefullyTimeout); - } - else - { - // If the device is a leader, or it's already detached or disabled, we start the timer with zero duration to - // stop and invoke the callback when the timer fires, so the operation finishes immediately and asynchronously. - mDetachGracefullyTimer.Start(0); + case kRoleLeader: + break; + + case kRoleRouter: +#if OPENTHREAD_FTD + Get().SendAddressRelease(); +#endif + break; + + case kRoleChild: + IgnoreError(SendChildUpdateRequest(/* aAppendChallenge */ false, /* aTimeout */ 0)); + break; + + case kRoleDisabled: + case kRoleDetached: + // If device is already detached or disabled, we start the timer + // with zero duration to stop and invoke the callback when the + // timer fires, so the operation finishes immediately and + // asynchronously. + timeout = 0; + break; } - if (IsChild()) - { - IgnoreError(SendChildUpdateRequest(/* aAppendChallenge */ false, /* aTimeout */ 0)); - } -#if OPENTHREAD_FTD - else if (IsRouter()) - { - Get().SendAddressRelease(&Mle::HandleDetachGracefullyAddressReleaseResponse, this); - } -#endif + mDetachGracefullyTimer.Start(timeout); exit: return error; @@ -4340,28 +4350,6 @@ void Mle::HandleDetachGracefullyTimer(void) Stop(); } -#if OPENTHREAD_FTD -void Mle::HandleDetachGracefullyAddressReleaseResponse(void * aContext, - otMessage * aMessage, - const otMessageInfo *aMessageInfo, - Error aResult) -{ - OT_UNUSED_VARIABLE(aMessage); - OT_UNUSED_VARIABLE(aMessageInfo); - OT_UNUSED_VARIABLE(aResult); - - static_cast(aContext)->HandleDetachGracefullyAddressReleaseResponse(); -} - -void Mle::HandleDetachGracefullyAddressReleaseResponse(void) -{ - if (IsDetachingGracefully()) - { - Stop(); - } -} -#endif // OPENTHREAD_FTD - //--------------------------------------------------------------------------------------------------------------------- // TlvList diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 4029b1f61..1feda0d32 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3760,7 +3760,7 @@ exit: return error; } -void MleRouter::SendAddressRelease(Coap::ResponseHandler aResponseHandler, void *aResponseHandlerContext) +void MleRouter::SendAddressRelease(void) { Error error = kErrorNone; Tmf::MessageInfo messageInfo(GetInstance()); @@ -3774,8 +3774,7 @@ void MleRouter::SendAddressRelease(Coap::ResponseHandler aResponseHandler, void SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderRloc()); - SuccessOrExit(error = - Get().SendMessage(*message, messageInfo, aResponseHandler, aResponseHandlerContext)); + SuccessOrExit(error = Get().SendMessage(*message, messageInfo)); Log(kMessageSend, kTypeAddressRelease, messageInfo.GetPeerAddr()); diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 774827a76..4dca318ba 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -570,15 +570,6 @@ public: void SetThreadVersionCheckEnabled(bool aEnabled) { mThreadVersionCheckEnabled = aEnabled; } #endif - /** - * This function sends an Address Release. - * - * @param[in] aResponseHandler A pointer to a function that is called upon response reception or time-out. - * @param[in] aResponseHandlerContext A pointer to callback application-specific context. - * - */ - void SendAddressRelease(Coap::ResponseHandler aResponseHandler = nullptr, void *aResponseHandlerContext = nullptr); - private: static constexpr uint16_t kDiscoveryMaxJitter = 250; // Max jitter delay Discovery Responses (in msec). static constexpr uint32_t kStateUpdatePeriod = 1000; // State update period (in msec). @@ -615,6 +606,7 @@ private: ThreadStatusTlv::Status aResponseStatus, const Router * aRouter, const Ip6::MessageInfo &aMessageInfo); + void SendAddressRelease(void); void SendAdvertisement(void); Error SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neighbor * aNeighbor,