mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
1e79496c57
This commit adds support for handling mDNS service name conflicts by automatically renaming the service when a collision is detected during registration. The new naming scheme appends a suffix based on the last two bytes of the device's Extended Address (e.g., " #AB1E"). If this name also conflicts, an additional index is appended (e.g., " #AB1E (1)"). Changes: - Added `mServiceRenameIndex` to `Manager` and `EphemeralKeyManager` to track re-naming attempts. - Updated `otBorderAgentSetMeshCoPServiceBaseName()` and CLI documentation to reflect the new naming and conflict resolution logic. - Updated `OT_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME_MAX_LENGTH` to ensure the full name fits within the 63-character DNS label limit. - Added Nexus tests to verify the renaming logic under conflict.
466 lines
18 KiB
C++
466 lines
18 KiB
C++
/*
|
|
* Copyright (c) 2018, 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.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* This file includes definitions for the BorderAgent role.
|
|
*/
|
|
|
|
#ifndef OT_CORE_MESHCOP_BORDER_AGENT_HPP_
|
|
#define OT_CORE_MESHCOP_BORDER_AGENT_HPP_
|
|
|
|
#include "openthread-core-config.h"
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
|
|
|
#include <openthread/border_agent.h>
|
|
#include <openthread/history_tracker.h>
|
|
|
|
#include "border_router/routing_manager.hpp"
|
|
#include "common/appender.hpp"
|
|
#include "common/as_core_type.hpp"
|
|
#include "common/heap_allocatable.hpp"
|
|
#include "common/linked_list.hpp"
|
|
#include "common/locator.hpp"
|
|
#include "common/log.hpp"
|
|
#include "common/non_copyable.hpp"
|
|
#include "common/notifier.hpp"
|
|
#include "common/owned_ptr.hpp"
|
|
#include "common/tasklet.hpp"
|
|
#include "common/uptime.hpp"
|
|
#include "meshcop/border_agent_admitter.hpp"
|
|
#include "meshcop/border_agent_txt_data.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"
|
|
#include "thread/uri_paths.hpp"
|
|
|
|
namespace ot {
|
|
namespace MeshCoP {
|
|
namespace BorderAgent {
|
|
|
|
#if !OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
|
|
#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
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
|
class EphemeralKeyManager;
|
|
#endif
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
|
|
/**
|
|
* Represents a Border Agent Identifier.
|
|
*/
|
|
struct Id : public otBorderAgentId, public Clearable<Id>, public Equatable<Id>
|
|
{
|
|
static constexpr uint16_t kLength = OT_BORDER_AGENT_ID_LENGTH; ///< The ID length (number of bytes).
|
|
|
|
/**
|
|
* Generates a random ID.
|
|
*/
|
|
void GenerateRandom(void) { Random::NonCrypto::Fill(mId); }
|
|
};
|
|
#endif
|
|
|
|
class Manager : public InstanceLocator, private NonCopyable
|
|
{
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
|
|
friend ot::Dnssd;
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
|
|
friend class EphemeralKeyManager;
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
friend class Admitter;
|
|
#endif
|
|
friend class ot::Notifier;
|
|
friend class Tmf::Agent;
|
|
friend class TxtData;
|
|
|
|
class CoapDtlsSession;
|
|
|
|
public:
|
|
typedef otBorderAgentCounters Counters; ///< Border Agent Counters.
|
|
typedef otBorderAgentSessionInfo SessionInfo; ///< A session info.
|
|
|
|
/**
|
|
* Represents an iterator for secure sessions.
|
|
*/
|
|
class SessionIterator : public otBorderAgentSessionIterator
|
|
{
|
|
public:
|
|
/**
|
|
* Initializes the `SessionIterator`.
|
|
*
|
|
* @param[in] aInstance The OpenThread instance.
|
|
*/
|
|
void Init(Instance &aInstance);
|
|
|
|
/**
|
|
* Retrieves the next session information.
|
|
*
|
|
* @param[out] aSessionInfo A `SessionInfo` to populate.
|
|
*
|
|
* @retval kErrorNone Successfully retrieved the next session. @p aSessionInfo is updated.
|
|
* @retval kErrorNotFound No more sessions are available. The end of the list has been reached.
|
|
*/
|
|
Error GetNextSessionInfo(SessionInfo &aSessionInfo);
|
|
|
|
private:
|
|
CoapDtlsSession *GetSession(void) const { return static_cast<CoapDtlsSession *>(mPtr); }
|
|
void SetSession(CoapDtlsSession *aSession) { mPtr = aSession; }
|
|
uint64_t GetInitTime(void) const { return mData; }
|
|
void SetInitTime(uint64_t aInitTime) { mData = aInitTime; }
|
|
};
|
|
|
|
/**
|
|
* Initializes the `Manager` object.
|
|
*
|
|
* @param[in] aInstance A reference to the OpenThread instance.
|
|
*/
|
|
explicit Manager(Instance &aInstance);
|
|
|
|
/**
|
|
* Enables or disables the Border Agent service.
|
|
*
|
|
* By default, the Border Agent service is enabled. This method allows us to explicitly control its state. This can
|
|
* be useful in scenarios such as:
|
|
* - The code wishes to delay the start of the Border Agent service (and its mDNS advertisement of the
|
|
* `_meshcop._udp` service on the infrastructure link). This allows time to prepare or determine vendor-specific
|
|
* TXT data entries for inclusion.
|
|
* - Unit tests or test scripts might disable the Border Agent service to prevent it from interfering with specific
|
|
* test steps. For example, tests validating mDNS or DNS-SD functionality may disable the Border Agent to prevent
|
|
* its registration of the MeshCoP service.
|
|
*
|
|
* @param[in] aEnabled Whether to enable or disable.
|
|
*/
|
|
void SetEnabled(bool aEnabled);
|
|
|
|
/**
|
|
* Indicated whether or not the Border Agent is enabled.
|
|
*
|
|
* @retval TRUE The Border Agent is enabled.
|
|
* @retval FALSE The Border Agent is disabled.
|
|
*/
|
|
bool IsEnabled(void) const { return mEnabled; }
|
|
|
|
/**
|
|
* Indicates whether the Border Agent service is enabled and running.
|
|
*
|
|
* @retval TRUE Border Agent service is running.
|
|
* @retval FALSE Border Agent service is not running.
|
|
*/
|
|
bool IsRunning(void) const { return mIsRunning; }
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
|
|
static_assert(sizeof(Id) == Id::kLength, "sizeof(Id) is not valid");
|
|
|
|
/**
|
|
* Gets the randomly generated Border Agent ID.
|
|
*
|
|
* The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to
|
|
* be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this
|
|
* Border Router/Agent device.
|
|
*
|
|
* @param[out] aId Reference to return the Border Agent ID.
|
|
*/
|
|
void GetId(Id &aId);
|
|
|
|
/**
|
|
* Sets the Border Agent ID.
|
|
*
|
|
* The Border Agent ID will be saved in persistent storage and survive reboots. It's required
|
|
* to set the ID only once after factory reset. If the ID has never been set by calling this
|
|
* method, a random ID will be generated and returned when `GetId()` is called.
|
|
*
|
|
* @param[in] aId The Border Agent ID.
|
|
*/
|
|
void SetId(const Id &aId);
|
|
#endif
|
|
|
|
/**
|
|
* Gets the UDP port of this service.
|
|
*
|
|
* @returns UDP port number.
|
|
*/
|
|
uint16_t GetUdpPort(void) const;
|
|
|
|
#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_COMMISSIONER_EVICTION_API_ENABLE
|
|
/**
|
|
* Forcefully evicts the current active Thread Commissioner.
|
|
*
|
|
* This is intended as an administrator tool to address a misbehaving or stale commissioner session that may be
|
|
* connected through a different Border Agent. It provides a mechanism to clear the single Active Commissioner
|
|
* role within the Thread network, allowing a new candidate to be selected as the Active commissioner.
|
|
*
|
|
* @retval kErrorNone Successfully sent the eviction request to the Leader.
|
|
* @retval kErrorNotFound There is no active commissioner session to evict.
|
|
* @retval kErrorNoBufs Could not allocate a message buffer to send the request.
|
|
*/
|
|
Error EvictActiveCommissioner(void);
|
|
#endif
|
|
|
|
/**
|
|
* Gets the set of border agent counters.
|
|
*
|
|
* @returns The border agent counters.
|
|
*/
|
|
const Counters &GetCounters(void) { return mCounters; }
|
|
|
|
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>;
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
friend class Admitter;
|
|
#endif
|
|
|
|
public:
|
|
Error SendMessage(OwnedPtr<Coap::Message> aMessage);
|
|
void ForwardUdpProxyToCommissioner(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
|
void ForwardUdpRelayToCommissioner(const Message &aMessage);
|
|
void Cleanup(void);
|
|
bool IsActiveCommissioner(void) const;
|
|
uint64_t GetAllocationTime(void) const { return mAllocationTime; }
|
|
uint16_t GetIndex(void) const { return mIndex; }
|
|
void CopyInfoTo(SessionInfo &aInfo, UptimeMsec aUptimeNow) const;
|
|
|
|
private:
|
|
enum Action : uint8_t
|
|
{
|
|
kReceive,
|
|
kSend,
|
|
kForward,
|
|
};
|
|
|
|
struct ForwardContext : public ot::LinkedListEntry<ForwardContext>,
|
|
public Heap::Allocatable<ForwardContext>,
|
|
private ot::NonCopyable
|
|
{
|
|
ForwardContext(CoapDtlsSession &aSession, const Coap::Message &aMessage, Uri aUri);
|
|
|
|
CoapDtlsSession &mSession;
|
|
ForwardContext *mNext;
|
|
Uri mUri;
|
|
Coap::Token mToken;
|
|
};
|
|
|
|
CoapDtlsSession(Instance &aInstance, Dtls::Transport &aDtlsTransport);
|
|
|
|
Error ForwardToCommissioner(OwnedPtr<Coap::Message> aForwardMessage, const Message &aMessage);
|
|
Error ForwardUdpRelay(const Message &aMessage);
|
|
Error ForwardUdpProxy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
|
void HandleTmfCommissionerKeepAlive(Coap::Msg &aMsg);
|
|
void HandleTmfRelayTx(Coap::Msg &aMsg);
|
|
void HandleTmfProxyTx(Coap::Msg &aMsg);
|
|
void HandleTmfDatasetGet(Coap::Message &aMessage, Uri aUri);
|
|
Error ForwardToLeader(const Coap::Msg &aMsg, Uri aUri);
|
|
void SendErrorMessage(Error aError, const Coap::Token &aToken);
|
|
|
|
static void HandleConnected(ConnectEvent aEvent, void *aContext);
|
|
void HandleConnected(ConnectEvent aEvent);
|
|
static void HandleLeaderResponseToFwdTmf(void *aContext, Coap::Msg *aMsg, otError aResult);
|
|
void HandleLeaderResponseToFwdTmf(const ForwardContext &aForwardContext,
|
|
const Coap::Msg *aResponse,
|
|
Error aResult);
|
|
static bool HandleResource(CoapBase &aCoapBase, const char *aUriPath, Coap::Msg &aMsg);
|
|
bool HandleResource(const char *aUriPath, Coap::Msg &aMsg);
|
|
static void HandleTimer(Timer &aTimer);
|
|
void HandleTimer(void);
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
bool IsEnroller(void) const { return mEnroller != nullptr; }
|
|
void ResignEnroller(void);
|
|
void HandleEnrollerTmf(Uri aUri, const Coap::Msg &aMsg);
|
|
Error ProcessEnrollerRegister(const Coap::Message &aMessage);
|
|
Error ProcessEnrollerKeepAlive(const Coap::Message &aMessage);
|
|
Error ProcessEnrollerJoinerAccept(const Coap::Message &aMessage);
|
|
Error ProcessEnrollerJoinerRelease(const Coap::Message &aMessage);
|
|
void SendEnrollerResponse(Uri aUri, StateTlv::State aResponseState, const Coap::Message &aRequest);
|
|
void SendEnrollerReportState(uint8_t aAdmitterState);
|
|
Error AppendAdmitterTlvs(Coap::Message &aMessage, uint8_t aAdmitterState);
|
|
void ForwardUdpRelayToEnroller(const Coap::Message &aMessage, bool aCheckEnrollerMode);
|
|
void ForwardUdpProxyToEnroller(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
|
|
|
static Error ReadSteeringDataTlv(const Message &aMessage, SteeringData &aSteeringData);
|
|
#endif
|
|
|
|
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
|
void LogUri(Action aAction, const char *aUriString, const char *aTxt);
|
|
|
|
template <Uri kUri> void Log(Action aAction) { Log<kUri>(aAction, ""); }
|
|
template <Uri kUri> void Log(Action aAction, const char *aTxt) { LogUri(aAction, UriToString<kUri>(), aTxt); }
|
|
#else
|
|
template <Uri kUri> void Log(Action) {}
|
|
template <Uri kUri> void Log(Action, const char *) {}
|
|
#endif
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
OwnedPtr<Admitter::Enroller> mEnroller;
|
|
#endif
|
|
LinkedList<ForwardContext> mForwardContexts;
|
|
TimerMilliContext mTimer;
|
|
UptimeMsec mAllocationTime;
|
|
uint16_t mIndex;
|
|
};
|
|
|
|
void UpdateState(void);
|
|
void Start(void);
|
|
void Stop(void);
|
|
|
|
// Callback from Notifier
|
|
void HandleNotifierEvents(Events aEvents);
|
|
|
|
template <Uri kUri> void HandleTmf(Coap::Msg &aMsg);
|
|
|
|
// Callbacks used with `Dtls::Transport`.
|
|
static SecureSession *HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo);
|
|
CoapDtlsSession *HandleAcceptSession(void);
|
|
static void HandleRemoveSession(void *aContext, SecureSession &aSession);
|
|
void HandleRemoveSession(SecureSession &aSession);
|
|
|
|
uint16_t GetNextSessionIndex(void) { return ++mSessionIndex; }
|
|
const Ip6::Address &GetCommissionerAloc(void) const { return mCommissionerAloc.GetAddress(); }
|
|
CoapDtlsSession *GetCommissionerSession(void) { return mCommissionerSession; }
|
|
|
|
bool IsCommissionerSession(const CoapDtlsSession &aSession) const { return mCommissionerSession == &aSession; }
|
|
void HandleSessionConnected(CoapDtlsSession &aSession);
|
|
void HandleSessionDisconnected(CoapDtlsSession &aSession, CoapDtlsSession::ConnectEvent aEvent);
|
|
void HandleCommissionerPetitionAccepted(CoapDtlsSession &aSession, uint16_t aSessionId);
|
|
void RevokeRoleIfActiveCommissioner(CoapDtlsSession &aSession);
|
|
|
|
static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
|
bool HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
|
|
// Callback from `BorderAgent::TxtData`.
|
|
void HandleServiceTxtDataChanged(void) { RegisterService(); }
|
|
|
|
// Callback from `Dnssd`
|
|
void HandleDnssdPlatformStateChange(void) { RegisterService(); }
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
// Callback from `Admitter`
|
|
void HandlePrimeAdmitterStateChanged(void) { RegisterService(); }
|
|
#endif
|
|
|
|
const char *GetServiceName(void);
|
|
bool IsServiceNameEmpty(void) const { return mServiceName[0] == kNullChar; }
|
|
void ConstructServiceName(void);
|
|
void ConstructServiceName(uint16_t aRenameIndex, Dns::Name::LabelBuffer &aNameBuffer);
|
|
void RegisterService(void);
|
|
void UnregisterService(void);
|
|
void HandleRegisterDone(Error aError);
|
|
|
|
static void HandleRegisterDone(otInstance *aInstance, otPlatDnssdRequestId aRequestId, otError aError);
|
|
#endif
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
|
|
static const char kServiceType[];
|
|
static const char kDefaultBaseServiceName[];
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE
|
|
static const char kAdmitterSubType[];
|
|
static const char *const kServiceSubTypes[];
|
|
#endif
|
|
#endif
|
|
|
|
bool mEnabled;
|
|
bool mIsRunning;
|
|
uint16_t mSessionIndex;
|
|
Dtls::Transport mDtlsTransport;
|
|
CoapDtlsSession *mCommissionerSession;
|
|
Ip6::Udp::Receiver mCommissionerUdpReceiver;
|
|
Ip6::Netif::UnicastAddress mCommissionerAloc;
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
|
|
Id mId;
|
|
bool mIdInitialized;
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
|
|
|
|
char mBaseServiceName[kBaseServiceNameMaxLen + 1];
|
|
Dns::Name::LabelBuffer mServiceName;
|
|
uint16_t mServiceRenameIndex;
|
|
#endif
|
|
Counters mCounters;
|
|
};
|
|
|
|
DeclareTmfHandler(Manager, kUriRelayRx);
|
|
|
|
} // namespace BorderAgent
|
|
} // namespace MeshCoP
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
|
|
DefineCoreType(otBorderAgentId, MeshCoP::BorderAgent::Id);
|
|
#endif
|
|
|
|
DefineCoreType(otBorderAgentSessionIterator, MeshCoP::BorderAgent::Manager::SessionIterator);
|
|
|
|
} // namespace ot
|
|
|
|
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
|
|
|
#endif // OT_CORE_MESHCOP_BORDER_AGENT_HPP_
|