[nexus] add support for otPlatMdns APIs simulation (#11529)

This commit updates `Nexus` simulation platform to implement and
emulate `otPlatMdns` APIs. This allows Nexus test cases to be
written which require and use the OpenThread's native mDNS.

This commit also enhances `test_border_agent` to validate that the
Border Agent's registered `_meshcop._udp` can be queried and
resolved (using mDNS) from other devices.
This commit is contained in:
Abtin Keshavarzian
2025-05-28 18:03:39 -07:00
committed by GitHub
parent 7cbfb8edc9
commit 0216b59fe1
8 changed files with 448 additions and 42 deletions
+1
View File
@@ -42,6 +42,7 @@ set(COMMON_COMPILE_OPTIONS
add_library(ot-nexus-platform
platform/nexus_alarm.cpp
platform/nexus_core.cpp
platform/nexus_mdns.cpp
platform/nexus_misc.cpp
platform/nexus_node.cpp
platform/nexus_radio.cpp
+18
View File
@@ -100,6 +100,7 @@ void Core::Process(Node &aNode)
otTaskletsProcess(&aNode.GetInstance());
ProcessRadio(aNode);
ProcessMdns(aNode);
if (aNode.mAlarm.ShouldTrigger(mNow))
{
@@ -203,5 +204,22 @@ exit:
return;
}
void Core::ProcessMdns(Node &aNode)
{
Mdns::AddressInfo senderAddress;
aNode.mMdns.GetAddress(senderAddress);
for (Mdns::PendingTx &pendingTx : aNode.mMdns.mPendingTxList)
{
for (Node &rxNode : mNodes)
{
rxNode.mMdns.Receive(rxNode.GetInstance(), pendingTx, senderAddress);
}
}
aNode.mMdns.mPendingTxList.Free();
}
} // namespace Nexus
} // namespace ot
+1
View File
@@ -76,6 +76,7 @@ private:
void Process(Node &aNode);
void ProcessRadio(Node &aNode);
void ProcessMdns(Node &aNode);
static Core *sCore;
+177
View File
@@ -0,0 +1,177 @@
/*
* Copyright (c) 2025, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <openthread/platform/mdns_socket.h>
#include "nexus_core.hpp"
#include "nexus_node.hpp"
namespace ot {
namespace Nexus {
//---------------------------------------------------------------------------------------------------------------------
// otPlatMdns APIs
extern "C" {
otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
{
return AsNode(aInstance).mMdns.SetListeningEnabled(AsCoreType(aInstance), aEnable, aInfraIfIndex);
}
void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
{
AsNode(aInstance).mMdns.SendMulticast(AsCoreType(aMessage), aInfraIfIndex);
}
void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
{
AsNode(aInstance).mMdns.SendUnicast(AsCoreType(aMessage), *aAddress);
}
} // extern "C"
//---------------------------------------------------------------------------------------------------------------------
// Mdns
Mdns::Mdns(void)
: mEnabled(false)
{
Ip6::Address address;
Ip6::InterfaceIdentifier iid;
iid.GenerateRandom();
address.SetToLinkLocalAddress(iid);
SuccessOrQuit(mIfAddresses.PushBack(address));
}
Error Mdns::SetListeningEnabled(Instance &aInstance, bool aEnable, uint32_t aInfraIfIndex)
{
Error error = kErrorNone;
VerifyOrExit(aInfraIfIndex == kInfraIfIndex, error = kErrorFailed);
VerifyOrExit(mEnabled != aEnable);
mEnabled = aEnable;
if (mEnabled)
{
SignalIfAddresses(aInstance);
}
exit:
return error;
}
void Mdns::SendMulticast(Message &aMessage, uint32_t aInfraIfIndex)
{
PendingTx *pendingTx;
if (aInfraIfIndex != kInfraIfIndex)
{
aMessage.Free();
ExitNow();
}
pendingTx = PendingTx::Allocate();
VerifyOrQuit(pendingTx != nullptr);
pendingTx->mMessage.Reset(&aMessage);
pendingTx->mIsUnicast = false;
mPendingTxList.PushAfterTail(*pendingTx);
exit:
return;
}
void Mdns::SendUnicast(Message &aMessage, const AddressInfo &aAddress)
{
PendingTx *pendingTx;
if (aAddress.mInfraIfIndex != kInfraIfIndex)
{
aMessage.Free();
ExitNow();
}
pendingTx = PendingTx::Allocate();
VerifyOrQuit(pendingTx != nullptr);
pendingTx->mMessage.Reset(&aMessage);
pendingTx->mIsUnicast = true;
pendingTx->mAddress = aAddress;
mPendingTxList.PushAfterTail(*pendingTx);
exit:
return;
}
void Mdns::SignalIfAddresses(Instance &aInstance)
{
otPlatMdnsHandleHostAddressRemoveAll(&aInstance, kInfraIfIndex);
for (const Ip6::Address &address : mIfAddresses)
{
otPlatMdnsHandleHostAddressEvent(&aInstance, &address, /* aAdded */ true, kInfraIfIndex);
}
}
void Mdns::Receive(Instance &aInstance, const PendingTx &aPendingTx, const AddressInfo &aSenderAddress)
{
Message *message;
VerifyOrExit(mEnabled);
if (aPendingTx.mIsUnicast)
{
VerifyOrExit(aPendingTx.mAddress.mInfraIfIndex == kInfraIfIndex);
VerifyOrExit(aPendingTx.mAddress.mPort == kUdpPort);
VerifyOrExit(mIfAddresses.Contains(AsCoreType(&aPendingTx.mAddress.mAddress)));
}
message = aPendingTx.mMessage->Clone();
VerifyOrQuit(message != nullptr);
otPlatMdnsHandleReceive(&aInstance, message, aPendingTx.mIsUnicast, &aSenderAddress);
exit:
return;
}
void Mdns::GetAddress(AddressInfo &aAddress) const
{
ClearAllBytes(aAddress);
aAddress.mAddress = mIfAddresses[0];
aAddress.mPort = kUdpPort;
aAddress.mInfraIfIndex = kInfraIfIndex;
}
} // namespace Nexus
} // namespace ot
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2025, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OT_NEXUS_MDNS_HPP_
#define OT_NEXUS_MDNS_HPP_
#include "instance/instance.hpp"
namespace ot {
namespace Nexus {
class Mdns
{
public:
static constexpr uint16_t kUdpPort = 5353;
static constexpr uint32_t kInfraIfIndex = 1;
using AddressInfo = otPlatMdnsAddressInfo;
struct PendingTx : public Heap::Allocatable<PendingTx>, public LinkedListEntry<PendingTx>
{
PendingTx *mNext;
OwnedPtr<Message> mMessage;
bool mIsUnicast;
AddressInfo mAddress;
};
Mdns(void);
Error SetListeningEnabled(Instance &aInstance, bool aEnable, uint32_t aInfraIfIndex);
void SendMulticast(Message &aMessage, uint32_t aInfraIfIndex);
void SendUnicast(Message &aMessage, const AddressInfo &aAddress);
void SignalIfAddresses(Instance &aInstance);
void Receive(Instance &aInstance, const PendingTx &aPendingTx, const AddressInfo &aSenderAddress);
void GetAddress(AddressInfo &aAddress) const;
bool mEnabled;
Heap::Array<Ip6::Address> mIfAddresses;
OwningList<PendingTx> mPendingTxList;
};
} // namespace Nexus
} // namespace ot
#endif // OT_NEXUS_MDNS_HPP_
-30
View File
@@ -104,36 +104,6 @@ exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// otPlatMdns
OT_TOOL_WEAK otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aEnable);
OT_UNUSED_VARIABLE(aInfraIfIndex);
return kErrorNone;
}
OT_TOOL_WEAK void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aInfraIfIndex);
AsCoreType(aMessage).Free();
}
OT_TOOL_WEAK void otPlatMdnsSendUnicast(otInstance *aInstance,
otMessage *aMessage,
const otPlatMdnsAddressInfo *aAddress)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aAddress);
AsCoreType(aMessage).Free();
}
//---------------------------------------------------------------------------------------------------------------------
// Misc
+2
View File
@@ -33,6 +33,7 @@
#include "nexus_alarm.hpp"
#include "nexus_core.hpp"
#include "nexus_mdns.hpp"
#include "nexus_radio.hpp"
#include "nexus_settings.hpp"
#include "nexus_utils.hpp"
@@ -79,6 +80,7 @@ public:
Node *mNext;
Radio mRadio;
Alarm mAlarm;
Mdns mMdns;
Settings mSettings;
bool mPendingTasklet;
+179 -12
View File
@@ -1058,6 +1058,81 @@ void TestBorderAgentTxtDataCallback(void)
//----------------------------------------------------------------------------------------------------------------------
static constexpr uint32_t kInfraIfIndex = 1;
static constexpr uint16_t kMaxEntries = 5;
static constexpr uint16_t kMaxTxtDataSize = 128;
typedef Dns::Name::Buffer DnsName;
struct BrowseOutcome
{
DnsName mServiceInstance;
uint32_t mTtl;
};
struct SrvOutcome
{
DnsName mHostName;
uint16_t mPort;
uint32_t mTtl;
};
struct TxtOutcome
{
uint8_t mTxtData[kMaxTxtDataSize];
uint16_t mTxtDataLength;
uint32_t mTtl;
};
static Array<BrowseOutcome, kMaxEntries> sBrowseOutcomes;
static Array<SrvOutcome, kMaxEntries> sSrvOutcomes;
static Array<TxtOutcome, kMaxEntries> sTxtOutcomes;
void HandleBrowseCallback(otInstance *aInstance, const Dns::Multicast::Core::BrowseResult *aResult)
{
BrowseOutcome *outcome;
VerifyOrQuit(aInstance != nullptr);
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
outcome = sBrowseOutcomes.PushBack();
VerifyOrQuit(outcome != nullptr);
SuccessOrQuit(StringCopy(outcome->mServiceInstance, aResult->mServiceInstance));
outcome->mTtl = aResult->mTtl;
}
void HandleSrvCallback(otInstance *aInstance, const Dns::Multicast::Core::SrvResult *aResult)
{
SrvOutcome *outcome;
VerifyOrQuit(aInstance != nullptr);
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
outcome = sSrvOutcomes.PushBack();
VerifyOrQuit(outcome != nullptr);
SuccessOrQuit(StringCopy(outcome->mHostName, aResult->mHostName));
outcome->mPort = aResult->mPort;
outcome->mTtl = aResult->mTtl;
}
void HandleTxtCallback(otInstance *aInstance, const Dns::Multicast::Core::TxtResult *aResult)
{
TxtOutcome *outcome;
VerifyOrQuit(aInstance != nullptr);
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
outcome = sTxtOutcomes.PushBack();
VerifyOrQuit(outcome != nullptr);
VerifyOrQuit(aResult->mTxtDataLength < kMaxTxtDataSize);
memcpy(outcome->mTxtData, aResult->mTxtData, aResult->mTxtDataLength);
outcome->mTxtDataLength = aResult->mTxtDataLength;
outcome->mTtl = aResult->mTtl;
}
void ValidateRegisteredServiceData(Dns::Multicast::Core::Service &aService, Node &aNode)
{
TxtData txtData;
@@ -1066,33 +1141,43 @@ void ValidateRegisteredServiceData(Dns::Multicast::Core::Service &aService, Node
ValidateMeshCoPTxtData(txtData, aNode);
}
void TestBorderAgentServiceRegisteration(void)
void TestBorderAgentServiceRegistration(void)
{
static const char kDefaultServiceBaseName[] = OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME;
static const char kEphemeralKey[] = "nexus1234";
static const uint8_t kVendorTxtData[] = {8, 'v', 'n', '=', 'n', 'e', 'x', 'u', 's'};
static constexpr uint32_t kUdpPort = 49155;
static constexpr uint32_t kInfraIfIndex = 1;
static constexpr uint32_t kUdpPort = 49155;
Core nexus;
Node &node0 = nexus.CreateNode();
Dns::Multicast::Core::Iterator *iterator;
Dns::Multicast::Core::Service service;
Dns::Multicast::Core::EntryState entryState;
uint16_t txtDataLengthWithNoVendorData;
Core nexus;
Node &node0 = nexus.CreateNode();
Node &node1 = nexus.CreateNode();
Dns::Multicast::Core::Iterator *iterator;
Dns::Multicast::Core::Service service;
Dns::Multicast::Core::EntryState entryState;
Dns::Multicast::Core::Browser browser;
Dns::Multicast::Core::SrvResolver srvResolver;
Dns::Multicast::Core::TxtResolver txtResolver;
TxtData txtData;
uint16_t txtDataLengthWithNoVendorData;
Log("------------------------------------------------------------------------------------------------------");
Log("TestBorderAgentServiceRegisteration");
Log("TestBorderAgentServiceRegistration");
nexus.AdvanceTime(0);
node0.Form();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disable Border Agent function on node1
node1.Get<MeshCoP::BorderAgent>().SetEnabled(false);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enable mDNS
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().IsEnabled());
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
VerifyOrQuit(node1.Get<Dns::Multicast::Core>().IsEnabled());
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1133,7 +1218,52 @@ void TestBorderAgentServiceRegisteration(void)
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Enable ans start ephemeral key");
Log("Validate that the service can be resolved on other nodes");
ClearAllBytes(browser);
browser.mServiceType = "_meshcop._udp";
browser.mInfraIfIndex = kInfraIfIndex;
browser.mCallback = HandleBrowseCallback;
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartBrowser(browser));
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, kDefaultServiceBaseName));
VerifyOrQuit(sBrowseOutcomes[0].mTtl > 0);
ClearAllBytes(srvResolver);
srvResolver.mServiceInstance = sBrowseOutcomes[0].mServiceInstance;
srvResolver.mServiceType = browser.mServiceType;
srvResolver.mInfraIfIndex = kInfraIfIndex;
srvResolver.mCallback = HandleSrvCallback;
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartSrvResolver(srvResolver));
ClearAllBytes(txtResolver);
txtResolver.mServiceInstance = sBrowseOutcomes[0].mServiceInstance;
txtResolver.mServiceType = browser.mServiceType;
txtResolver.mInfraIfIndex = kInfraIfIndex;
txtResolver.mCallback = HandleTxtCallback;
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartTxtResolver(txtResolver));
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
VerifyOrQuit(sSrvOutcomes.GetLength() == 1);
VerifyOrQuit(StringStartsWith(sSrvOutcomes[0].mHostName, "ot"));
VerifyOrQuit(sSrvOutcomes[0].mTtl > 0);
VerifyOrQuit(sSrvOutcomes[0].mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
VerifyOrQuit(sTxtOutcomes.GetLength() == 1);
VerifyOrQuit(sTxtOutcomes[0].mTtl > 0);
txtData.Init(sTxtOutcomes[0].mTxtData, sTxtOutcomes[0].mTxtDataLength);
ValidateMeshCoPTxtData(txtData, node0);
sBrowseOutcomes.Clear();
sSrvOutcomes.Clear();
sTxtOutcomes.Clear();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Enable and start ephemeral key");
node0.Get<EphemeralKeyManager>().SetEnabled(true);
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
@@ -1192,6 +1322,10 @@ void TestBorderAgentServiceRegisteration(void)
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
VerifyOrQuit(sBrowseOutcomes.GetLength() == 0);
VerifyOrQuit(sSrvOutcomes.GetLength() == 0);
VerifyOrQuit(sTxtOutcomes.GetLength() == 0);
Log("Wait for the ephemeral key to expire and validate the registered service is removed");
nexus.AdvanceTime(5 * Time::kOneMinuteInMsec);
@@ -1253,6 +1387,27 @@ void TestBorderAgentServiceRegisteration(void)
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// Check browser/resolver outcome on node1
VerifyOrQuit(sSrvOutcomes.GetLength() == 1);
VerifyOrQuit(sSrvOutcomes[0].mTtl == 0);
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StopSrvResolver(srvResolver));
VerifyOrQuit(sTxtOutcomes.GetLength() == 1);
VerifyOrQuit(sTxtOutcomes[0].mTtl == 0);
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StopTxtResolver(txtResolver));
VerifyOrQuit(sBrowseOutcomes.GetLength() == 2);
VerifyOrQuit(sBrowseOutcomes[0].mTtl == 0);
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, kDefaultServiceBaseName));
VerifyOrQuit(sBrowseOutcomes[1].mTtl > 0);
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[1].mServiceInstance, "OpenThreadAgent"));
sBrowseOutcomes.Clear();
sSrvOutcomes.Clear();
sTxtOutcomes.Clear();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Disable Border Agent and validate that registered service is removed");
@@ -1268,6 +1423,12 @@ void TestBorderAgentServiceRegisteration(void)
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
VerifyOrQuit(sBrowseOutcomes[0].mTtl == 0);
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, "OpenThreadAgent"));
sBrowseOutcomes.Clear();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Re-enable Border Agent and validate that service is registered again");
@@ -1302,6 +1463,12 @@ void TestBorderAgentServiceRegisteration(void)
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
VerifyOrQuit(sBrowseOutcomes[0].mTtl > 0);
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, "OpenThreadAgent"));
sBrowseOutcomes.Clear();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Set vendor TXT data and validate that it is included in the registered mDNS service");
@@ -1381,7 +1548,7 @@ int main(void)
ot::Nexus::TestBorderAgent();
ot::Nexus::TestBorderAgentEphemeralKey();
ot::Nexus::TestBorderAgentTxtDataCallback();
ot::Nexus::TestBorderAgentServiceRegisteration();
ot::Nexus::TestBorderAgentServiceRegistration();
printf("All tests passed\n");
return 0;
}