[border-agent] add new apis for refactoring meshcop service publishing (#11215)

This commit adds a new OT API to set callback for border agent state
change: `otBorderAgentSetMeshCoPServiceChangedCallback`

`otBorderAgentStateChangedCallback` is invoked when the 'IsActive'
state of BorderAgent changes or the MeshCoP TXT data from Thread stack
changes. For example, the network name, the EXT PAN ID. This is used
to update the MeshCoP TXT data that will be published on the host and
notify the platform to start/stop the UDP Proxy.

After applying the UdpProxy design, the UDP port of published MeshCoP
service will be provided by the UdpProxy on the host (in ot-br-posix)
instead of OT core.
This commit is contained in:
Li Cao
2025-02-18 13:33:16 -08:00
committed by GitHub
parent a6432f7daa
commit 36a8f71d06
8 changed files with 547 additions and 4 deletions
+29
View File
@@ -143,6 +143,35 @@ bool otBorderAgentIsActive(otInstance *aInstance);
*/
uint16_t otBorderAgentGetUdpPort(otInstance *aInstance);
/**
* This callback informs the application of the changes in the state of the MeshCoP service.
*
* In specific, the 'state' includes the MeshCoP TXT data originated from the Thread network and whether the
* Border Agent is Active (which can be obtained by `otBorderAgentIsActive`).
*
* @param[in] aTxtData A pointer to the encoded MeshCoP TXT data originated from the Thread network.
* @param[in] aLength The length of the encoded TXT data.
* @param[in] aContext A pointer to application-specific context.
*/
typedef void (*otBorderAgentMeshCoPServiceChangedCallback)(const uint8_t *aTxtData, uint16_t aLength, void *aContext);
/**
* Sets the callback function used by the Border Agent to notify of any changes to the state of the MeshCoP service.
*
* The callback is invoked when the 'Is Active' state of the Border Agent or the MeshCoP service TXT data values
* change. For example, it is invoked when the network name or the extended PAN ID changes and passes the updated
* encoded TXT data to the application layer.
*
* This callback is invoked once right after this API is called to provide initial states of the MeshCoP service.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCallback The callback to be invoked when there are any changes of the MeshCoP service.
* @param[in] aContext A pointer to application-specific context.
*/
void otBorderAgentSetMeshCoPServiceChangedCallback(otInstance *aInstance,
otBorderAgentMeshCoPServiceChangedCallback aCallback,
void *aContext);
/**
* 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 (477)
#define OPENTHREAD_API_VERSION (478)
/**
* @addtogroup api-instance
+7
View File
@@ -76,6 +76,13 @@ otError otBorderAgentGetNextSessionInfo(otBorderAgentSessionIterator *aIterator,
return AsCoreType(aIterator).GetNextSessionInfo(*aSessionInfo);
}
void otBorderAgentSetMeshCoPServiceChangedCallback(otInstance *aInstance,
otBorderAgentMeshCoPServiceChangedCallback aCallback,
void *aContext)
{
AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().SetMeshCoPServiceChangedCallback(aCallback, aContext);
}
const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance)
{
return &AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().GetCounters();
@@ -2301,6 +2301,9 @@ void RoutingManager::OmrPrefixManager::SetFavordPrefix(const OmrPrefix &aOmrPref
if (oldFavoredPrefix != mFavoredPrefix)
{
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
Get<MeshCoP::BorderAgent>().PostNotifyMeshCoPServiceChangedTask();
#endif
LogInfo("Favored OMR prefix: %s -> %s", FavoredToString(oldFavoredPrefix).AsCString(),
FavoredToString(mFavoredPrefix).AsCString());
}
+198
View File
@@ -52,6 +52,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
, mIdInitialized(false)
#endif
, mNotifyMeshCoPServiceChangedTask(aInstance)
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
, mEphemeralKeyManager(aInstance)
#endif
@@ -114,6 +115,7 @@ void BorderAgent::Start(void)
pskc.Clear();
mIsRunning = true;
PostNotifyMeshCoPServiceChangedTask();
LogInfo("Border Agent start listening on port %u", GetUdpPort());
@@ -132,6 +134,7 @@ void BorderAgent::Stop(void)
mDtlsTransport.Close();
mIsRunning = false;
PostNotifyMeshCoPServiceChangedTask();
LogInfo("Border Agent stopped");
@@ -141,6 +144,13 @@ exit:
uint16_t BorderAgent::GetUdpPort(void) const { return mDtlsTransport.GetUdpPort(); }
void BorderAgent::SetMeshCoPServiceChangedCallback(MeshCoPServiceChangedCallback aCallback, void *aContext)
{
mMeshCoPServiceChangedCallback.Set(aCallback, aContext);
mNotifyMeshCoPServiceChangedTask.Post();
}
void BorderAgent::HandleNotifierEvents(Events aEvents)
{
if (aEvents.Contains(kEventThreadRoleChanged))
@@ -169,6 +179,12 @@ void BorderAgent::HandleNotifierEvents(Events aEvents)
pskc.Clear();
}
if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadExtPanIdChanged | kEventThreadNetworkNameChanged |
kEventThreadBackboneRouterStateChanged | kEventActiveDatasetChanged))
{
PostNotifyMeshCoPServiceChangedTask();
}
exit:
return;
}
@@ -316,6 +332,188 @@ exit:
FreeMessageOnError(message, error);
}
void BorderAgent::NotifyMeshCoPServiceChanged(void)
{
MeshCoPTxtEncoder meshCoPTxtEncoder(GetInstance());
VerifyOrExit(mMeshCoPServiceChangedCallback.IsSet());
SuccessOrAssert(meshCoPTxtEncoder.EncodeTxtData());
mMeshCoPServiceChangedCallback.Invoke(meshCoPTxtEncoder.GetTxtData(), meshCoPTxtEncoder.GetTxtDataLen());
exit:
return;
}
void BorderAgent::PostNotifyMeshCoPServiceChangedTask(void)
{
if (mMeshCoPServiceChangedCallback.IsSet())
{
mNotifyMeshCoPServiceChangedTask.Post();
}
}
//----------------------------------------------------------------------------------------------------------------------
// BorderAgent::MeshCoPTxtEncoder
Error BorderAgent::MeshCoPTxtEncoder::AppendTxtEntry(const char *aKey, const void *aValue, uint16_t aValueLength)
{
Dns::TxtEntry txtEntry;
txtEntry.Init(aKey, reinterpret_cast<const uint8_t *>(aValue), aValueLength);
return txtEntry.AppendTo(mAppender);
}
template <> Error BorderAgent::MeshCoPTxtEncoder::AppendTxtEntry<NameData>(const char *aKey, const NameData &aObject)
{
return AppendTxtEntry(aKey, aObject.GetBuffer(), aObject.GetLength());
}
Error BorderAgent::MeshCoPTxtEncoder::EncodeTxtData(void)
{
#if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
static const char kThreadVersionString[] = "1.1.1";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_2
static const char kThreadVersionString[] = "1.2.0";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3
static const char kThreadVersionString[] = "1.3.0";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3_1
static const char kThreadVersionString[] = "1.3.1";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_4
static const char kThreadVersionString[] = "1.4.0";
#endif
Error error = kErrorNone;
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
Id id;
#endif
StateBitmap state;
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
if (Get<BorderAgent>().GetId(id) == kErrorNone)
{
SuccessOrExit(error = AppendTxtEntry("id", id));
}
#endif
SuccessOrExit(error = AppendTxtEntry("nn", Get<NetworkNameManager>().GetNetworkName().GetAsData()));
SuccessOrExit(error = AppendTxtEntry("xp", Get<ExtendedPanIdManager>().GetExtPanId()));
SuccessOrExit(error = AppendTxtEntry("tv", NameData(kThreadVersionString, sizeof(kThreadVersionString) - 1)));
SuccessOrExit(error = AppendTxtEntry("xa", Get<Mac::Mac>().GetExtAddress()));
state = GetStateBitmap();
SuccessOrExit(error = AppendTxtEntry("sb", BigEndian::HostSwap32(state.ToUint32())));
if (state.mThreadIfStatus == kThreadIfStatusActive)
{
SuccessOrExit(error = AppendTxtEntry(
"pt", BigEndian::HostSwap32(Get<Mle::MleRouter>().GetLeaderData().GetPartitionId())));
if (Get<MeshCoP::ActiveDatasetManager>().GetTimestamp().IsValid())
{
SuccessOrExit(error = AppendTxtEntry("at", Get<MeshCoP::ActiveDatasetManager>().GetTimestamp()));
}
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
SuccessOrExit(error = AppendBbrTxtEntry(state));
#endif
#if OTBR_ENABLE_BORDER_ROUTING
SuccessOrExit(error = AppendOmrTxtEntry());
#endif
exit:
return error;
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
Error BorderAgent::MeshCoPTxtEncoder::AppendBbrTxtEntry(StateBitmap aState)
{
Error error = kErrorNone;
const DomainName &domainName = Get<MeshCoP::NetworkNameManager>().GetDomainName();
if (aState.mBbrIsActive)
{
BackboneRouter::Config bbrConfig;
Get<BackboneRouter::Local>().GetConfig(bbrConfig);
SuccessOrExit(error = AppendTxtEntry("sq", bbrConfig.mSequenceNumber));
SuccessOrExit(error = AppendTxtEntry("bb", BigEndian::HostSwap16(BackboneRouter::kBackboneUdpPort)));
}
error = AppendTxtEntry(
"dn", NameData(domainName.GetAsCString(), StringLength(domainName.GetAsCString(), sizeof(domainName))));
exit:
return error;
}
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Error BorderAgent::MeshCoPTxtEncoder::AppendOmrTxtEntry(void)
{
Error error = kErrorNone;
Ip6::Prefix prefix;
BorderRouter::RoutingManager::RoutePreference preference;
if ((error = Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference)) == kErrorNone)
{
uint8_t omrData[Ip6::NetworkPrefix::kSize + 1];
omrData[0] = prefix.GetLength();
memcpy(omrData + 1, prefix.GetBytes(), prefix.GetBytesSize());
SuccessOrExit(error = AppendTxtEntry("omr", omrData));
}
exit:
return error;
}
#endif
BorderAgent::MeshCoPTxtEncoder::StateBitmap BorderAgent::MeshCoPTxtEncoder::GetStateBitmap(void)
{
StateBitmap state;
state.mConnectionMode = kConnectionModePskc;
state.mAvailability = kAvailabilityHigh;
switch (Get<Mle::MleRouter>().GetRole())
{
case Mle::DeviceRole::kRoleDisabled:
state.mThreadIfStatus = kThreadIfStatusNotInitialized;
state.mThreadRole = kThreadRoleDisabledOrDetached;
break;
case Mle::DeviceRole::kRoleDetached:
state.mThreadIfStatus = kThreadIfStatusInitialized;
state.mThreadRole = kThreadRoleDisabledOrDetached;
break;
case Mle::DeviceRole::kRoleChild:
state.mThreadIfStatus = kThreadIfStatusActive;
state.mThreadRole = kThreadRoleChild;
break;
case Mle::DeviceRole::kRoleRouter:
state.mThreadIfStatus = kThreadIfStatusActive;
state.mThreadRole = kThreadRoleRouter;
break;
case Mle::DeviceRole::kRoleLeader:
state.mThreadIfStatus = kThreadIfStatusActive;
state.mThreadRole = kThreadRoleLeader;
break;
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
state.mBbrIsActive = state.mThreadIfStatus == kThreadIfStatusActive &&
Get<BackboneRouter::Local>().GetState() != BackboneRouter::Local::State::kStateDisabled;
state.mBbrIsPrimary = state.mThreadIfStatus == kThreadIfStatusActive &&
Get<BackboneRouter::Local>().GetState() == BackboneRouter::Local::State::kStatePrimary;
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
state.mEpskcSupported =
Get<BorderAgent::EphemeralKeyManager>().GetState() != EphemeralKeyManager::State::kStateDisabled;
#endif
return state;
}
//----------------------------------------------------------------------------------------------------------------------
// BorderAgent::SessionIterator
+136
View File
@@ -40,6 +40,8 @@
#include <openthread/border_agent.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"
@@ -50,6 +52,7 @@
#include "common/tasklet.hpp"
#include "meshcop/dataset.hpp"
#include "meshcop/secure_transport.hpp"
#include "net/dns_types.hpp"
#include "net/socket.hpp"
#include "net/udp6.hpp"
#include "thread/tmf.hpp"
@@ -69,6 +72,9 @@ namespace MeshCoP {
class BorderAgent : public InstanceLocator, private NonCopyable
{
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
friend class ot::BorderRouter::RoutingManager;
#endif
friend class ot::Notifier;
friend class Tmf::Agent;
@@ -161,6 +167,23 @@ public:
*/
bool IsRunning(void) const { return mIsRunning; }
typedef otBorderAgentMeshCoPServiceChangedCallback MeshCoPServiceChangedCallback;
/**
* Sets the callback function used by the Border Agent to notify any changes on the MeshCoP service TXT values.
*
* The callback is invoked when the state of MeshCoP service TXT values changes. For example, it is
* invoked when the network name or the extended PAN ID changes and pass the updated encoded TXT data to the
* application layer.
*
* This callback is invoked once right after this API is called to provide initial states of the MeshCoP
* service to the application.
*
* @param[in] aCallback The callback to invoke when there are any changes of the MeshCoP service.
* @param[in] aContext A pointer to application-specific context.
*/
void SetMeshCoPServiceChangedCallback(MeshCoPServiceChangedCallback aCallback, void *aContext);
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
/**
* Manages the ephemeral key use by Border Agent.
@@ -403,6 +426,112 @@ private:
uint64_t mAllocationTime;
};
class MeshCoPTxtEncoder : public InstanceLocator
{
public:
explicit MeshCoPTxtEncoder(Instance &aInstance)
: InstanceLocator(aInstance)
, mAppender(mTxtDataBuffer, sizeof(mTxtDataBuffer))
{
}
enum : uint8_t
{
kConnectionModeDisabled = 0,
kConnectionModePskc = 1,
kConnectionModePskd = 2,
kConnectionModeVendor = 3,
kConnectionModeX509 = 4,
};
enum : uint8_t
{
kThreadIfStatusNotInitialized = 0,
kThreadIfStatusInitialized = 1,
kThreadIfStatusActive = 2,
};
enum : uint8_t
{
kThreadRoleDisabledOrDetached = 0,
kThreadRoleChild = 1,
kThreadRoleRouter = 2,
kThreadRoleLeader = 3,
};
enum : uint8_t
{
kAvailabilityInfrequent = 0,
kAvailabilityHigh = 1,
};
struct StateBitmap
{
uint32_t mConnectionMode : 3;
uint32_t mThreadIfStatus : 2;
uint32_t mAvailability : 2;
uint32_t mBbrIsActive : 1;
uint32_t mBbrIsPrimary : 1;
uint32_t mThreadRole : 2;
uint32_t mEpskcSupported : 1;
StateBitmap(void)
: mConnectionMode(0)
, mThreadIfStatus(0)
, mAvailability(0)
, mBbrIsActive(0)
, mBbrIsPrimary(0)
, mThreadRole(kThreadRoleDisabledOrDetached)
, mEpskcSupported(0)
{
}
uint32_t ToUint32(void) const
{
uint32_t bitmap = 0;
bitmap |= mConnectionMode << 0;
bitmap |= mThreadIfStatus << 3;
bitmap |= mAvailability << 5;
bitmap |= mBbrIsActive << 7;
bitmap |= mBbrIsPrimary << 8;
bitmap |= mThreadRole << 9;
bitmap |= mEpskcSupported << 11;
return bitmap;
}
};
Error EncodeTxtData(void);
uint8_t *GetTxtData(void) { return mTxtDataBuffer; }
uint16_t GetTxtDataLen(void) { return mAppender.GetAppendedLength(); }
private:
Error AppendTxtEntry(const char *aKey, const void *aValue, uint16_t aValueLength);
template <typename ObjectType> Error AppendTxtEntry(const char *aKey, const ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
static_assert(!TypeTraits::IsSame<ObjectType, NameData>::kValue, "ObjectType must not be `NameData`");
return AppendTxtEntry(aKey, &aObject, sizeof(ObjectType));
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
Error AppendBbrTxtEntry(StateBitmap aState);
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Error AppendOmrTxtEntry(void);
#endif
StateBitmap GetStateBitmap(void);
static constexpr uint16_t kMaxTxtDataLen = 128;
uint8_t mTxtDataBuffer[kMaxTxtDataLen];
Appender mAppender;
};
void Start(void);
void Stop(void);
void HandleNotifierEvents(Events aEvents);
@@ -421,12 +550,19 @@ private:
static Coap::Message::Code CoapCodeFromError(Error aError);
void PostNotifyMeshCoPServiceChangedTask(void);
void NotifyMeshCoPServiceChanged(void);
using NotifyMeshCoPServiceChangedTask = TaskletIn<BorderAgent, &BorderAgent::NotifyMeshCoPServiceChanged>;
bool mIsRunning;
Dtls::Transport mDtlsTransport;
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
Id mId;
bool mIdInitialized;
#endif
Callback<MeshCoPServiceChangedCallback> mMeshCoPServiceChangedCallback;
NotifyMeshCoPServiceChangedTask mNotifyMeshCoPServiceChangedTask;
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
EphemeralKeyManager mEphemeralKeyManager;
#endif
+11 -1
View File
@@ -1211,6 +1211,17 @@ public:
*/
Error AppendTo(Message &aMessage) const;
/**
* Encodes and appends the `TxtEntry` to an Appender object.
*
* @param[in] aAppender The appender to append to.
*
* @retval kErrorNone Entry was appended successfully to @p aAppender.
* @retval kErrorInvalidArgs The `TxTEntry` info is not valid.
* @retval kErrorNoBufs Insufficient available space in @p aAppender.
*/
Error AppendTo(Appender &aAppender) const;
/**
* Appends an array of `TxtEntry` items to a message.
*
@@ -1238,7 +1249,6 @@ public:
static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, MutableData<kWithUint16Length> &aData);
private:
Error AppendTo(Appender &aAppender) const;
static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Appender &aAppender);
static constexpr uint8_t kMaxKeyValueEncodedSize = 255;
+162 -2
View File
@@ -36,8 +36,13 @@
namespace ot {
namespace Nexus {
using BorderAgent = MeshCoP::BorderAgent;
using EphemeralKeyManager = ot::MeshCoP::BorderAgent::EphemeralKeyManager;
using ActiveDatasetManager = MeshCoP::ActiveDatasetManager;
using BorderAgent = MeshCoP::BorderAgent;
using EphemeralKeyManager = ot::MeshCoP::BorderAgent::EphemeralKeyManager;
using ExtendedPanIdManager = MeshCoP::ExtendedPanIdManager;
using NameData = MeshCoP::NameData;
using NetworkNameManager = MeshCoP::NetworkNameManager;
using TxtEntry = Dns::TxtEntry;
void TestBorderAgent(void)
{
@@ -737,6 +742,160 @@ void TestBorderAgentEphemeralKey(void)
VerifyOrQuit(node0.Get<BorderAgent>().GetCounters().mEpskcInvalidArgsErrors == 2);
}
class MeshCoPServiceTester
{
public:
MeshCoPServiceTester(BorderAgent &aBorderAgent)
: mBorderAgent(aBorderAgent)
, mIsRunning(false)
, mUdpPort(0)
{
}
void HandleMeshCoPServiceChanged(const uint8_t *aTxtData, uint16_t aLength)
{
mIsRunning = mBorderAgent.IsRunning();
mUdpPort = mBorderAgent.GetUdpPort();
assert(aLength <= kMaxTxtDataLen);
memcpy(mTxtData, aTxtData, aLength);
mTxtDataLength = aLength;
}
bool FindTxtEntry(const char *aKey, TxtEntry &aTxtEntry)
{
bool found = false;
TxtEntry::Iterator iter;
iter.Init(mTxtData, mTxtDataLength);
while (iter.GetNextEntry(aTxtEntry) == kErrorNone)
{
if (strcmp(aTxtEntry.mKey, aKey) == 0)
{
found = true;
break;
}
}
return found;
}
static constexpr uint16_t kMaxTxtDataLen = 128;
BorderAgent &mBorderAgent;
uint8_t mTxtData[kMaxTxtDataLen];
uint16_t mTxtDataLength;
bool mIsRunning;
uint16_t mUdpPort;
};
static void HandleMeshCoPServiceChanged(const uint8_t *aTxtData, uint16_t aLength, void *aContext)
{
static_cast<MeshCoPServiceTester *>(aContext)->HandleMeshCoPServiceChanged(aTxtData, aLength);
}
template <typename ObjectType> bool CheckObjectSameAsTxtEntryData(const TxtEntry &aTxtEntry, const ObjectType &aObject)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return aTxtEntry.mValueLength == sizeof(ObjectType) && memcmp(aTxtEntry.mValue, &aObject, sizeof(ObjectType)) == 0;
}
template <> bool CheckObjectSameAsTxtEntryData<NameData>(const TxtEntry &aTxtEntry, const NameData &aNameData)
{
return aTxtEntry.mValueLength == aNameData.GetLength() &&
memcmp(aTxtEntry.mValue, aNameData.GetBuffer(), aNameData.GetLength()) == 0;
}
#if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
static const char kThreadVersionString[] = "1.1.1";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_2
static const char kThreadVersionString[] = "1.2.0";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3
static const char kThreadVersionString[] = "1.3.0";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3_1
static const char kThreadVersionString[] = "1.3.1";
#elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_4
static const char kThreadVersionString[] = "1.4.0";
#endif
void TestBorderAgentMeshCoPServiceChangedCallback(void)
{
Core nexus;
Node &node0 = nexus.CreateNode();
Log("------------------------------------------------------------------------------------------------------");
Log("TestBorderAgentMeshCoPServiceChangedCallback");
nexus.AdvanceTime(0);
MeshCoPServiceTester meshCoPServiceTester(node0.Get<BorderAgent>());
TxtEntry txtEntry;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 1. Set MeshCoP service change callback. Will get initial values.
Log("Set MeshCoP service change callback and check initial values");
node0.Get<BorderAgent>().SetMeshCoPServiceChangedCallback(HandleMeshCoPServiceChanged, &meshCoPServiceTester);
nexus.AdvanceTime(1);
// 1.1 Check the initial TXT entries
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("id", txtEntry));
BorderAgent::Id id;
VerifyOrQuit(node0.Get<BorderAgent>().GetId(id) == kErrorNone);
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, id));
#endif
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("nn", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<NetworkNameManager>().GetNetworkName().GetAsData()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("xp", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<ExtendedPanIdManager>().GetExtPanId()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("tv", txtEntry));
VerifyOrQuit(
CheckObjectSameAsTxtEntryData(txtEntry, NameData(kThreadVersionString, sizeof(kThreadVersionString) - 1)));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("xa", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<Mac::Mac>().GetExtAddress()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("sb", txtEntry));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("pt", txtEntry) == false);
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("at", txtEntry) == false);
// 1.2 Check the Border Agent state
VerifyOrQuit(meshCoPServiceTester.mIsRunning == false);
VerifyOrQuit(meshCoPServiceTester.mUdpPort == 0);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 2. Join Thread network and check updated values and states.
Log("Join Thread network and check updated Txt data and states");
node0.Form();
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
// 2.1 Check the initial TXT entries
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("id", txtEntry));
VerifyOrQuit(node0.Get<BorderAgent>().GetId(id) == kErrorNone);
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, id));
#endif
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("nn", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<NetworkNameManager>().GetNetworkName().GetAsData()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("xp", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<ExtendedPanIdManager>().GetExtPanId()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("tv", txtEntry));
VerifyOrQuit(
CheckObjectSameAsTxtEntryData(txtEntry, NameData(kThreadVersionString, sizeof(kThreadVersionString) - 1)));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("xa", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<Mac::Mac>().GetExtAddress()));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("sb", txtEntry));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("pt", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(
txtEntry, BigEndian::HostSwap32(node0.Get<Mle::MleRouter>().GetLeaderData().GetPartitionId())));
VerifyOrQuit(meshCoPServiceTester.FindTxtEntry("at", txtEntry));
VerifyOrQuit(CheckObjectSameAsTxtEntryData(txtEntry, node0.Get<ActiveDatasetManager>().GetTimestamp()));
// 2.2 Check the Border Agent state
VerifyOrQuit(meshCoPServiceTester.mIsRunning == true);
VerifyOrQuit(meshCoPServiceTester.mUdpPort != 0);
}
} // namespace Nexus
} // namespace ot
@@ -744,6 +903,7 @@ int main(void)
{
ot::Nexus::TestBorderAgent();
ot::Nexus::TestBorderAgentEphemeralKey();
ot::Nexus::TestBorderAgentMeshCoPServiceChangedCallback();
printf("All tests passed\n");
return 0;
}