mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 06:17:47 +00:00
[network-data] add new DNS/SRP anycast/unicast service definitions (#6501)
This commit adds new network data service entry definitions to indicate presence of DNS/SRP servers within the Thread mesh and provide info about them. Two service TLV formats are added: `NetworkData::Service::DnsSrpAnycast` indicates that DNS/SRP client on a device can use the associated anycast address with this service TLV to reach the DNS/SRP server. The use of anycast address ensures that the messages are routed to the nearest node which has added such a service entry in the network data. The service TLV data in this model contains a one byte sequence number which is used to notify the SRP clients if they need to re-register with the server(s) (e.g., due server reset/reboot and/or loss of previous registrations). `NetworkData::Service::DnsSrpUnicast` directly provides the IPv6 address and port info for a DNS/SRP server which can be included as part of the service TLV data and/or the server TLV data. Using service TLV data allows the info about a common infrastructure SRP/DNS server to be added by multiple BRs. In the case of server TLV, the IPv6 address info can be optionally omitted (i.e. just a port number is provided) which then causes the associated RLOC/ALOC address of the node who added the service entry to be used as the server's IPv6 address. This commit updates the `Srp::Client` to use the new service entries to discover/select the SRP sever when auto-start mode is enabled. The client prefers and uses a `DnsSrpAnycast` over `DnsSrpUnicast` entries. The `Srp::Server` is also updated to publish its info as `DnsSrpAnycast` entry (using mesh-local address). This commit also updates the `test_network_data` unit test to cover the behavior of newly methods which iterate and parse different service entry formats.
This commit is contained in:
@@ -504,4 +504,9 @@
|
||||
#error "OPENTHREAD_CONFIG_ANNOUNCE_SENDER_INTERVAL_REED was replaced by OPENTHREAD_CONFIG_ANNOUNCE_SENDER_INTERVAL"
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER
|
||||
#error "OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER was removed. "\
|
||||
"Service numbers are defined in `network_data_servcie.hpp` per spec"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_CONFIG_CHECK_H_
|
||||
|
||||
@@ -55,16 +55,6 @@
|
||||
#define OPENTHREAD_CONFIG_SRP_SERVER_UDP_PORT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER
|
||||
*
|
||||
* Specifies the Thread Network Data Service number for SRP Server.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER
|
||||
#define OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER 0x5du
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_UPDATE_TIMEOUT
|
||||
*
|
||||
|
||||
@@ -295,6 +295,14 @@ public:
|
||||
*/
|
||||
const Address &GetAddress(void) const { return *static_cast<const Address *>(&mAddress); }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 address.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address.
|
||||
*
|
||||
*/
|
||||
void SetAddress(const Address &aAddress) { mAddress = aAddress; }
|
||||
|
||||
/**
|
||||
* This method returns the socket address port number.
|
||||
*
|
||||
|
||||
+62
-27
@@ -150,6 +150,7 @@ Client::Client(Instance &aInstance)
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
, mAutoStartModeEnabled(kAutoStartDefaultMode)
|
||||
, mAutoStartDidSelectServer(false)
|
||||
, mAutoStartIsUsingAnycastAddress(false)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
, mServiceKeyRecordEnabled(false)
|
||||
@@ -165,6 +166,7 @@ Client::Client(Instance &aInstance)
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
, mAutoStartCallback(nullptr)
|
||||
, mAutoStartContext(nullptr)
|
||||
, mServerSequenceNumber(0)
|
||||
#endif
|
||||
, mDomainName(kDefaultDomainName)
|
||||
, mTimer(aInstance, Client::HandleTimer)
|
||||
@@ -311,7 +313,7 @@ void Client::HandleNotifierEvents(Events aEvents)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
if (aEvents.Contains(kEventThreadNetdataChanged))
|
||||
if (aEvents.ContainsAny(kEventThreadNetdataChanged | kEventThreadMeshLocalAddrChanged))
|
||||
{
|
||||
ProcessAutoStart();
|
||||
}
|
||||
@@ -1510,51 +1512,84 @@ exit:
|
||||
|
||||
void Client::ProcessAutoStart(void)
|
||||
{
|
||||
uint16_t numServers = 0;
|
||||
NetworkData::Service::SrpServer::Info selectedServer;
|
||||
NetworkData::Service::SrpServer::Info server;
|
||||
NetworkData::Service::Manager::Iterator iterator;
|
||||
Ip6::SockAddr serverSockAddr;
|
||||
bool serverIsAnycast = false;
|
||||
NetworkData::Service::DnsSrpAnycast::Info anycastInfo;
|
||||
|
||||
VerifyOrExit(mAutoStartModeEnabled);
|
||||
|
||||
// If the client is not running we check if there is any SRP sever
|
||||
// info in Network Data and select one randomly and then start the
|
||||
// client. If the client is already running with a server that was
|
||||
// selected by the auto-start feature, we verify that the selected
|
||||
// server is still present in the Network Data.
|
||||
serverSockAddr.Clear();
|
||||
|
||||
// If the SRP client is not running and auto start mode is
|
||||
// enabled, we check if we can find any SRP server info in the
|
||||
// Thread Network Data. If it is already running and the server
|
||||
// was chosen by the auto-start feature, then we ensure that the
|
||||
// selected server is still present in the Network Data.
|
||||
//
|
||||
// Two types of "DNS/SRP Service" entries can be present in
|
||||
// Network Data, "DNS/SRP Service Anycast Address" model and
|
||||
// "DNS/SRP Service Unicast" model. The Anycast entries are
|
||||
// preferred over the Unicast entries.
|
||||
|
||||
VerifyOrExit(!IsRunning() || mAutoStartDidSelectServer);
|
||||
|
||||
while (Get<NetworkData::Service::Manager>().GetNextSrpServerInfo(iterator, server) == kErrorNone)
|
||||
// Now `IsRunning()` implies `mAutoStartDidSelectServer`.
|
||||
|
||||
if (Get<NetworkData::Service::Manager>().FindPreferredDnsSrpAnycastInfo(anycastInfo) == kErrorNone)
|
||||
{
|
||||
numServers++;
|
||||
|
||||
// Choose a server randomly (with uniform distribution) from
|
||||
// the list of servers. As we iterate through server entries,
|
||||
// with probability `1/numServers`, we choose to switch the
|
||||
// current selected server with the new entry. This approach
|
||||
// results in a uniform/same probability of selection among
|
||||
// all server entries.
|
||||
|
||||
if ((numServers == 1) || (Random::NonCrypto::GetUint16InRange(0, numServers) == 0))
|
||||
if (IsRunning() && mAutoStartIsUsingAnycastAddress && (mServerSequenceNumber == anycastInfo.mSequenceNumber) &&
|
||||
(GetServerAddress().GetAddress() == anycastInfo.mAnycastAddress))
|
||||
{
|
||||
selectedServer = server;
|
||||
// Client is already using the same anycast address.
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (IsRunning() && mAutoStartDidSelectServer && (GetServerAddress() == server.mSockAddr))
|
||||
otLogInfoSrp("[client] Found anycast server %d", anycastInfo.mSequenceNumber);
|
||||
|
||||
serverSockAddr.SetAddress(anycastInfo.mAnycastAddress);
|
||||
serverSockAddr.SetPort(kAnycastServerPort);
|
||||
mServerSequenceNumber = anycastInfo.mSequenceNumber;
|
||||
serverIsAnycast = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t numServers = 0;
|
||||
NetworkData::Service::DnsSrpUnicast::Info unicastInfo;
|
||||
NetworkData::Service::Manager::Iterator iterator;
|
||||
|
||||
while (Get<NetworkData::Service::Manager>().GetNextDnsSrpUnicastInfo(iterator, unicastInfo) == kErrorNone)
|
||||
{
|
||||
ExitNow();
|
||||
if (IsRunning() && !mAutoStartIsUsingAnycastAddress && (GetServerAddress() == unicastInfo.mSockAddr))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
numServers++;
|
||||
|
||||
// Choose a server randomly (with uniform distribution) from
|
||||
// the list of servers. As we iterate through server entries,
|
||||
// with probability `1/numServers`, we choose to switch the
|
||||
// current selected server with the new entry. This approach
|
||||
// results in a uniform/same probability of selection among
|
||||
// all server entries.
|
||||
|
||||
if ((numServers == 1) || (Random::NonCrypto::GetUint16InRange(0, numServers) == 0))
|
||||
{
|
||||
serverSockAddr = unicastInfo.mSockAddr;
|
||||
serverIsAnycast = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsRunning())
|
||||
{
|
||||
otLogInfoSrp("[client] Server %s is no longer present in net data", GetServerAddress().ToString().AsCString());
|
||||
Stop(kRequesterAuto);
|
||||
}
|
||||
|
||||
VerifyOrExit(numServers > 0);
|
||||
IgnoreError(Start(selectedServer.mSockAddr, kRequesterAuto));
|
||||
VerifyOrExit(!serverSockAddr.GetAddress().IsUnspecified());
|
||||
|
||||
mAutoStartIsUsingAnycastAddress = serverIsAnycast;
|
||||
IgnoreError(Start(serverSockAddr, kRequesterAuto));
|
||||
|
||||
exit:
|
||||
return;
|
||||
|
||||
@@ -710,6 +710,11 @@ private:
|
||||
kAutoStartDefaultMode = OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_DEFAULT_MODE,
|
||||
};
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
kAnycastServerPort = 53, // Port number to use when server is discovered using "network data anycast service".
|
||||
};
|
||||
|
||||
// This enumeration type is used by the private `Start()` and
|
||||
// `Stop()` methods to indicate whether it is being requested by the
|
||||
// user or by the auto-start feature.
|
||||
@@ -794,6 +799,7 @@ private:
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
bool mAutoStartModeEnabled : 1;
|
||||
bool mAutoStartDidSelectServer : 1;
|
||||
bool mAutoStartIsUsingAnycastAddress : 1;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
bool mServiceKeyRecordEnabled : 1;
|
||||
@@ -815,6 +821,7 @@ private:
|
||||
#if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
|
||||
AutoStartCallback mAutoStartCallback;
|
||||
void * mAutoStartContext;
|
||||
uint8_t mServerSequenceNumber;
|
||||
#endif
|
||||
|
||||
const char * mDomainName;
|
||||
|
||||
@@ -506,18 +506,17 @@ exit:
|
||||
|
||||
Error Server::PublishServerData(void)
|
||||
{
|
||||
NetworkData::Service::SrpServer::ServerData serverData;
|
||||
NetworkData::Service::DnsSrpUnicast::ServerData serverData(Get<Mle::Mle>().GetMeshLocal64(),
|
||||
mSocket.GetSockName().GetPort());
|
||||
|
||||
OT_ASSERT(mSocket.IsBound());
|
||||
|
||||
serverData.SetPort(mSocket.GetSockName().GetPort());
|
||||
|
||||
return Get<NetworkData::Service::Manager>().Add<NetworkData::Service::SrpServer>(serverData);
|
||||
return Get<NetworkData::Service::Manager>().Add<NetworkData::Service::DnsSrpUnicast>(serverData);
|
||||
}
|
||||
|
||||
void Server::UnpublishServerData(void)
|
||||
{
|
||||
Error error = Get<NetworkData::Service::Manager>().Remove<NetworkData::Service::SrpServer>();
|
||||
Error error = Get<NetworkData::Service::Manager>().Remove<NetworkData::Service::DnsSrpUnicast>();
|
||||
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
|
||||
@@ -43,18 +43,27 @@ namespace ot {
|
||||
namespace NetworkData {
|
||||
namespace Service {
|
||||
|
||||
// Definitions of static const class member variables to allow ODR-use
|
||||
// (One Definition Rule), e.g., to get address of `kServiceData`.
|
||||
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
const uint8_t BackboneRouter::kServiceData;
|
||||
#endif
|
||||
const uint8_t DnsSrpUnicast::kServiceData;
|
||||
|
||||
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
|
||||
Error Manager::AddService(uint8_t aServiceNumber,
|
||||
Error Manager::AddService(const void *aServiceData,
|
||||
uint8_t aServiceDataLength,
|
||||
bool aServerStable,
|
||||
const void *aServerData,
|
||||
uint8_t aServerDataLength)
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = Get<Local>().AddService(kThreadEnterpriseNumber, &aServiceNumber, sizeof(aServiceNumber),
|
||||
aServerStable, reinterpret_cast<const uint8_t *>(aServerData),
|
||||
aServerDataLength));
|
||||
SuccessOrExit(error = Get<Local>().AddService(
|
||||
kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData), aServiceDataLength,
|
||||
aServerStable, reinterpret_cast<const uint8_t *>(aServerData), aServerDataLength));
|
||||
|
||||
Get<Notifier>().HandleServerDataUpdated();
|
||||
|
||||
@@ -62,11 +71,12 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Manager::RemoveService(uint8_t aServiceNumber)
|
||||
Error Manager::RemoveService(const void *aServiceData, uint8_t aServiceDataLength)
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = Get<Local>().RemoveService(kThreadEnterpriseNumber, &aServiceNumber, sizeof(aServiceNumber)));
|
||||
SuccessOrExit(error = Get<Local>().RemoveService(
|
||||
kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData), aServiceDataLength));
|
||||
Get<Notifier>().HandleServerDataUpdated();
|
||||
|
||||
exit:
|
||||
@@ -75,26 +85,27 @@ exit:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
|
||||
Error Manager::GetServiceId(uint8_t aServiceNumber, bool aServerStable, uint8_t &aServiceId) const
|
||||
Error Manager::GetServiceId(const void *aServiceData,
|
||||
uint8_t aServiceDataLength,
|
||||
bool aServerStable,
|
||||
uint8_t & aServiceId) const
|
||||
{
|
||||
return Get<Leader>().GetServiceId(kThreadEnterpriseNumber, &aServiceNumber, sizeof(aServiceNumber), aServerStable,
|
||||
aServiceId);
|
||||
return Get<Leader>().GetServiceId(kThreadEnterpriseNumber, reinterpret_cast<const uint8_t *>(aServiceData),
|
||||
aServiceDataLength, aServerStable, aServiceId);
|
||||
}
|
||||
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
void Manager::GetBackboneRouterPrimary(ot::BackboneRouter::BackboneRouterConfig &aConfig) const
|
||||
{
|
||||
const uint8_t serviceData = BackboneRouter::kServiceNumber;
|
||||
const ServerTlv * rvalServerTlv = nullptr;
|
||||
const BackboneRouter::ServerData *rvalServerData = nullptr;
|
||||
Iterator iterator;
|
||||
|
||||
aConfig.mServer16 = Mac::kShortAddrInvalid;
|
||||
|
||||
iterator.mServiceTlv = Get<Leader>().FindService(kThreadEnterpriseNumber, &serviceData, sizeof(serviceData));
|
||||
|
||||
VerifyOrExit(iterator.mServiceTlv != nullptr);
|
||||
iterator.mServiceTlv = Get<Leader>().FindService(kThreadEnterpriseNumber, &BackboneRouter::kServiceData,
|
||||
sizeof(BackboneRouter::kServiceData));
|
||||
|
||||
while (IterateToNextServer(iterator) == kErrorNone)
|
||||
{
|
||||
@@ -132,38 +143,106 @@ exit:
|
||||
|
||||
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
Error Manager::GetNextSrpServerInfo(Iterator &aIterator, SrpServer::Info &aInfo) const
|
||||
Error Manager::GetNextDnsSrpAnycastInfo(Iterator &aIterator, DnsSrpAnycast::Info &aInfo) const
|
||||
{
|
||||
Error error = kErrorNotFound;
|
||||
Error error = kErrorNone;
|
||||
uint8_t serviceData = DnsSrpAnycast::kServiceNumber;
|
||||
const ServiceTlv *tlv = aIterator.mServiceTlv;
|
||||
|
||||
if (aIterator.mServiceTlv == nullptr)
|
||||
do
|
||||
{
|
||||
const uint8_t serviceData = SrpServer::kServiceNumber;
|
||||
tlv = Get<Leader>().FindNextMatchingService(tlv, kThreadEnterpriseNumber, &serviceData, sizeof(serviceData));
|
||||
VerifyOrExit(tlv != nullptr, error = kErrorNotFound);
|
||||
|
||||
aIterator.mServiceTlv = Get<Leader>().FindService(kThreadEnterpriseNumber, &serviceData, sizeof(serviceData));
|
||||
VerifyOrExit(aIterator.mServiceTlv != nullptr);
|
||||
}
|
||||
else
|
||||
} while (tlv->GetServiceDataLength() < sizeof(DnsSrpAnycast::ServiceData));
|
||||
|
||||
aInfo.mAnycastAddress.SetToAnycastLocator(Get<Mle::Mle>().GetMeshLocalPrefix(),
|
||||
Mle::Mle::ServiceAlocFromId(tlv->GetServiceId()));
|
||||
aInfo.mSequenceNumber =
|
||||
reinterpret_cast<const DnsSrpAnycast::ServiceData *>(tlv->GetServiceData())->GetSequenceNumber();
|
||||
|
||||
aIterator.mServiceTlv = tlv;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Manager::FindPreferredDnsSrpAnycastInfo(DnsSrpAnycast::Info &aInfo) const
|
||||
{
|
||||
Iterator iterator;
|
||||
DnsSrpAnycast::Info info;
|
||||
bool found = false;
|
||||
|
||||
while (GetNextDnsSrpAnycastInfo(iterator, info) == kErrorNone)
|
||||
{
|
||||
VerifyOrExit(aIterator.mServerSubTlv != nullptr);
|
||||
}
|
||||
|
||||
while ((error = IterateToNextServer(aIterator)) == kErrorNone)
|
||||
{
|
||||
const SrpServer::ServerData *serverData;
|
||||
|
||||
if (aIterator.mServerSubTlv->GetServerDataLength() < sizeof(SrpServer::ServerData))
|
||||
if (!found || info.IsSequenceNumberAheadOf(aInfo))
|
||||
{
|
||||
continue;
|
||||
aInfo = info;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found ? kErrorNone : kErrorNotFound;
|
||||
}
|
||||
|
||||
Error Manager::GetNextDnsSrpUnicastInfo(Iterator &aIterator, DnsSrpUnicast::Info &aInfo) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Process Server sub-TLVs in the current Service TLV.
|
||||
|
||||
while (IterateToNextServer(aIterator) == kErrorNone)
|
||||
{
|
||||
// Server sub-TLV can contain address and port info
|
||||
// (then we parse and return the info), or it can be
|
||||
// empty (then we skip over it).
|
||||
|
||||
if (aIterator.mServerSubTlv->GetServerDataLength() >= sizeof(DnsSrpUnicast::ServerData))
|
||||
{
|
||||
const DnsSrpUnicast::ServerData *serverData =
|
||||
reinterpret_cast<const DnsSrpUnicast::ServerData *>(aIterator.mServerSubTlv->GetServerData());
|
||||
|
||||
aInfo.mSockAddr.SetAddress(serverData->GetAddress());
|
||||
aInfo.mSockAddr.SetPort(serverData->GetPort());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (aIterator.mServerSubTlv->GetServerDataLength() == sizeof(uint16_t))
|
||||
{
|
||||
// Handle the case where the server TLV data only
|
||||
// contains a port number and use the RLOC as the
|
||||
// IPv6 address.
|
||||
aInfo.mSockAddr.GetAddress().SetToRoutingLocator(Get<Mle::Mle>().GetMeshLocalPrefix(),
|
||||
aIterator.mServerSubTlv->GetServer16());
|
||||
aInfo.mSockAddr.SetPort(Encoding::BigEndian::ReadUint16(aIterator.mServerSubTlv->GetServerData()));
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
serverData = reinterpret_cast<const SrpServer::ServerData *>(aIterator.mServerSubTlv->GetServerData());
|
||||
// Find the next matching Service TLV.
|
||||
|
||||
aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16();
|
||||
aInfo.mSockAddr.GetAddress().SetToRoutingLocator(Get<Mle::Mle>().GetMeshLocalPrefix(), aInfo.mRloc16);
|
||||
aInfo.mSockAddr.SetPort(serverData->GetPort());
|
||||
aIterator.mServiceTlv =
|
||||
Get<Leader>().FindNextMatchingService(aIterator.mServiceTlv, kThreadEnterpriseNumber,
|
||||
&DnsSrpUnicast::kServiceData, sizeof(DnsSrpUnicast::kServiceData));
|
||||
|
||||
break;
|
||||
VerifyOrExit(aIterator.mServiceTlv != nullptr, error = kErrorNotFound);
|
||||
|
||||
if (aIterator.mServiceTlv->GetServiceDataLength() >= sizeof(DnsSrpUnicast::ServiceData))
|
||||
{
|
||||
// The Service TLV data contains the address and port info.
|
||||
|
||||
const DnsSrpUnicast::ServiceData *serviceData;
|
||||
|
||||
serviceData = reinterpret_cast<const DnsSrpUnicast::ServiceData *>(aIterator.mServiceTlv->GetServiceData());
|
||||
aInfo.mSockAddr.SetAddress(serviceData->GetAddress());
|
||||
aInfo.mSockAddr.SetPort(serviceData->GetPort());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Go back to the start of `while (true)` loop to
|
||||
// process the Server sub-TLVs in the new Service TLV.
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -172,13 +251,22 @@ exit:
|
||||
|
||||
Error Manager::IterateToNextServer(Iterator &aIterator) const
|
||||
{
|
||||
const NetworkDataTlv *start;
|
||||
Error error = kErrorNotFound;
|
||||
|
||||
start =
|
||||
(aIterator.mServerSubTlv != nullptr) ? aIterator.mServerSubTlv->GetNext() : aIterator.mServiceTlv->GetSubTlvs();
|
||||
aIterator.mServerSubTlv = NetworkData::FindTlv<ServerTlv>(start, aIterator.mServiceTlv->GetNext());
|
||||
VerifyOrExit(aIterator.mServiceTlv != nullptr);
|
||||
|
||||
return (aIterator.mServerSubTlv != nullptr) ? kErrorNone : kErrorNotFound;
|
||||
aIterator.mServerSubTlv = NetworkData::FindTlv<ServerTlv>(
|
||||
/* aStart */ (aIterator.mServerSubTlv != nullptr) ? aIterator.mServerSubTlv->GetNext()
|
||||
: aIterator.mServiceTlv->GetSubTlvs(),
|
||||
/* aEnd */ aIterator.mServiceTlv->GetNext());
|
||||
|
||||
if (aIterator.mServerSubTlv != nullptr)
|
||||
{
|
||||
error = kErrorNone;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -66,10 +66,13 @@ enum : uint32_t
|
||||
class BackboneRouter
|
||||
{
|
||||
public:
|
||||
enum : uint8_t
|
||||
{
|
||||
kServiceNumber = 0x01, ///< Backbone Router service data number (THREAD_SERVICE_DATA_BBR).
|
||||
};
|
||||
/**
|
||||
* This constant variable represents the Backbone Router service data.
|
||||
*
|
||||
* The service data contains only the service number (THREAD_SERVICE_DATA_BBR) as a single byte.
|
||||
*
|
||||
*/
|
||||
static const uint8_t kServiceData = 0x01;
|
||||
|
||||
/**
|
||||
* This class implements the generation and parsing of "Backbone Router Service" server data.
|
||||
@@ -150,63 +153,224 @@ public:
|
||||
#endif // #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
/**
|
||||
* This type implements Thread Network Data "SRP Server Service" server data generation and parsing.
|
||||
* This type implements Thread Network Data "DNS/SRP Service Anycast Address" generation and parsing.
|
||||
*
|
||||
*/
|
||||
class SrpServer
|
||||
class DnsSrpAnycast
|
||||
{
|
||||
public:
|
||||
enum : uint8_t
|
||||
{
|
||||
kServiceNumber = OPENTHREAD_CONFIG_SRP_SERVER_SERVICE_NUMBER, ///< SRP Sever Service number
|
||||
kServiceNumber = 0x5c, ///< The service number of a `DnsSrpAnycast` entry.
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure represents information about an SRP server (from "SRP Server Service" Server entries).
|
||||
* This structure represents information about an DNS/SRP server parsed from related Network Data service entries.
|
||||
*
|
||||
*/
|
||||
struct Info
|
||||
{
|
||||
Ip6::SockAddr mSockAddr; ///< The SRP server address (IPv6 address and port number).
|
||||
uint16_t mRloc16; ///< The RLOC16 of SRP server.
|
||||
/**
|
||||
* This method indicates whether or not the sequence number from the current `Info` is ahead of (more recent
|
||||
* than) the sequence number from another `Info`.
|
||||
*
|
||||
* The sequence numbers comparison follows the Serial Number Arithmetic logic from RFC-1982. It is semantically
|
||||
* equivalent to `GetSequenceNumber() > aOther.GetSequenceNumber()` while handling roll-over of the `uint8_t`
|
||||
* values.
|
||||
*
|
||||
* @param[in] aOther The other `Info` to compare with.
|
||||
*
|
||||
* @retval TRUE The `Info` is ahead of @p aOther.
|
||||
* @retval FALSE The `Info` is not ahead of @p aOther.
|
||||
*
|
||||
*/
|
||||
bool IsSequenceNumberAheadOf(const Info &aOther) const
|
||||
{
|
||||
return (((aOther.mSequenceNumber - mSequenceNumber) & (1U << 7)) != 0);
|
||||
}
|
||||
|
||||
Ip6::Address mAnycastAddress; ///< The anycast address associated with the DNS/SRP servers.
|
||||
uint8_t mSequenceNumber; ///< Sequence number used to notify SRP client if they need to re-register.
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements generation and parsing of "SRP Server Service" server data.
|
||||
* This class represents the "DNS/SRP Service (Anycast)" service data.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ServiceData
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the `ServiceData` object.
|
||||
*
|
||||
* @param[in] aSequenceNumber The sequence number of "DNS/SRP server" service.
|
||||
*
|
||||
*/
|
||||
explicit ServiceData(uint8_t aSequenceNumber)
|
||||
: mServiceNumber(kServiceNumber)
|
||||
, mSequenceNumber(aSequenceNumber)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(mServiceNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the length (in bytes) of service data.
|
||||
*
|
||||
* @returns The data length in bytes.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLength(void) const { return sizeof(ServiceData); }
|
||||
|
||||
/**
|
||||
* This method returns the sequence number.
|
||||
*
|
||||
* @returns The sequence number.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSequenceNumber(void) const { return mSequenceNumber; }
|
||||
|
||||
private:
|
||||
uint8_t mServiceNumber;
|
||||
uint8_t mSequenceNumber;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
DnsSrpAnycast(void) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* This type implements Thread Network Data DNS/SRP Service (Unicast Address) generation and parsing.
|
||||
*
|
||||
*/
|
||||
class DnsSrpUnicast
|
||||
{
|
||||
public:
|
||||
enum : uint8_t
|
||||
{
|
||||
kServiceNumber = 0x5d, ///< The service number of `DnsSrpUnicast` entry.
|
||||
};
|
||||
|
||||
/**
|
||||
* This constant variable represents the short version of service data.
|
||||
*
|
||||
* The short version of service data contains only service number as a single byte.
|
||||
*
|
||||
*/
|
||||
static const uint8_t kServiceData = kServiceNumber;
|
||||
|
||||
/**
|
||||
* This structure represents information about an DNS/SRP server parsed from related Network Data service entries.
|
||||
*
|
||||
*/
|
||||
struct Info
|
||||
{
|
||||
Ip6::SockAddr mSockAddr; ///< The socket address (IPv6 address and port) of the DNS/SRP server.
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents long version of "DNS/SRP Service (Unicast)" service data.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ServiceData
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the `ServiceData` object.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address of DNS/SRP server.
|
||||
* @param[in] aPort The port number of DNS/SRP server.
|
||||
*
|
||||
*/
|
||||
explicit ServiceData(const Ip6::Address &aAddress, uint16_t aPort)
|
||||
: mServiceNumber(kServiceNumber)
|
||||
, mAddress(aAddress)
|
||||
, mPort(HostSwap16(aPort))
|
||||
{
|
||||
OT_UNUSED_VARIABLE(mServiceNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the length (in bytes) of service data.
|
||||
*
|
||||
* @returns The data length in bytes.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLength(void) const { return sizeof(ServiceData); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv6 address.
|
||||
*
|
||||
* @returns The IPv6 address
|
||||
*
|
||||
*/
|
||||
const Ip6::Address &GetAddress(void) const { return mAddress; }
|
||||
|
||||
/**
|
||||
* This method returns the port number.
|
||||
*
|
||||
* @returns The port number.
|
||||
*
|
||||
*/
|
||||
uint16_t GetPort(void) const { return HostSwap16(mPort); }
|
||||
|
||||
private:
|
||||
uint8_t mServiceNumber;
|
||||
Ip6::Address mAddress;
|
||||
uint16_t mPort;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class represents long version of "DNS/SRP Service (Unicast)" server data.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ServerData
|
||||
{
|
||||
public:
|
||||
/** This method returns the length (in bytes) of server data.
|
||||
/**
|
||||
* This constructor initializes the `ServerData` object.
|
||||
*
|
||||
* @returns The server data length in bytes.
|
||||
* @param[in] aAddress The IPv6 address of DNS/SRP server.
|
||||
* @param[in] aPort The port number of DNS/SRP server.
|
||||
*
|
||||
*/
|
||||
ServerData(const Ip6::Address &aAddress, uint16_t aPort)
|
||||
: mAddress(aAddress)
|
||||
, mPort(HostSwap16(aPort))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the length (in bytes) of server data.
|
||||
*
|
||||
* @returns The data length in bytes.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLength(void) const { return sizeof(ServerData); }
|
||||
|
||||
/**
|
||||
* This method returns the port number being used by the SRP server.
|
||||
* This method returns the IPv6 address.
|
||||
*
|
||||
* @return The port number of SPR server.
|
||||
* @returns The IPv6 address
|
||||
*
|
||||
*/
|
||||
const Ip6::Address &GetAddress(void) const { return mAddress; }
|
||||
|
||||
/**
|
||||
* This method returns the port number.
|
||||
*
|
||||
* @returns The port number.
|
||||
*
|
||||
*/
|
||||
uint16_t GetPort(void) const { return HostSwap16(mPort); }
|
||||
|
||||
/**
|
||||
* This method sets the SRP port number in `ServerData`.
|
||||
*
|
||||
* @param[in] aPort The port number of SRP server.
|
||||
*
|
||||
*/
|
||||
void SetPort(uint16_t aPort) { mPort = HostSwap16(aPort); }
|
||||
|
||||
private:
|
||||
uint16_t mPort;
|
||||
Ip6::Address mAddress;
|
||||
uint16_t mPort;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
SrpServer(void) = delete;
|
||||
DnsSrpUnicast(void) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -258,8 +422,11 @@ public:
|
||||
* When successfully added, this method also invokes `Notifier::HandleServerDataUpdated()` to register the changes
|
||||
* in local Network Data with leader.
|
||||
*
|
||||
* This version of `Add<SeviceType>()` is intended for use with a `ServiceType` that has a constant service data
|
||||
* format with a non-empty and potentially non-const server data format (provided as input parameter).
|
||||
*
|
||||
* The template type `ServiceType` has the following requirements:
|
||||
* - It MUST have a constant `ServiceType::kServiceNumber` specifying the service number.
|
||||
* - It MUST have a constant variable `ServiceType::kServiceData` specifying the service data.
|
||||
* - It MUST define nested type `ServiceType::ServerData` representing the server data (and its format).
|
||||
* - The `ServiceType::ServerData` MUST provide `GetLength()` method returning the length of server data.
|
||||
*
|
||||
@@ -275,17 +442,49 @@ public:
|
||||
template <typename ServiceType>
|
||||
Error Add(const typename ServiceType::ServerData &aServerData, bool aServerStable = true)
|
||||
{
|
||||
return AddService(ServiceType::kServiceNumber, aServerStable, &aServerData, aServerData.GetLength());
|
||||
return AddService(&ServiceType::kServiceData, sizeof(ServiceType::kServiceData), aServerStable, &aServerData,
|
||||
aServerData.GetLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removed a Thread Service entry to the local Thread Network Data.
|
||||
* This method adds a Thread Service entry to the local Thread Network Data.
|
||||
*
|
||||
* When successfully added, this method also invokes `Notifier::HandleServerDataUpdated()` to register the changes
|
||||
* in local Network Data with leader.
|
||||
*
|
||||
* This version of `Add<SeviceType>()` is intended for use with a `ServiceType` that has a non-const service data
|
||||
* format (provided as input parameter) with an empty server data.
|
||||
*
|
||||
* The template type `ServiceType` has the following requirements:
|
||||
* - It MUST define nested type `ServiceType::ServiceData` representing the service data (and its format).
|
||||
* - The `ServiceType::ServiceData` MUST provide `GetLength()` method returning the length of service data.
|
||||
*
|
||||
* @tparam ServiceType The service type to be added.
|
||||
*
|
||||
* @param[in] aServiceData The service data.
|
||||
* @param[in] aServerStable The Stable flag value for Server TLV.
|
||||
*
|
||||
* @retval kErrorNone Successfully added the Service entry.
|
||||
* @retval kErrorNoBufs Insufficient space to add the Service entry.
|
||||
*
|
||||
*/
|
||||
template <typename ServiceType>
|
||||
Error Add(const typename ServiceType::ServiceData &aServiceData, bool aServerStable = true)
|
||||
{
|
||||
return AddService(&aServiceData, aServiceData.GetLength(), aServerStable, nullptr, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes a Thread Service entry from the local Thread Network Data.
|
||||
*
|
||||
* When successfully removed, this method also invokes `Notifier::HandleServerDataUpdated()` to register the
|
||||
* changes in local Network Data with leader.
|
||||
*
|
||||
* This version of `Remove<SeviceType>()` is intended for use with a `ServiceType` that has a constant service data
|
||||
* format.
|
||||
*
|
||||
* The template type `ServiceType` has the following requirements:
|
||||
* - It MUST have a constant `ServiceType::kServiceNumber` specifying the service number.
|
||||
* - It MUST have a constant variable `ServiceType::kServiceData` specifying the service data.
|
||||
*
|
||||
* @tparam ServiceType The service type to be removed.
|
||||
*
|
||||
@@ -293,9 +492,36 @@ public:
|
||||
* @retval kErrorNotFound Could not find the Service entry.
|
||||
*
|
||||
*/
|
||||
template <typename ServiceType> Error Remove(void) { return RemoveService(ServiceType::kServiceNumber); }
|
||||
template <typename ServiceType> Error Remove(void)
|
||||
{
|
||||
return RemoveService(&ServiceType::kServiceData, sizeof(ServiceType::kServiceData));
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* This method removes a Thread Service entry from the local Thread Network Data.
|
||||
*
|
||||
* When successfully removed, this method also invokes `Notifier::HandleServerDataUpdated()` to register the
|
||||
* changes in local Network Data with leader.
|
||||
*
|
||||
* This version of `Remove<SeviceType>()` is intended for use with a `ServiceType` that has a non-const service data
|
||||
* format (provided as input parameter).
|
||||
*
|
||||
* The template type `ServiceType` has the following requirements:
|
||||
* - It MUST define nested type `ServiceType::ServiceData` representing the service data (and its format).
|
||||
* - The `ServiceType::ServiceData` MUST provide `GetLength()` method returning the length of service data.
|
||||
*
|
||||
* @tparam ServiceType The service type to be removed.
|
||||
*
|
||||
* @retval kErrorNone Successfully removed the Service entry.
|
||||
* @retval kErrorNotFound Could not find the Service entry.
|
||||
*
|
||||
*/
|
||||
template <typename ServiceType> Error Remove(const typename ServiceType::ServiceData &aServiceData)
|
||||
{
|
||||
return RemoveService(&aServiceData, aServiceData.GetLength());
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
|
||||
/**
|
||||
* This method gets the Service ID for the specified service from Thread Network Data.
|
||||
@@ -314,7 +540,7 @@ public:
|
||||
*/
|
||||
template <typename ServiceType> Error GetServiceId(bool aServerStable, uint8_t &aServiceId) const
|
||||
{
|
||||
return GetServiceId(ServiceType::kServiceNumber, aServerStable, aServiceId);
|
||||
return GetServiceId(&ServiceType::kServiceData, sizeof(ServiceType::kServiceData), aServerStable, aServiceId);
|
||||
}
|
||||
|
||||
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
@@ -328,27 +554,64 @@ public:
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method gets the next SRP server info from the Thread Network Data "SRP Server Service" entries.
|
||||
* This method gets the next DNS/SRP info from the Thread Network Data "DNS/SRP Service Anycast Address" entries.
|
||||
*
|
||||
* This method allows caller to iterate through all server entries for Network Data "SRP Server Service". To get
|
||||
* the first entry @p aIterator should be cleared (e.g., a new instance of `Iterator` or calling `Clear()` method).
|
||||
* To get the first entry, @p aIterator should be cleared (e.g., a new instance of `Iterator` or calling `Clear()`
|
||||
* method).
|
||||
*
|
||||
* @param[inout] aIterator A reference to an iterator.
|
||||
* @param[out] aInfo A reference to `SrpServer::Info` to return the next SRP server info.
|
||||
* @param[out] aInfo A reference to `DnsSrpAnycast::Info` to return the info.
|
||||
*
|
||||
* @retval kErrorNone Successfully got the next SRP server info. @p aInfo and @p aIterator are updated.
|
||||
* @retval kErrorNotFound No more SRP server entries in Network Data.
|
||||
* @retval kErrorNone Successfully got the next info. @p aInfo and @p aIterator are updated.
|
||||
* @retval kErrorNotFound No more matching entries in the Network Data.
|
||||
*
|
||||
*/
|
||||
Error GetNextSrpServerInfo(Iterator &aIterator, SrpServer::Info &aInfo) const;
|
||||
Error GetNextDnsSrpAnycastInfo(Iterator &aIterator, DnsSrpAnycast::Info &aInfo) const;
|
||||
|
||||
/**
|
||||
* This method finds the preferred DNS/SRP info among all the Thread Network Data "DNS/SRP Service Anycast Address"
|
||||
* entries.
|
||||
*
|
||||
* The preferred entry is determined based on the sequence number value where a larger value (in the sense
|
||||
* specified by Serial Number Arithmetic logic in RFC-1982) is considered more recent and therefore preferred.
|
||||
*
|
||||
* @param[out] aInfo A reference to `DnsSrpAnycast::Info` to return the info.
|
||||
*
|
||||
* @retval kErrorNone Successfully found the preferred info. @p aInfo is updated.
|
||||
* @retval kErrorNotFound No "DNS/SRP Service Anycast" entry in Network Data.
|
||||
*
|
||||
*/
|
||||
Error FindPreferredDnsSrpAnycastInfo(DnsSrpAnycast::Info &aInfo) const;
|
||||
|
||||
/**
|
||||
* This method gets the next DNS/SRP info from the Thread Network Data "DNS/SRP Service Unicast Address" entries.
|
||||
*
|
||||
* To get the first entry @p aIterator should be cleared (e.g., a new instance of `Iterator` or calling `Clear()`
|
||||
* method).
|
||||
*
|
||||
* @param[inout] aIterator A reference to an iterator.
|
||||
* @param[out] aInfo A reference to `DnsSrpUnicast::Info` to return the info.
|
||||
*
|
||||
* @retval kErrorNone Successfully got the next info. @p aInfo and @p aIterator are updated.
|
||||
* @retval kErrorNotFound No more matching entries in the Network Data.
|
||||
*
|
||||
*/
|
||||
Error GetNextDnsSrpUnicastInfo(Iterator &aIterator, DnsSrpUnicast::Info &aInfo) const;
|
||||
|
||||
private:
|
||||
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
Error AddService(uint8_t aServiceNumber, bool aServerStable, const void *aServerData, uint8_t aServerDataLength);
|
||||
Error RemoveService(uint8_t aServiceNumber);
|
||||
Error AddService(const void *aServiceData,
|
||||
uint8_t aServiceDataLength,
|
||||
bool aServerStable,
|
||||
const void *aServerData,
|
||||
uint8_t aServerDataLength);
|
||||
Error RemoveService(const void *aServiceData, uint8_t aServiceDataLength);
|
||||
#endif
|
||||
|
||||
Error GetServiceId(uint8_t aServiceNumber, bool aServerStable, uint8_t &aServiceId) const;
|
||||
Error GetServiceId(const void *aServiceData,
|
||||
uint8_t aServiceDataLength,
|
||||
bool aServerStable,
|
||||
uint8_t & aServiceId) const;
|
||||
Error IterateToNextServer(Iterator &aIterator) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -931,8 +931,9 @@ class NodeImpl:
|
||||
# TODO: for now, we are using 0xfd as the SRP service data.
|
||||
# May use a dedicated bit flag for SRP server.
|
||||
if int(service[1], 16) == 0x5d:
|
||||
# The SRP server data are 2-bytes UDP port number.
|
||||
return int(service[2], 16)
|
||||
# The SRP server data contains IPv6 address (16 bytes)
|
||||
# followed by UDP port number.
|
||||
return int(service[2][2 * 16:], 16)
|
||||
|
||||
def srp_client_start(self, server_address, server_port):
|
||||
self.send_command(f'srp client start {server_address} {server_port}')
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "thread/network_data_leader.hpp"
|
||||
#include "thread/network_data_local.hpp"
|
||||
#include "thread/network_data_service.hpp"
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.hpp"
|
||||
@@ -312,6 +314,140 @@ void TestNetworkDataFindNextService(void)
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
|
||||
void TestNetworkDataDsnSrpServices(void)
|
||||
{
|
||||
class TestLeader : public Leader
|
||||
{
|
||||
public:
|
||||
void Populate(const uint8_t *aTlvs, uint8_t aTlvsLength)
|
||||
{
|
||||
memcpy(mTlvs, aTlvs, aTlvsLength);
|
||||
mLength = aTlvsLength;
|
||||
}
|
||||
};
|
||||
|
||||
ot::Instance *instance;
|
||||
|
||||
printf("\n\n-------------------------------------------------");
|
||||
printf("\nTestNetworkDataDsnSrpServices()\n");
|
||||
|
||||
instance = testInitInstance();
|
||||
VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
|
||||
|
||||
{
|
||||
struct AnycastEntry
|
||||
{
|
||||
uint16_t mAloc16;
|
||||
uint8_t mSequenceNumber;
|
||||
|
||||
bool Matches(Service::DnsSrpAnycast::Info aInfo) const
|
||||
{
|
||||
VerifyOrQuit(aInfo.mAnycastAddress.GetIid().IsAnycastServiceLocator(), "Anycast address is invalid");
|
||||
|
||||
return (aInfo.mAnycastAddress.GetIid().GetLocator() == mAloc16) &&
|
||||
(aInfo.mSequenceNumber == mSequenceNumber);
|
||||
}
|
||||
};
|
||||
|
||||
struct UnicastEntry
|
||||
{
|
||||
const char *mAddress;
|
||||
uint16_t mPort;
|
||||
|
||||
bool Matches(Service::DnsSrpUnicast::Info aInfo) const
|
||||
{
|
||||
Ip6::SockAddr sockAddr;
|
||||
|
||||
SuccessOrQuit(sockAddr.GetAddress().FromString(mAddress), "Ip6::Address::FromString() failed");
|
||||
sockAddr.SetPort(mPort);
|
||||
|
||||
return (aInfo.mSockAddr == sockAddr);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t kNetworkData[] = {
|
||||
0x0b, 0x08, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x28, 0x00, 0x0b, 0x08, 0x81, 0x02, 0x5c, 0xff, 0x0d, 0x02,
|
||||
0x6c, 0x00, 0x0b, 0x09, 0x82, 0x02, 0x5c, 0x03, 0x0d, 0x03, 0x4c, 0x00, 0xaa, 0x0b, 0x35, 0x83, 0x13, 0x5d,
|
||||
0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00, 0x2d, 0x0e, 0xc6, 0x27, 0x55, 0x56, 0x18, 0xd9, 0x12, 0x34,
|
||||
0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x6c, 0x00, 0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11,
|
||||
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xab, 0xcd, 0x0d, 0x04, 0x28, 0x00, 0x56, 0x78, 0x0b, 0x23, 0x84, 0x01,
|
||||
0x5d, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x4c, 0x00, 0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde,
|
||||
0xf0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0x00, 0x0e, 0x0d, 0x04, 0x6c, 0x00, 0xcd, 0x12,
|
||||
};
|
||||
|
||||
const AnycastEntry kAnycastEntries[] = {
|
||||
{0xfc10, 0x02},
|
||||
{0xfc11, 0xff},
|
||||
{0xfc12, 0x03},
|
||||
};
|
||||
|
||||
const UnicastEntry kUnicastEntries[] = {
|
||||
{"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234}, {"fd00:aabb:ccdd:eeff:11:2233:4455:6677", 0xabcd},
|
||||
{"fdde:ad00:beef:0:0:ff:fe00:2800", 0x5678}, {"fd00:1234:5678:9abc:def0:123:4567:89ab", 0x0e},
|
||||
{"fdde:ad00:beef:0:0:ff:fe00:6c00", 0xcd12},
|
||||
};
|
||||
|
||||
const uint8_t kPreferredAnycastEntryIndex = 2;
|
||||
|
||||
Service::Manager & manager = instance->Get<Service::Manager>();
|
||||
Service::Manager::Iterator iterator;
|
||||
Service::DnsSrpAnycast::Info anycastInfo;
|
||||
Service::DnsSrpUnicast::Info unicastInfo;
|
||||
|
||||
reinterpret_cast<TestLeader &>(instance->Get<Leader>()).Populate(kNetworkData, sizeof(kNetworkData));
|
||||
|
||||
DumpBuffer("netdata", kNetworkData, sizeof(kNetworkData));
|
||||
|
||||
// Verify all the "DNS/SRP Anycast Service" entries in Network Data
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nDNS/SRP Anycast Service entries\n");
|
||||
|
||||
for (const AnycastEntry &entry : kAnycastEntries)
|
||||
{
|
||||
SuccessOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo), "GetNextDnsSrpAnycastInfo() failed");
|
||||
|
||||
printf("\nanycastInfo { %s, seq:%d }", anycastInfo.mAnycastAddress.ToString().AsCString(),
|
||||
anycastInfo.mSequenceNumber);
|
||||
|
||||
VerifyOrQuit(entry.Matches(anycastInfo), "GetNextDnsSrpAnycastInfo() returned incorrect info");
|
||||
}
|
||||
|
||||
VerifyOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo) == kErrorNotFound,
|
||||
"GetNextDnsSrpAnycastInfo() returned unexpected extra entry");
|
||||
|
||||
// Find the preferred "DNS/SRP Anycast Service" entries in Network Data
|
||||
|
||||
SuccessOrQuit(manager.FindPreferredDnsSrpAnycastInfo(anycastInfo), "FindPreferredDnsSrpAnycastInfo() failed");
|
||||
|
||||
printf("\n\nPreferred anycastInfo { %s, seq:%d }", anycastInfo.mAnycastAddress.ToString().AsCString(),
|
||||
anycastInfo.mSequenceNumber);
|
||||
|
||||
VerifyOrQuit(kAnycastEntries[kPreferredAnycastEntryIndex].Matches(anycastInfo),
|
||||
"FindPreferredDnsSrpAnycastInfo() returned invalid info");
|
||||
|
||||
printf("\n\n- - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nDNS/SRP Unicast Service entries\n");
|
||||
|
||||
iterator.Clear();
|
||||
|
||||
for (const UnicastEntry &entry : kUnicastEntries)
|
||||
{
|
||||
SuccessOrQuit(manager.GetNextDnsSrpUnicastInfo(iterator, unicastInfo), "GetNextDnsSrpUnicastInfo() failed");
|
||||
printf("\nunicastInfo %s", unicastInfo.mSockAddr.ToString().AsCString());
|
||||
|
||||
VerifyOrQuit(entry.Matches(unicastInfo), "GetNextDnsSrpUnicastInfo() returned incorrect info");
|
||||
}
|
||||
|
||||
VerifyOrQuit(manager.GetNextDnsSrpUnicastInfo(iterator, unicastInfo) == kErrorNotFound,
|
||||
"GetNextDnsSrpUnicastInfo() returned unexpected extra entry");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
|
||||
} // namespace NetworkData
|
||||
} // namespace ot
|
||||
|
||||
@@ -321,6 +457,7 @@ int main(void)
|
||||
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||
ot::NetworkData::TestNetworkDataFindNextService();
|
||||
#endif
|
||||
ot::NetworkData::TestNetworkDataDsnSrpServices();
|
||||
|
||||
printf("\nAll tests passed\n");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user