[border-agent] manage mDNS MeshCoP service registrations (#11455)

This commit updates `BorderAgent` modules to directly manage the
registration of mDNS MeshCoP services. Previously, this was the
responsibility of the platform or higher-level code. This behavior is
enabled using `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE`
configuration option.

When enabled, the `BorderAgent` module itself will register the
`_meshcop._udp` service name with properly formatted TXT data. As the
state changes, the service registration is updated accordingly.

If the ephemeral key feature is enabled and used, the `BorderAgent`
will also manage the registration of the `_meshcop-e._udp` service.

The implementation allows the service instance name to be configured
in different ways. The Thread specification recommends using a
user-friendly name, such as "<VendorName> <ProductName>". The
name can be set using a newly added configuration option, or
alternatively, using a newly added public API for projects where the
name needs to be set at run-time after device initialization.

This commit also updates `test_border_agent`, validating all the
newly added behaviors related to MeshCoP service registrations.
This commit is contained in:
Abtin Keshavarzian
2025-05-08 20:39:54 -07:00
committed by GitHub
parent 65098ebcc1
commit 293b41c808
15 changed files with 634 additions and 10 deletions
+2
View File
@@ -176,6 +176,7 @@ ot_option(OT_BLE_TCAT OPENTHREAD_CONFIG_BLE_TCAT_ENABLE "Ble based thread commis
ot_option(OT_BORDER_AGENT OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE "border agent")
ot_option(OT_BORDER_AGENT_EPSKC OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE "border agent ephemeral PSKc")
ot_option(OT_BORDER_AGENT_ID OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE "create and save border agent ID")
ot_option(OT_BORDER_AGENT_MESHCOP_SERVICE OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE "border agent meshcop service")
ot_option(OT_BORDER_ROUTER OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE "border router")
ot_option(OT_BORDER_ROUTING OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE "border routing")
ot_option(OT_BORDER_ROUTING_DHCP6_PD OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE "dhcpv6 pd support in border routing")
@@ -332,6 +333,7 @@ ot_multi_option(OT_LOG_OUTPUT OT_LOG_OUTPUT_VALUES OPENTHREAD_CONFIG_LOG_OUTPUT
ot_string_option(OT_VENDOR_NAME OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "set the vendor name config")
ot_string_option(OT_VENDOR_MODEL OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL "set the vendor model config")
ot_string_option(OT_VENDOR_SW_VERSION OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION "set the vendor sw version config")
ot_string_option(OT_BORDER_AGENT_SERVICE_NAME OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME "set the border agent service base name")
set(OT_POWER_SUPPLY_VALUES "BATTERY" "EXTERNAL" "EXTERNAL_STABLE" "EXTERNAL_UNSTABLE")
ot_multi_option(OT_POWER_SUPPLY OT_POWER_SUPPLY_VALUES OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY OT_POWER_SUPPLY_ "set the device power supply config")
+36
View File
@@ -35,6 +35,7 @@
#ifndef OPENTHREAD_BORDER_AGENT_H_
#define OPENTHREAD_BORDER_AGENT_H_
#include <openthread/dns.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
@@ -242,6 +243,41 @@ void otBorderAgentSetMeshCoPServiceChangedCallback(otInstance
*/
otError otBorderAgentGetMeshCoPServiceTxtData(otInstance *aInstance, otBorderAgentMeshCoPServiceTxtData *aTxtData);
/**
* Maximum string length of base name used in `otBorderAgentSetMeshCoPServiceBaseName()`.
*
* The full DNS label is constructed by appending the Extended Address of the device (as 16-character hex digits) to
* the given base name.
*/
#define OT_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME_MAX_LENGTH (OT_DNS_MAX_LABEL_SIZE - 17)
/**
* Sets the base name to construct the service instance name used when advertising the mDNS `_meshcop._udp` service by
* the Border Agent.
*
* Requires the `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE` feature.
*
* The name can also be configured using the `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME` configuration
* option (which is the recommended way to specify this name). This API is provided for projects where the name needs
* to be set after device initialization and at run-time.
*
* Per the Thread specification, the service instance should be a user-friendly name identifying the device model or
* product. A recommended format is "<VendorName> <ProductName>".
*
* To construct the full name and ensure name uniqueness, the OpenThread Border Agent module will append the Extended
* Address of the device (as 16-character hex digits) to the given base name.
*
* Note that the same name will be used for the ephemeral key service `_meshcop-e._udp` when the ephemeral key feature
* is enabled and used.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aBaseName The base name to use (MUST not be NULL).
*
* @retval OT_ERROR_NONE The name was set successfully.
* @retval OT_ERROR_INVALID_ARGS The name is too long or invalid.
*/
otError otBorderAgentSetMeshCoPServiceBaseName(otInstance *aInstance, const char *aBaseName);
/**
* Gets the randomly generated Border Agent ID.
*
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (505)
#define OPENTHREAD_API_VERSION (506)
/**
* @addtogroup api-instance
+15
View File
@@ -410,6 +410,21 @@ Active
Done
```
### ba servicebasename \<name\>
Sets the base name to construct the service instance name used when advertising the mDNS `_meshcop._udp` service by the Border Agent.
Requires the `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE` feature.
The name can also be configured using the `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME` configuration option (which is the recommended way to specify this name). This CLI command (and its corresponding API) is provided for projects where the name needs to be set after device initialization and at run-time.
Per the Thread specification, the service instance should be a user-friendly name identifying the device model or product. A recommended format is "<VendorName> <ProductName>". To construct the full name and ensure name uniqueness, the OpenThread Border Agent module will append the Extended Address of the device (as 16-character hex digits) to the given base name. Note that the same name will be used for the ephemeral key service `_meshcop-e._udp` when the ephemeral key feature is enabled and used.
```bash
ba servicebasename OpenThreadBorderAgent
Done
```
### ba sessions
Prints the list of Border Agent's sessions. Information per session:
+16
View File
@@ -502,6 +502,22 @@ template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive");
}
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
/**
* @cli ba servicebasename
* @code
* ba servicebasename OpenThreadBorderAgent
* Done
* @endcode
* @par api_copy
* #otBorderAgentSetMeshCoPServiceBaseName
*/
else if (aArgs[0] == "servicebasename")
{
VerifyOrExit(!aArgs[1].IsEmpty() && aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = otBorderAgentSetMeshCoPServiceBaseName(GetInstancePtr(), aArgs[1].GetCString());
}
#endif
/**
* @cli ba sessions
* @code
+9
View File
@@ -57,6 +57,15 @@ bool otBorderAgentIsActive(otInstance *aInstance)
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().IsRunning();
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
otError otBorderAgentSetMeshCoPServiceBaseName(otInstance *aInstance, const char *aBaseName)
{
AssertPointerIsNotNull(aBaseName);
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().SetServiceBaseName(aBaseName);
}
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
otError otBorderAgentGetId(otInstance *aInstance, otBorderAgentId *aId)
{
+32
View File
@@ -89,6 +89,38 @@
OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
*
* Define to 1 to enable Border Agent to manage registering/updating of the mDNS MeshCoP service(s) on the
* infrastructure link
*
* This includes the ephemeral key service when the `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE` is enabled.
*/
#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
#define OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE \
(OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE || OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE)
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME
*
* Specifies the base name to construct the service instance name used when advertising the mDNS `_meshcop._udp`
* service by the Border Agent.
*
* Applicable when the `OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE` feature is enabled.
*
* The name can also be configured using the `otBorderAgentSetMeshCoPServiceBaseName()` API at run-time.
*
* Per the Thread specification, the service instance should be a user-friendly name identifying the device model or
* product. A recommended format is "<VendorName> <ProductName>".
*
* The name MUST have a length less than or equal to `OT_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME_MAX_LENGTH` (47 chars).
*/
#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME
#define OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME "OpenThread BR (unspecified vendor) "
#endif
/**
* @}
*/
+174 -5
View File
@@ -45,6 +45,11 @@ RegisterLogModule("BorderAgent");
//----------------------------------------------------------------------------------------------------------------------
// `BorderAgent`
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
const char BorderAgent::kServiceType[] = "_meshcop._udp";
const char BorderAgent::kDefaultBaseServiceName[] = OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME;
#endif
BorderAgent::BorderAgent(Instance &aInstance)
: InstanceLocator(aInstance)
, mEnabled(true)
@@ -59,6 +64,14 @@ BorderAgent::BorderAgent(Instance &aInstance)
#endif
{
ClearAllBytes(mCounters);
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
ClearAllBytes(mServiceName);
PostServiceTask();
static_assert(sizeof(kDefaultBaseServiceName) - 1 <= kBaseServiceNameMaxLen,
"OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME is too long");
#endif
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
@@ -111,6 +124,13 @@ void BorderAgent::SetEnabled(bool aEnabled)
LogInfo("%sabling Border Agent", mEnabled ? "En" : "Dis");
UpdateState();
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
if (!mEnabled)
{
UnregisterService();
}
#endif
exit:
return;
}
@@ -365,24 +385,113 @@ exit:
FreeMessageOnError(message, error);
}
void BorderAgent::PostServiceTask(void)
{
VerifyOrExit(mEnabled);
#if !OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
VerifyOrExit(mServiceChangedCallback.IsSet());
#endif
mServiceTask.Post();
exit:
return;
}
void BorderAgent::HandleServiceTask(void)
{
VerifyOrExit(mEnabled);
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
RegisterService();
#endif
mServiceChangedCallback.InvokeIfSet();
exit:
return;
}
void BorderAgent::PostServiceTask(void)
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
Error BorderAgent::SetServiceBaseName(const char *aBaseName)
{
if (mEnabled && mServiceChangedCallback.IsSet())
{
mServiceTask.Post();
}
Error error = kErrorNone;
Dns::Name::LabelBuffer newName;
VerifyOrExit(StringLength(aBaseName, kBaseServiceNameMaxLen + 1) <= kBaseServiceNameMaxLen,
error = kErrorInvalidArgs);
ConstrcutServiceName(aBaseName, newName);
VerifyOrExit(!StringMatch(newName, mServiceName));
UnregisterService();
IgnoreError(StringCopy(mServiceName, newName));
RegisterService();
exit:
return error;
}
const char *BorderAgent::GetServiceName(void)
{
if (IsServiceNameEmpty())
{
ConstrcutServiceName(kDefaultBaseServiceName, mServiceName);
}
return mServiceName;
}
void BorderAgent::ConstrcutServiceName(const char *aBaseName, Dns::Name::LabelBuffer &aNameBuffer)
{
StringWriter writer(aNameBuffer, sizeof(Dns::Name::LabelBuffer));
writer.Append("%.*s%s", kBaseServiceNameMaxLen, aBaseName, Get<Mac::Mac>().GetExtAddress().ToString().AsCString());
}
void BorderAgent::RegisterService(void)
{
ServiceTxtData txtData;
Dnssd::Service service;
VerifyOrExit(Get<Dnssd>().IsReady());
SuccessOrAssert(PrepareServiceTxtData(txtData));
service.Clear();
service.mServiceInstance = GetServiceName();
service.mServiceType = kServiceType;
service.mPort = IsRunning() ? GetUdpPort() : kDummyUdpPort;
service.mTxtData = txtData.mData;
service.mTxtDataLength = txtData.mLength;
Get<Dnssd>().RegisterService(service, /* aRequestId */ 0, /* aCallback */ nullptr);
exit:
return;
}
void BorderAgent::UnregisterService(void)
{
Dnssd::Service service;
VerifyOrExit(Get<Dnssd>().IsReady());
VerifyOrExit(!IsServiceNameEmpty());
service.Clear();
service.mServiceInstance = GetServiceName();
service.mServiceType = kServiceType;
Get<Dnssd>().UnregisterService(service, /* aRequestId */ 0, /* aCallback */ nullptr);
exit:
return;
}
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
Error BorderAgent::PrepareServiceTxtData(ServiceTxtData &aTxtData)
{
Error error = kErrorNone;
@@ -529,6 +638,10 @@ exit:
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
const char BorderAgent::EphemeralKeyManager::kServiceType[] = "_meshcop-e._udp";
#endif
BorderAgent::EphemeralKeyManager::EphemeralKeyManager(Instance &aInstance)
: InstanceLocator(aInstance)
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT
@@ -659,11 +772,20 @@ exit:
void BorderAgent::EphemeralKeyManager::SetState(State aState)
{
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
bool isServiceRegistered = ShouldRegisterService();
#endif
VerifyOrExit(mState != aState);
LogInfo("Ephemeral key - state: %s -> %s", StateToString(mState), StateToString(aState));
mState = aState;
mCallbackTask.Post();
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
VerifyOrExit(isServiceRegistered != ShouldRegisterService());
RegisterOrUnregisterService();
#endif
exit:
return;
}
@@ -761,6 +883,53 @@ void BorderAgent::EphemeralKeyManager::HandleTransportClosed(void)
;
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
bool BorderAgent::EphemeralKeyManager::ShouldRegisterService(void) const
{
bool shouldRegister = false;
switch (mState)
{
case kStateDisabled:
case kStateStopped:
break;
case kStateStarted:
case kStateConnected:
case kStateAccepted:
shouldRegister = true;
break;
}
return shouldRegister;
}
void BorderAgent::EphemeralKeyManager::RegisterOrUnregisterService(void)
{
Dnssd::Service service;
VerifyOrExit(Get<Dnssd>().IsReady());
service.Clear();
service.mServiceInstance = Get<BorderAgent>().GetServiceName();
service.mServiceType = kServiceType;
service.mPort = GetUdpPort();
if (ShouldRegisterService())
{
Get<Dnssd>().RegisterService(service, /* aRequestId */ 0, /* aCallback */ nullptr);
}
else
{
Get<Dnssd>().UnregisterService(service, /* aRequestId */ 0, /* aCallback */ nullptr);
}
exit:
return;
}
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
const char *BorderAgent::EphemeralKeyManager::StateToString(State aState)
{
static const char *const kStateStrings[] = {
+59 -1
View File
@@ -49,11 +49,11 @@
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/owned_ptr.hpp"
#include "common/random.hpp"
#include "common/tasklet.hpp"
#include "meshcop/dataset.hpp"
#include "meshcop/secure_transport.hpp"
#include "net/dns_types.hpp"
#include "net/dnssd.hpp"
#include "net/socket.hpp"
#include "net/udp6.hpp"
#include "thread/tmf.hpp"
@@ -67,10 +67,25 @@ namespace MeshCoP {
#error "Border Agent feature requires `OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE`"
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
#if !(OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE || OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE)
#error "OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE requires either the native mDNS or platform DNS-SD APIs"
#endif
#if !OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
#error "OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE requires OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE"
#endif
#endif
class BorderAgent : public InstanceLocator, private NonCopyable
{
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
friend class ot::BorderRouter::RoutingManager;
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
friend ot::Dnssd;
#endif
friend class ot::Notifier;
friend class Tmf::Agent;
@@ -229,6 +244,19 @@ public:
*/
Error PrepareServiceTxtData(ServiceTxtData &aTxtData);
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
/**
* Sets the base name to construct the service instance name used when advertising the mDNS `_meshcop._udp` service
* by the Border Agent.
*
* @param[in] aBaseName The base name to use (MUST not be NULL).
*
* @retval kErrorNone The name was set successfully.
* @retval kErrorInvalidArgs The name is too long or invalid.
*/
Error SetServiceBaseName(const char *aBaseName);
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
/**
* Manages the ephemeral key use by Border Agent.
@@ -359,6 +387,10 @@ public:
void HandleSessionConnected(void);
void HandleSessionDisconnected(SecureSession::ConnectEvent aEvent);
void HandleCommissionerPetitionAccepted(void);
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
bool ShouldRegisterService(void) const;
void RegisterOrUnregisterService(void);
#endif
// Session or Transport callbacks
static SecureSession *HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo);
@@ -372,6 +404,10 @@ public:
static const char *StopReasonToString(StopReason aReason);
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
static const char kServiceType[];
#endif
using TimeoutTimer = TimerMilliIn<EphemeralKeyManager, &EphemeralKeyManager::HandleTimer>;
using CallbackTask = TaskletIn<EphemeralKeyManager, &EphemeralKeyManager::HandleTask>;
@@ -403,6 +439,11 @@ private:
static constexpr uint16_t kUdpPort = OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT;
static constexpr uint32_t kKeepAliveTimeout = 50 * 1000; // Timeout to reject a commissioner (in msec)
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
static constexpr uint16_t kDummyUdpPort = 49152;
static constexpr uint8_t kBaseServiceNameMaxLen = OT_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME_MAX_LENGTH;
#endif
class CoapDtlsSession : public Coap::SecureSession, public Heap::Allocatable<CoapDtlsSession>
{
friend Heap::Allocatable<CoapDtlsSession>;
@@ -544,8 +585,22 @@ private:
void HandleFavoredOmrPrefixChanged(void) { PostServiceTask(); }
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
const char *GetServiceName(void);
bool IsServiceNameEmpty(void) const { return mServiceName[0] == kNullChar; }
void ConstrcutServiceName(const char *aBaseName, Dns::Name::LabelBuffer &aNameBuffer);
void RegisterService(void);
void UnregisterService(void);
void HandleDnssdPlatformStateChange(void) { PostServiceTask(); }
#endif
using ServiceTask = TaskletIn<BorderAgent, &BorderAgent::HandleServiceTask>;
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
static const char kServiceType[];
static const char kDefaultBaseServiceName[];
#endif
bool mEnabled;
bool mIsRunning;
Dtls::Transport mDtlsTransport;
@@ -557,6 +612,9 @@ private:
ServiceTask mServiceTask;
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
EphemeralKeyManager mEphemeralKeyManager;
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
Dns::Name::LabelBuffer mServiceName;
#endif
Counters mCounters;
};
+4
View File
@@ -526,6 +526,10 @@ void Dnssd::HandleStateChange(void)
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
Get<Dns::ServiceDiscovery::Server>().HandleDnssdPlatformStateChange();
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
Get<MeshCoP::BorderAgent>().HandleDnssdPlatformStateChange();
#endif
}
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
+3 -3
View File
@@ -94,9 +94,9 @@
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 0
#define OPENTHREAD_CONFIG_MLE_MAX_CHILDREN 128
#define OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF 0
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 0
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE 0
#define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 0
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE 1
#define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 1
#define OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE 0
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE OPENTHREAD_FTD
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL "Nexus Simulation"
+30
View File
@@ -104,6 +104,36 @@ 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
+238
View File
@@ -987,6 +987,243 @@ void TestBorderAgentTxtDataCallback(void)
VerifyOrQuit(!(stateBitmap & kFlagEpskcSupported));
}
//----------------------------------------------------------------------------------------------------------------------
void TestBorderAgentServiceRegisteration(void)
{
static const char kDefaultServiceBaseName[] = OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME;
static const char kEphemeralKey[] = "nexus1234";
static constexpr uint32_t kUdpPort = 49155;
static constexpr uint32_t kInfraIfIndex = 1;
Core nexus;
Node &node0 = nexus.CreateNode();
Dns::Multicast::Core::Iterator *iterator;
Dns::Multicast::Core::Service service;
Dns::Multicast::Core::EntryState entryState;
Log("------------------------------------------------------------------------------------------------------");
Log("TestBorderAgentServiceRegisteration");
nexus.AdvanceTime(0);
node0.Form();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enable mDNS
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().IsEnabled());
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEnabled());
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Validate the registered mDNS MeshCop service by Border Agent");
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState));
Log(" HostName: %s", service.mHostName);
Log(" ServiceInstance: %s", service.mServiceInstance);
Log(" ServiceType: %s", service.mServiceType);
Log(" Port: %u", service.mPort);
Log(" TTL: %lu", ToUlong(service.mTtl));
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
VerifyOrQuit(service.mTxtDataLength > 1);
VerifyOrQuit(service.mTtl > 0);
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
// Check that there is no more registered mDNS service
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Enable ans start ephemeral key");
node0.Get<EphemeralKeyManager>().SetEnabled(true);
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
node0.Get<EphemeralKeyManager>().SetCallback(HandleEphemeralKeyChange, &node0);
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Check the registered services");
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
for (uint8_t num = 2; num > 0; num--)
{
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState));
Log("- - - - - - - - - - - - - - - - -");
Log(" HostName: %s", service.mHostName);
Log(" ServiceInstance: %s", service.mServiceInstance);
Log(" ServiceType: %s", service.mServiceType);
Log(" Port: %u", service.mPort);
Log(" TTL: %lu", ToUlong(service.mTtl));
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
VerifyOrQuit(service.mTtl > 0);
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
if (StringMatch(service.mServiceType, "_meshcop._udp"))
{
VerifyOrQuit(service.mTxtDataLength > 1);
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
}
else if (StringMatch(service.mServiceType, "_meshcop-e._udp"))
{
VerifyOrQuit(service.mPort == kUdpPort);
VerifyOrQuit(service.mTxtDataLength == 1);
VerifyOrQuit(service.mTxtData[0] == 0);
}
else
{
// Unexpected service type
VerifyOrQuit(false);
}
}
// Check that there is no more registered mDNS service
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
Log("Wait for the ephemeral key to expire and validate the registered service is removed");
nexus.AdvanceTime(5 * Time::kOneMinuteInMsec);
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState));
Log(" HostName: %s", service.mHostName);
Log(" ServiceInstance: %s", service.mServiceInstance);
Log(" ServiceType: %s", service.mServiceType);
Log(" Port: %u", service.mPort);
Log(" TTL: %lu", ToUlong(service.mTtl));
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
VerifyOrQuit(service.mTxtDataLength > 1);
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
VerifyOrQuit(service.mTtl > 0);
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
// Check that there is no more registered mDNS service
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Change the base service name and validate the new service");
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent>().SetServiceBaseName("OpenThreadAgent"));
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState));
Log(" HostName: %s", service.mHostName);
Log(" ServiceInstance: %s", service.mServiceInstance);
Log(" ServiceType: %s", service.mServiceType);
Log(" Port: %u", service.mPort);
Log(" TTL: %lu", ToUlong(service.mTtl));
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
VerifyOrQuit(service.mTxtDataLength > 1);
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
VerifyOrQuit(service.mTtl > 0);
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
// Check that there is no more registered mDNS service
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Disable Border Agent and validate that registered service is removed");
node0.Get<MeshCoP::BorderAgent>().SetEnabled(false);
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent>().IsEnabled());
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Log("Re-enable Border Agent and validate that service is registered again");
node0.Get<MeshCoP::BorderAgent>().SetEnabled(true);
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent>().IsEnabled());
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
VerifyOrQuit(iterator != nullptr);
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState));
Log(" HostName: %s", service.mHostName);
Log(" ServiceInstance: %s", service.mServiceInstance);
Log(" ServiceType: %s", service.mServiceType);
Log(" Port: %u", service.mPort);
Log(" TTL: %lu", ToUlong(service.mTtl));
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
VerifyOrQuit(service.mTxtDataLength > 1);
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent>().GetUdpPort());
VerifyOrQuit(service.mTtl > 0);
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
// Check that there is no more registered mDNS service
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNotFound);
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
}
} // namespace Nexus
} // namespace ot
@@ -995,6 +1232,7 @@ int main(void)
ot::Nexus::TestBorderAgent();
ot::Nexus::TestBorderAgentEphemeralKey();
ot::Nexus::TestBorderAgentTxtDataCallback();
ot::Nexus::TestBorderAgentServiceRegisteration();
printf("All tests passed\n");
return 0;
}
+8
View File
@@ -1849,6 +1849,14 @@ Core *InitTest(void)
VerifyOrQuit(sInstance != nullptr);
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
// Disable the Border Agent to prevent its attempt to
// register the `_meshcop._udp` service from
// interfering with this test.
sInstance->Get<MeshCoP::BorderAgent>().SetEnabled(false);
#endif
return &sInstance->Get<Core>();
}
+7
View File
@@ -543,6 +543,13 @@ void InitTest(void)
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
SuccessOrQuit(otThreadSetEnabled(sInstance, true));
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
// Disable the Border Agent to prevent its attempt to
// register the `_meshcop._udp` service from
// interfering with this test.
sInstance->Get<MeshCoP::BorderAgent>().SetEnabled(false);
#endif
// Configure the `Dnssd` module to use `otPlatDnssd` APIs.
sInstance->Get<Dnssd>().SetUseNativeMdns(false);