diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 5253d69b8..0b47bbe99 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (245) +#define OPENTHREAD_API_VERSION (246) /** * @addtogroup api-instance diff --git a/include/openthread/srp_server.h b/include/openthread/srp_server.h index fba71749b..4c928e0d2 100644 --- a/include/openthread/srp_server.h +++ b/include/openthread/srp_server.h @@ -132,14 +132,14 @@ enum }; /** - * Represents the state of an SRP server + * This enumeration represents the state of the SRP server. * */ typedef enum { OT_SRP_SERVER_STATE_DISABLED = 0, ///< The SRP server is disabled. - OT_SRP_SERVER_STATE_RUNNING = 1, ///< The SRP server is running. - OT_SRP_SERVER_STATE_STOPPED = 2, ///< The SRP server is stopped. + OT_SRP_SERVER_STATE_RUNNING = 1, ///< The SRP server is enabled and running. + OT_SRP_SERVER_STATE_STOPPED = 2, ///< The SRP server is enabled but stopped. } otSrpServerState; /** @@ -302,12 +302,49 @@ otError otSrpServerSetAnycastModeSequenceNumber(otInstance *aInstance, uint8_t a /** * This function enables/disables the SRP server. * + * On a Border Router, it is recommended to use `otSrpServerSetAutoEnableMode()` instead. + * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aEnabled A boolean to enable/disable the SRP server. * */ void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled); +/** + * This function enables/disables the auto-enable mode on SRP server. + * + * This function requires `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` feature. + * + * When this mode is enabled, the Border Routing Manager controls if/when to enable or disable the SRP server. + * SRP sever is auto-enabled if/when Border Routing is started and it is done with the initial prefix and route + * configurations (when the OMR and on-link prefixes are determined, advertised in emitted Router Advertisement message + * on infrastructure side and published in the Thread Network Data). The SRP server is auto-disabled if/when BR is + * stopped (e.g., if the infrastructure network interface is brought down or if BR gets detached). + * + * This mode can be disabled by a `otSrpServerSetAutoEnableMode()` call with @p aEnabled set to `false` or if the SRP + * server is explicitly enabled or disabled by a call to `otSrpServerSetEnabled()` function. Disabling auto-enable mode + * using `otSrpServerSetAutoEnableMode(false)` will not change the current state of SRP sever (e.g., if it is enabled + * it stays enabled). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEnbaled A boolean to enable/disable the auto-enable mode. + * + */ +void otSrpServerSetAutoEnableMode(otInstance *aInstance, bool aEnabled); + +/** + * This function indicates whether the auto-enable mode is enabled or disabled. + * + * This function requires `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` feature. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE The auto-enable mode is enabled. + * @retval FALSE The auto-enable mode is disabled. + * + */ +bool otSrpServerIsAutoEnableMode(otInstance *aInstance); + /** * This function returns SRP server TTL configuration. * diff --git a/src/cli/cli_srp_server.cpp b/src/cli/cli_srp_server.cpp index e13b8eca6..474b950ab 100644 --- a/src/cli/cli_srp_server.cpp +++ b/src/cli/cli_srp_server.cpp @@ -96,6 +96,47 @@ otError SrpServer::ProcessAddrMode(Arg aArgs[]) return error; } +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +otError SrpServer::ProcessAuto(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + + /** + * @cli srp server auto + * @code + * srp server auto + * Disabled + * Done + * @endcode + * @par api_copy + * #otSrpServerIsAutoEnableMode + */ + if (aArgs[0].IsEmpty()) + { + OutputEnabledDisabledStatus(otSrpServerIsAutoEnableMode(GetInstancePtr())); + } + /** + * @cli srp server auto enable + * @code + * srp server auto enable + * Done + * @endcode + * @par api_copy + * #otSrpServerSetAutoEnableMode + */ + else + { + bool enable; + + SuccessOrExit(error = Interpreter::ParseEnableOrDisable(aArgs[0], enable)); + otSrpServerSetAutoEnableMode(GetInstancePtr(), enable); + } + +exit: + return error; +} +#endif + otError SrpServer::ProcessDomain(Arg aArgs[]) { otError error = OT_ERROR_NONE; diff --git a/src/cli/cli_srp_server.hpp b/src/cli/cli_srp_server.hpp index 363f59118..1a29c9e95 100644 --- a/src/cli/cli_srp_server.hpp +++ b/src/cli/cli_srp_server.hpp @@ -82,6 +82,9 @@ private: using Command = CommandEntry; otError ProcessAddrMode(Arg aArgs[]); +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + otError ProcessAuto(Arg aArgs[]); +#endif otError ProcessDomain(Arg aArgs[]); otError ProcessState(Arg aArgs[]); otError ProcessEnable(Arg aArgs[]); @@ -96,11 +99,19 @@ private: void OutputHostAddresses(const otSrpServerHost *aHost); static constexpr Command sCommands[] = { - {"addrmode", &SrpServer::ProcessAddrMode}, {"disable", &SrpServer::ProcessDisable}, - {"domain", &SrpServer::ProcessDomain}, {"enable", &SrpServer::ProcessEnable}, - {"help", &SrpServer::ProcessHelp}, {"host", &SrpServer::ProcessHost}, - {"lease", &SrpServer::ProcessLease}, {"seqnum", &SrpServer::ProcessSeqNum}, - {"service", &SrpServer::ProcessService}, {"state", &SrpServer::ProcessState}, + {"addrmode", &SrpServer::ProcessAddrMode}, +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + {"auto", &SrpServer::ProcessAuto}, +#endif + {"disable", &SrpServer::ProcessDisable}, + {"domain", &SrpServer::ProcessDomain}, + {"enable", &SrpServer::ProcessEnable}, + {"help", &SrpServer::ProcessHelp}, + {"host", &SrpServer::ProcessHost}, + {"lease", &SrpServer::ProcessLease}, + {"seqnum", &SrpServer::ProcessSeqNum}, + {"service", &SrpServer::ProcessService}, + {"state", &SrpServer::ProcessState}, {"ttl", &SrpServer::ProcessTtl}, }; diff --git a/src/core/api/srp_server_api.cpp b/src/core/api/srp_server_api.cpp index f9d4367e4..488164a25 100644 --- a/src/core/api/srp_server_api.cpp +++ b/src/core/api/srp_server_api.cpp @@ -87,6 +87,18 @@ void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled) AsCoreType(aInstance).Get().SetEnabled(aEnabled); } +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +void otSrpServerSetAutoEnableMode(otInstance *aInstance, bool aEnabled) +{ + AsCoreType(aInstance).Get().SetAutoEnableMode(aEnabled); +} + +bool otSrpServerIsAutoEnableMode(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().IsAutoEnableMode(); +} +#endif + void otSrpServerGetTtlConfig(otInstance *aInstance, otSrpServerTtlConfig *aTtlConfig) { AsCoreType(aInstance).Get().GetTtlConfig(AsCoreType(aTtlConfig)); diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 0793cb1ca..1c82cc8ce 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -286,10 +286,36 @@ void RoutingManager::Stop(void) mIsRunning = false; +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + if (Get().IsAutoEnableMode()) + { + Get().Disable(); + } +#endif + exit: return; } +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE +void RoutingManager::HandleSrpServerAutoEnableMode(void) +{ + VerifyOrExit(Get().IsAutoEnableMode()); + + if (IsInitalPolicyEvaluationDone()) + { + Get().Enable(); + } + else + { + Get().Disable(); + } + +exit: + return; +} +#endif + void RoutingManager::HandleReceived(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress) { const Ip6::Icmp::Header *icmp6Header; @@ -410,7 +436,7 @@ void RoutingManager::EvaluateOmrPrefix(void) { LogInfo("EvaluateOmrPrefix: No preferred OMR prefix found in Thread network"); - // The `aNewPrefixes` remains empty if we fail to publish + // The `mFavoredOmrPrefix` remains empty if we fail to publish // the local OMR prefix. SuccessOrExit(mLocalOmrPrefix.AddToNetData()); @@ -537,9 +563,33 @@ void RoutingManager::EvaluateRoutingPolicy(void) SendRouterAdvertisement(kAdvPrefixesFromNetData); +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + if (Get().IsAutoEnableMode() && IsInitalPolicyEvaluationDone()) + { + // If SRP server uses the auto-enable mode, we enable the SRP + // server on the first RA transmission after we are done with + // initial prefix/route configurations. Note that if SRP server + // is already enabled, calling `Enable()` again does nothing. + + Get().Enable(); + } +#endif + ScheduleRoutingPolicyEvaluation(kForNextRa); } +bool RoutingManager::IsInitalPolicyEvaluationDone(void) const +{ + // This method indicates whether or not we are done with the + // initial policy evaluation and prefix and route setup, i.e., + // the OMR and on-link prefixes are determined, advertised in + // the emitted Router Advert message on infrastructure side + // and published in the Thread Network Data. + + return mIsRunning && !mFavoredOmrPrefix.IsEmpty() && + (mFavoredDiscoveredOnLinkPrefix.GetLength() != 0 || mLocalOnLinkPrefix.IsAdvertising()); +} + void RoutingManager::ScheduleRoutingPolicyEvaluation(ScheduleMode aMode) { TimeMilli now = TimerMilli::GetNow(); diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index fd6e228e4..880032065 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -310,6 +310,16 @@ public: return mDiscoveredPrefixTable.GetNextEntry(aIterator, aEntry); } +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + /** + * This method determines whether to enable/disable SRP server when the auto-enable mode is changed on SRP server. + * + * This should be called from `Srp::Server` when auto-enable mode is changed. + * + */ + void HandleSrpServerAutoEnableMode(void); +#endif + private: static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES; @@ -728,6 +738,7 @@ private: void EvaluateOnLinkPrefix(void); void EvaluateRoutingPolicy(void); + bool IsInitalPolicyEvaluationDone(void) const; void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode); void EvaluateOmrPrefix(void); Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false); @@ -741,7 +752,6 @@ private: void HandleDiscoveredPrefixStaleTimer(void); static void HandleRoutingPolicyTimer(Timer &aTimer); - void DeprecateOnLinkPrefix(void); void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress); void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress); bool ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, const Ip6::Prefix &aPrefix); diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index f31244c3c..d04d1f7d0 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -96,6 +96,9 @@ Server::Server(Instance &aInstance) , mAddressMode(kDefaultAddressMode) , mAnycastSequenceNumber(0) , mHasRegisteredAnyService(false) +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + , mAutoEnable(false) +#endif { IgnoreError(SetDomain(kDefaultDomain)); } @@ -134,41 +137,71 @@ exit: void Server::SetEnabled(bool aEnabled) { +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + mAutoEnable = false; +#endif + if (aEnabled) { - VerifyOrExit(mState == kStateDisabled); - mState = kStateStopped; - - // Request publishing of "DNS/SRP Address Service" entry in the - // Thread Network Data based of `mAddressMode`. Then wait for - // callback `HandleNetDataPublisherEntryChange()` from the - // `Publisher` to start the SRP server. - - switch (mAddressMode) - { - case kAddressModeUnicast: - SelectPort(); - Get().PublishDnsSrpServiceUnicast(mPort); - break; - - case kAddressModeAnycast: - mPort = kAnycastAddressModePort; - Get().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber); - break; - } + Enable(); } else { - VerifyOrExit(mState != kStateDisabled); - Get().UnpublishDnsSrpService(); - Stop(); - mState = kStateDisabled; + Disable(); + } +} + +void Server::Enable(void) +{ + VerifyOrExit(mState == kStateDisabled); + mState = kStateStopped; + + // Request publishing of "DNS/SRP Address Service" entry in the + // Thread Network Data based of `mAddressMode`. Then wait for + // callback `HandleNetDataPublisherEntryChange()` from the + // `Publisher` to start the SRP server. + + switch (mAddressMode) + { + case kAddressModeUnicast: + SelectPort(); + Get().PublishDnsSrpServiceUnicast(mPort); + break; + + case kAddressModeAnycast: + mPort = kAnycastAddressModePort; + Get().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber); + break; } exit: return; } +void Server::Disable(void) +{ + VerifyOrExit(mState != kStateDisabled); + Get().UnpublishDnsSrpService(); + Stop(); + mState = kStateDisabled; + +exit: + return; +} + +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +void Server::SetAutoEnableMode(bool aEnabled) +{ + VerifyOrExit(mAutoEnable != aEnabled); + mAutoEnable = aEnabled; + + Get().HandleSrpServerAutoEnableMode(); + +exit: + return; +} +#endif + Server::TtlConfig::TtlConfig(void) { mMinTtl = kDefaultMinTtl; diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index 302ccc6cb..dbf609076 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -92,6 +92,12 @@ class Server; } } // namespace Dns +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE +namespace BorderRouter { +class RoutingManager; +} +#endif + namespace Srp { /** @@ -105,6 +111,9 @@ class Server : public InstanceLocator, private NonCopyable friend class Service; friend class Host; friend class Dns::ServiceDiscovery::Server; +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + friend class BorderRouter::RoutingManager; +#endif enum RetainName : bool { @@ -151,11 +160,15 @@ public: class Host; + /** + * This enumeration represents the state of SRP server. + * + */ enum State : uint8_t { - kStateDisabled = OT_SRP_SERVER_STATE_DISABLED, - kStateRunning = OT_SRP_SERVER_STATE_RUNNING, - kStateStopped = OT_SRP_SERVER_STATE_STOPPED, + kStateDisabled = OT_SRP_SERVER_STATE_DISABLED, ///< Server is disabled. + kStateRunning = OT_SRP_SERVER_STATE_RUNNING, ///< Server is enabled and running. + kStateStopped = OT_SRP_SERVER_STATE_STOPPED, ///< Server is enabled but stopped. }; /** @@ -775,17 +788,9 @@ public: Error SetAnycastModeSequenceNumber(uint8_t aSequenceNumber); /** - * This method tells whether the SRP server is currently running. + * This method returns the state of the SRP server. * - * @returns A boolean that indicates whether the server is running. - * - */ - bool IsRunning(void) const { return (mState == kStateRunning); } - - /** - * This method tells the state of the SRP server. - * - * @returns An enum that represents the state of the server. + * @returns The state of the server. * */ State GetState(void) const { return mState; } @@ -793,10 +798,10 @@ public: /** * This method tells the port the SRP server is listening to. * - * @returns An integer that represents the port of the server. It returns 0 if the SRP server is not running. + * @returns The port of the server or 0 if the SRP server is not running. * */ - uint16_t GetPort(void) const { return IsRunning() ? mPort : 0; } + uint16_t GetPort(void) const { return (mState == kStateRunning) ? mPort : 0; } /** * This method enables/disables the SRP server. @@ -806,6 +811,35 @@ public: */ void SetEnabled(bool aEnabled); +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + /** + * This method enables/disables the auto-enable mode on SRP server. + * + * When this mode is enabled, the Border Routing Manager controls if/when to enable or disable the SRP server. + * SRP sever is auto-enabled if/when Border Routing is started it is done with the initial prefix and route + * configurations (when the OMR and on-link prefixes are determined, advertised in emitted Router Advert message on + * infrastructure side and published in the Thread Network Data). The SRP server is auto-disabled when BR is + * stopped (e.g., if the infrastructure network interface is brought down or if BR gets detached). + * + * This mode can be disabled by a `SetAutoEnableMode(false)` call or if the SRP server is explicitly enabled or + * disabled by a call to `SetEnabled()` method. Disabling auto-enable mode using `SetAutoEnableMode(false` call + * will not change the current state of SRP sever (e.g., if it is enabled it stays enabled). + * + * @param[in] aEnbaled A boolean to enable/disable the auto-enable mode. + * + */ + void SetAutoEnableMode(bool aEnabled); + + /** + * This method indicates whether the auto-enable mode is enabled or disabled. + * + * @retval TRUE The auto-enable mode is enabled. + * @retval FALSE The auto-enable mode is disabled. + * + */ + bool IsAutoEnableMode(void) const { return mAutoEnable; } +#endif + /** * This method returns the TTL configuration. * @@ -942,6 +976,8 @@ private: bool mIsDirectRxFromClient; }; + void Enable(void); + void Disable(void); void Start(void); void Stop(void); void SelectPort(void); @@ -1039,6 +1075,9 @@ private: AddressMode mAddressMode; uint8_t mAnycastSequenceNumber; bool mHasRegisteredAnyService : 1; +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + bool mAutoEnable : 1; +#endif otSrpServerResponseCounters mResponseCounters; }; diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index b5e9f0046..36da3aff5 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -1721,6 +1721,213 @@ void TestExtPanIdChange(void) testFreeInstance(sInstance); } +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE +void TestAutoEnableOfSrpServer(void) +{ + Ip6::Prefix localOnLink; + Ip6::Prefix localOmr; + Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); + Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64); + + Log("--------------------------------------------------------------------------------------------"); + Log("TestAutoEnableOfSrpServer"); + + InitTest(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check SRP Server state and enable auto-enable mode + + otSrpServerSetAutoEnableMode(sInstance, true); + VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance)); + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start Routing Manager. Check emitted RS and RA messages. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + + SuccessOrQuit(sInstance->Get().SetEnabled(true)); + + SuccessOrQuit(sInstance->Get().GetOnLinkPrefix(localOnLink)); + SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); + + Log("Local on-link prefix is %s", localOnLink.ToString().AsCString()); + Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + + sExpectedRios.Add(localOmr); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Validate that SRP server was auto-enabled + + VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is enabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Signal that infra if state changed and is no longer running. + // This should stop Routing Manager and in turn the SRP server. + + sRaValidated = false; + sExpectedPio = kPioDeprecatingLocalOnLink; + + Log("Signal infra if is not running"); + SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false)); + AdvanceTime(1); + + VerifyOrQuit(sRaValidated); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that SRP server is disabled. + + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is disabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Signal that infra if state changed and is running again. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Add(localOmr); + + Log("Signal infra if is running"); + SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, true)); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that SRP server is enabled again. + + VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is enabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Disable `RoutingManager` explicitly. + + sRaValidated = false; + sExpectedPio = kPioDeprecatingLocalOnLink; + + Log("Disabling RoutingManager"); + SuccessOrQuit(sInstance->Get().SetEnabled(false)); + AdvanceTime(1); + + VerifyOrQuit(sRaValidated); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that SRP server is also disabled. + + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is disabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Disable auto-enable mode on SRP server. + + otSrpServerSetAutoEnableMode(sInstance, false); + VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance)); + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Re-start Routing Manager. Check emitted RS and RA messages. + // This cycle, router A will send a RA including a PIO. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kNoPio; + sExpectedRios.Clear(); + + SuccessOrQuit(sInstance->Get().SetEnabled(true)); + + SuccessOrQuit(sInstance->Get().GetOnLinkPrefix(localOnLink)); + SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); + + Log("Local on-link prefix is %s", localOnLink.ToString().AsCString()); + Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + + sExpectedRios.Add(localOmr); + + AdvanceTime(2000); + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that SRP server is still disabled. + + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is disabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Enable auto-enable mode on SRP server. Since `RoutingManager` + // is already done with initial policy evaluation, the SRP server + // must be started immediately. + + otSrpServerSetAutoEnableMode(sInstance, true); + VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance)); + + VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is enabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Disable auto-enable mode on SRP server. It must not impact + // its current state and it should remain enabled. + + otSrpServerSetAutoEnableMode(sInstance, false); + VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance)); + + AdvanceTime(2000); + VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is enabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Signal that infra if state changed and is no longer running. + // This should stop Routing Manager. + + sRaValidated = false; + + Log("Signal infra if is not running"); + SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false)); + AdvanceTime(1); + + VerifyOrQuit(sRaValidated); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Re-enable auto-enable mode on SRP server. Since `RoutingManager` + // is stopped (infra if is down), the SRP serer must be stopped + // immediately. + + otSrpServerSetAutoEnableMode(sInstance, true); + VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance)); + + VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED); + Log("Srp::Server is disabled"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Log("End of TestAutoEnableOfSrpServer"); + testFreeInstance(sInstance); +} +#endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE int main(void) @@ -1734,6 +1941,9 @@ int main(void) TestDomainPrefixAsOmr(); #endif TestExtPanIdChange(); +#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE + TestAutoEnableOfSrpServer(); +#endif printf("All tests passed\n"); #else printf("BORDER_ROUTING feature is not enabled\n");