diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 117a3e887..d638ca843 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (479) +#define OPENTHREAD_API_VERSION (480) /** * @addtogroup api-instance diff --git a/include/openthread/srp_server.h b/include/openthread/srp_server.h index 541ec9710..45fa6e732 100644 --- a/include/openthread/srp_server.h +++ b/include/openthread/srp_server.h @@ -84,11 +84,17 @@ typedef enum * * Address mode specifies how the address and port number are determined by the SRP server and how this info is * published in the Thread Network Data. + * + * @warning Using the `OT_SRP_SERVER_ADDRESS_MODE_UNICAST_FORCE_ADD` option will make the implementation + * non-compliant with the Thread specification. This option is intended for testing and specific use-cases. + * When selected, the SRP server, upon being enabled, will bypass the Network Data publisher and always add the + * "SRP/DNS unicast" entry directly to the Network Data, regardless of how many other similar entries are present. */ typedef enum otSrpServerAddressMode { - OT_SRP_SERVER_ADDRESS_MODE_UNICAST = 0, ///< Unicast address mode. - OT_SRP_SERVER_ADDRESS_MODE_ANYCAST = 1, ///< Anycast address mode. + OT_SRP_SERVER_ADDRESS_MODE_UNICAST = 0, ///< Unicast address mode. Use Network Data publisher. + OT_SRP_SERVER_ADDRESS_MODE_ANYCAST = 1, ///< Anycast address mode. Use Network Data publisher + OT_SRP_SERVER_ADDRESS_MODE_UNICAST_FORCE_ADD = 2, ///< Unicast address mode. Immediately force add to Network Data. } otSrpServerAddressMode; /** diff --git a/src/cli/cli_srp_server.cpp b/src/cli/cli_srp_server.cpp index 5e71a4a24..0845c5de6 100644 --- a/src/cli/cli_srp_server.cpp +++ b/src/cli/cli_srp_server.cpp @@ -54,7 +54,7 @@ namespace Cli { * anycast * Done * @endcode - * @cparam srp server addrmode [@ca{anycast}|@ca{unicast}] + * @cparam srp server addrmode [@ca{anycast}|@ca{unicast}|@ca{unicast-force-add}] * @par * Gets or sets the address mode used by the SRP server. * @par @@ -78,6 +78,10 @@ template <> otError SrpServer::Process(Arg aArgs[]) case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST: OutputLine("anycast"); break; + + case OT_SRP_SERVER_ADDRESS_MODE_UNICAST_FORCE_ADD: + OutputLine("unicast-force-add"); + break; } error = OT_ERROR_NONE; @@ -90,6 +94,10 @@ template <> otError SrpServer::Process(Arg aArgs[]) { error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_ANYCAST); } + else if (aArgs[0] == "unicast-force-add") + { + error = otSrpServerSetAddressMode(GetInstancePtr(), OT_SRP_SERVER_ADDRESS_MODE_UNICAST_FORCE_ADD); + } return error; } diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 2b086f975..9dd3b0a8a 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -144,6 +144,9 @@ void Server::Enable(void) // Thread Network Data based of `mAddressMode`. Then wait for // callback `HandleNetDataPublisherEvent()` from the // `Publisher` to start the SRP server. + // + // For `kAddressModeUnicastForceAdd`, directly add the entry + // in the Network Data and start. switch (mAddressMode) { @@ -156,6 +159,14 @@ void Server::Enable(void) mPort = kAnycastAddressModePort; Get().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber, kSrpVersion); break; + + case kAddressModeUnicastForceAdd: + SelectPort(); + SuccessOrExit(Get().AddDnsSrpUnicastServiceWithAddrInServerData( + Get().GetMeshLocalEid(), mPort, kSrpVersion)); + Get().HandleServerDataUpdated(); + Start(); + break; } exit: @@ -165,7 +176,20 @@ exit: void Server::Disable(void) { VerifyOrExit(mState != kStateDisabled); - Get().UnpublishDnsSrpService(); + + switch (mAddressMode) + { + case kAddressModeUnicast: + case kAddressModeAnycast: + Get().UnpublishDnsSrpService(); + break; + + case kAddressModeUnicastForceAdd: + IgnoreError(Get().RemoveDnsSrpUnicastServiceWithAddrInServerData()); + Get().HandleServerDataUpdated(); + break; + } + Stop(); mState = kStateDisabled; @@ -551,7 +575,8 @@ void Server::CommitSrpUpdate(Error aError, } #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE - if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast)) + if (!mHasRegisteredAnyService && + ((mAddressMode == kAddressModeUnicast) || (mAddressMode == kAddressModeUnicastForceAdd))) { Settings::SrpServerInfo info; @@ -1714,8 +1739,9 @@ void Server::HandleOutstandingUpdatesTimer(void) const char *Server::AddressModeToString(AddressMode aMode) { static const char *const kAddressModeStrings[] = { - "unicast", // (0) kAddressModeUnicast - "anycast", // (1) kAddressModeAnycast + "unicast", // (0) kAddressModeUnicast + "anycast", // (1) kAddressModeAnycast + "unicast-force-add", // (2) kAddressModeUnicastForceAdd }; struct EnumCheck @@ -1723,6 +1749,7 @@ const char *Server::AddressModeToString(AddressMode aMode) InitEnumValidatorCounter(); ValidateNextEnum(kAddressModeUnicast); ValidateNextEnum(kAddressModeAnycast); + ValidateNextEnum(kAddressModeUnicastForceAdd); }; return kAddressModeStrings[aMode]; diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index d77e60088..d2353e775 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -159,8 +159,9 @@ public: */ enum AddressMode : uint8_t { - kAddressModeUnicast = OT_SRP_SERVER_ADDRESS_MODE_UNICAST, ///< Unicast address mode. - kAddressModeAnycast = OT_SRP_SERVER_ADDRESS_MODE_ANYCAST, ///< Anycast address mode. + kAddressModeUnicast = OT_SRP_SERVER_ADDRESS_MODE_UNICAST, ///< Unicast mode with publisher. + kAddressModeAnycast = OT_SRP_SERVER_ADDRESS_MODE_ANYCAST, ///< Anycast mode with publisher. + kAddressModeUnicastForceAdd = OT_SRP_SERVER_ADDRESS_MODE_UNICAST_FORCE_ADD ///< Unicast - force add. }; class Host; diff --git a/tests/toranj/cli/cli.py b/tests/toranj/cli/cli.py index ee66f96fa..4bd3ecaa8 100644 --- a/tests/toranj/cli/cli.py +++ b/tests/toranj/cli/cli.py @@ -676,7 +676,8 @@ class Node(object): return self._cli_single_output('srp server state', expected_outputs=['disabled', 'running', 'stopped']) def srp_server_get_addr_mode(self): - return self._cli_single_output('srp server addrmode', expected_outputs=['unicast', 'anycast']) + return self._cli_single_output('srp server addrmode', + expected_outputs=['unicast', 'anycast', 'unicast-force-add']) def srp_server_set_addr_mode(self, mode): self._cli_no_output('srp server addrmode', mode) diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index 07fac5751..a9aa5ec30 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -1207,6 +1207,74 @@ void TestSrpClientDelayedResponse(void) #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +void TestSrpServerAddressModeForceAdd(void) +{ + Srp::Server *srpServer; + Srp::Client *srpClient; + uint16_t heapAllocations; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestSrpServerAddressModeForceAdd"); + + InitTest(); + + srpServer = &sInstance->Get(); + srpClient = &sInstance->Get(); + + heapAllocations = sHeapAllocatedPtrs.GetLength(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Set address mode to `kAddressModeUnicastForceAdd`. + + SuccessOrQuit(srpServer->SetAddressMode(Srp::Server::kAddressModeUnicastForceAdd)); + VerifyOrQuit(srpServer->GetAddressMode() == Srp::Server::kAddressModeUnicastForceAdd); + + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateDisabled); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP server, ensure it starts quickly. + + srpServer->SetEnabled(true); + VerifyOrQuit(srpServer->GetState() != Srp::Server::kStateDisabled); + + AdvanceTime(0); + VerifyOrQuit(srpServer->GetState() == Srp::Server::kStateRunning); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start SRP client and validate that it discovers server. + + srpClient->SetCallback(HandleSrpClientCallback, sInstance); + + srpClient->EnableAutoStartMode(nullptr, nullptr); + VerifyOrQuit(srpClient->IsAutoStartModeEnabled()); + + AdvanceTime(2000); + VerifyOrQuit(srpClient->IsRunning()); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Disable SRP server. Validate that the NetData entry is removed and + // client detects this. + + Log("Disabling SRP server"); + + srpServer->SetEnabled(false); + AdvanceTime(1); + + VerifyOrQuit(!srpClient->IsRunning()); + + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Finalize OT instance and validate all heap allocations are freed. + + Log("Finalizing OT instance"); + FinalizeTest(); + + VerifyOrQuit(sHeapAllocatedPtrs.IsEmpty()); + + Log("End of TestSrpServerAddressModeForceAdd"); +} + #endif // ENABLE_SRP_TEST } // namespace ot @@ -1223,6 +1291,7 @@ int main(void) ot::TestUpdateLeaseShortVariant(); ot::TestSrpClientDelayedResponse(); #endif + ot::TestSrpServerAddressModeForceAdd(); printf("All tests passed\n"); #else