mirror of
https://github.com/espressif/openthread.git
synced 2026-09-04 00:00:06 +00:00
[trel] introduce Trel::PeerDiscoverer class (#11493)
This commit introduces `PeerDiscoverer` as a class responsible for TREL peer discovery, separating this logic from `Trel::Interface`. The new class currently handles the preparation of TXT data, calling the platform API to register the TREL service, and handling callbacks from the platform layer with newly discovered or updated peer information. This separation helps with TREL module organization and enables future extensions, such as performing discovery using the native OpenThread mDNS module or the platform-specific DNS-SD (`otPlatDnssd`) module, in addition to the existing approach where discovery is delegated to the platform layer.
This commit is contained in:
@@ -619,6 +619,8 @@ openthread_core_files = [
|
||||
"radio/trel_packet.hpp",
|
||||
"radio/trel_peer.cpp",
|
||||
"radio/trel_peer.hpp",
|
||||
"radio/trel_peer_discoverer.cpp",
|
||||
"radio/trel_peer_discoverer.hpp",
|
||||
"thread/address_resolver.cpp",
|
||||
"thread/address_resolver.hpp",
|
||||
"thread/announce_begin_server.cpp",
|
||||
|
||||
@@ -204,6 +204,7 @@ set(COMMON_SOURCES
|
||||
radio/trel_link.cpp
|
||||
radio/trel_packet.cpp
|
||||
radio/trel_peer.cpp
|
||||
radio/trel_peer_discoverer.cpp
|
||||
thread/address_resolver.cpp
|
||||
thread/announce_begin_server.cpp
|
||||
thread/announce_sender.cpp
|
||||
|
||||
@@ -801,6 +801,8 @@ template <> inline Trel::Link &Instance::Get(void) { return mMac.mLinks.mTrel; }
|
||||
template <> inline Trel::Interface &Instance::Get(void) { return mMac.mLinks.mTrel.mInterface; }
|
||||
|
||||
template <> inline Trel::PeerTable &Instance::Get(void) { return mMac.mLinks.mTrel.mPeerTable; }
|
||||
|
||||
template <> inline Trel::PeerDiscoverer &Instance::Get(void) { return mMac.mLinks.mTrel.mPeerDiscoverer; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
|
||||
@@ -41,15 +41,11 @@ namespace Trel {
|
||||
|
||||
RegisterLogModule("TrelInterface");
|
||||
|
||||
const char Interface::kTxtRecordExtAddressKey[] = "xa";
|
||||
const char Interface::kTxtRecordExtPanIdKey[] = "xp";
|
||||
|
||||
Interface::Interface(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mInitialized(false)
|
||||
, mEnabled(false)
|
||||
, mFiltered(false)
|
||||
, mRegisterServiceTask(aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,9 +82,9 @@ void Interface::Enable(void)
|
||||
VerifyOrExit(mInitialized);
|
||||
|
||||
otPlatTrelEnable(&GetInstance(), &mUdpPort);
|
||||
Get<PeerDiscoverer>().Start();
|
||||
|
||||
LogInfo("Enabled interface, local port:%u", mUdpPort);
|
||||
mRegisterServiceTask.Post();
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -102,188 +98,14 @@ void Interface::Disable(void)
|
||||
VerifyOrExit(mInitialized);
|
||||
|
||||
otPlatTrelDisable(&GetInstance());
|
||||
Get<PeerTable>().Clear();
|
||||
Get<PeerDiscoverer>().Stop();
|
||||
|
||||
LogDebg("Disabled interface");
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interface::NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr, const Ip6::SockAddr &aRxSockAddr)
|
||||
{
|
||||
otPlatTrelNotifyPeerSocketAddressDifference(&GetInstance(), &aPeerSockAddr, &aRxSockAddr);
|
||||
}
|
||||
|
||||
void Interface::HandleExtAddressChange(void)
|
||||
{
|
||||
VerifyOrExit(mInitialized && mEnabled);
|
||||
LogDebg("Extended Address changed, re-registering DNS-SD service");
|
||||
mRegisterServiceTask.Post();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interface::HandleExtPanIdChange(void)
|
||||
{
|
||||
VerifyOrExit(mInitialized && mEnabled);
|
||||
LogDebg("Extended PAN ID changed, re-registering DNS-SD service");
|
||||
mRegisterServiceTask.Post();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interface::RegisterService(void)
|
||||
{
|
||||
// TXT data consists of two entries: the length fields, the
|
||||
// "key" string, "=" char, and binary representation of the MAC
|
||||
// or Extended PAN ID values.
|
||||
static constexpr uint8_t kTxtDataSize =
|
||||
/* ExtAddr */ sizeof(uint8_t) + sizeof(kTxtRecordExtAddressKey) - 1 + sizeof(char) + sizeof(Mac::ExtAddress) +
|
||||
/* ExtPanId */ sizeof(uint8_t) + sizeof(kTxtRecordExtPanIdKey) - 1 + sizeof(char) +
|
||||
sizeof(MeshCoP::ExtendedPanId);
|
||||
|
||||
uint8_t txtData[kTxtDataSize];
|
||||
Dns::TxtDataEncoder encoder(txtData, sizeof(txtData));
|
||||
|
||||
VerifyOrExit(mInitialized && mEnabled);
|
||||
|
||||
SuccessOrAssert(encoder.AppendEntry(kTxtRecordExtAddressKey, Get<Mac::Mac>().GetExtAddress()));
|
||||
SuccessOrAssert(encoder.AppendEntry(kTxtRecordExtPanIdKey, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
|
||||
|
||||
LogInfo("Registering DNS-SD service: port:%u, txt:\"%s=%s, %s=%s\"", mUdpPort, kTxtRecordExtAddressKey,
|
||||
Get<Mac::Mac>().GetExtAddress().ToString().AsCString(), kTxtRecordExtPanIdKey,
|
||||
Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId().ToString().AsCString());
|
||||
|
||||
otPlatTrelRegisterService(&GetInstance(), mUdpPort, txtData, static_cast<uint8_t>(encoder.GetLength()));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo)
|
||||
{
|
||||
Instance &instance = AsCoreType(aInstance);
|
||||
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
instance.Get<Interface>().HandleDiscoveredPeerInfo(*static_cast<const Interface::PeerInfo *>(aInfo));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interface::HandleDiscoveredPeerInfo(const PeerInfo &aInfo)
|
||||
{
|
||||
Peer *peer;
|
||||
Mac::ExtAddress extAddress;
|
||||
MeshCoP::ExtendedPanId extPanId;
|
||||
bool isNew = false;
|
||||
|
||||
VerifyOrExit(mInitialized && mEnabled);
|
||||
|
||||
SuccessOrExit(aInfo.ParseTxtData(extAddress, extPanId));
|
||||
|
||||
VerifyOrExit(extAddress != Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
if (aInfo.IsRemoved())
|
||||
{
|
||||
Get<PeerTable>().RemoveAndFreeAllMatching(extAddress);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// It is a new entry or an update to an existing entry. First
|
||||
// check whether we have an existing entry that matches the same
|
||||
// socket address, and remove it if it is associated with a
|
||||
// different Extended MAC address. This ensures that we do not
|
||||
// keep stale entries in the peer table.
|
||||
|
||||
peer = Get<PeerTable>().FindMatching(aInfo.GetSockAddr());
|
||||
|
||||
if ((peer != nullptr) && !peer->Matches(extAddress))
|
||||
{
|
||||
Get<PeerTable>().RemoveMatching(aInfo.GetSockAddr());
|
||||
peer = nullptr;
|
||||
}
|
||||
|
||||
if (peer == nullptr)
|
||||
{
|
||||
peer = Get<PeerTable>().FindMatching(extAddress);
|
||||
}
|
||||
|
||||
if (peer == nullptr)
|
||||
{
|
||||
peer = Get<PeerTable>().AllocateAndAddNewPeer();
|
||||
VerifyOrExit(peer != nullptr);
|
||||
|
||||
peer->SetExtAddress(extAddress);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
VerifyOrExit((peer->GetExtPanId() != extPanId) || (peer->GetSockAddr() != aInfo.GetSockAddr()));
|
||||
}
|
||||
|
||||
peer->SetExtPanId(extPanId);
|
||||
peer->SetSockAddr(aInfo.GetSockAddr());
|
||||
|
||||
peer->Log(isNew ? Peer::kAdded : Peer::kUpdated);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Error Interface::PeerInfo::ParseTxtData(Mac::ExtAddress &aExtAddress, MeshCoP::ExtendedPanId &aExtPanId) const
|
||||
{
|
||||
Error error;
|
||||
Dns::TxtEntry entry;
|
||||
Dns::TxtEntry::Iterator iterator;
|
||||
bool parsedExtAddress = false;
|
||||
bool parsedExtPanId = false;
|
||||
|
||||
aExtPanId.Clear();
|
||||
|
||||
iterator.Init(mTxtData, mTxtLength);
|
||||
|
||||
while ((error = iterator.GetNextEntry(entry)) == kErrorNone)
|
||||
{
|
||||
// If the TXT data happens to have entries with key longer
|
||||
// than `kMaxIterKeyLength`, `mKey` would be `nullptr` and full
|
||||
// entry would be placed in `mValue`. We skip over such
|
||||
// entries.
|
||||
if (entry.mKey == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StringMatch(entry.mKey, kTxtRecordExtAddressKey))
|
||||
{
|
||||
VerifyOrExit(!parsedExtAddress, error = kErrorParse);
|
||||
VerifyOrExit(entry.mValueLength >= sizeof(Mac::ExtAddress), error = kErrorParse);
|
||||
aExtAddress.Set(entry.mValue);
|
||||
parsedExtAddress = true;
|
||||
}
|
||||
else if (StringMatch(entry.mKey, kTxtRecordExtPanIdKey))
|
||||
{
|
||||
VerifyOrExit(!parsedExtPanId, error = kErrorParse);
|
||||
VerifyOrExit(entry.mValueLength >= sizeof(MeshCoP::ExtendedPanId), error = kErrorParse);
|
||||
memcpy(aExtPanId.m8, entry.mValue, sizeof(MeshCoP::ExtendedPanId));
|
||||
parsedExtPanId = true;
|
||||
}
|
||||
|
||||
// Skip over and ignore any unknown keys.
|
||||
}
|
||||
|
||||
VerifyOrExit(error == kErrorNotFound);
|
||||
error = kErrorNone;
|
||||
|
||||
VerifyOrExit(parsedExtAddress && parsedExtPanId, error = kErrorParse);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
const Counters *Interface::GetCounters(void) const { return otPlatTrelGetCounters(&GetInstance()); }
|
||||
|
||||
void Interface::ResetCounters(void) { otPlatTrelResetCounters(&GetInstance()); }
|
||||
|
||||
@@ -41,26 +41,19 @@
|
||||
#include <openthread/trel.h>
|
||||
#include <openthread/platform/trel.h>
|
||||
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/pool.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
#include "common/time.hpp"
|
||||
#include "net/socket.hpp"
|
||||
#include "radio/trel_packet.hpp"
|
||||
#include "radio/trel_peer.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
class Link;
|
||||
class Interface;
|
||||
|
||||
extern "C" void otPlatTrelHandleReceived(otInstance *aInstance,
|
||||
uint8_t *aBuffer,
|
||||
uint16_t aLength,
|
||||
const otSockAddr *aSenderAddr);
|
||||
extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo);
|
||||
|
||||
/**
|
||||
* Represents a group of TREL counters.
|
||||
*/
|
||||
@@ -76,7 +69,6 @@ class Interface : public InstanceLocator
|
||||
uint8_t *aBuffer,
|
||||
uint16_t aLength,
|
||||
const otSockAddr *aSenderAddr);
|
||||
friend void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo);
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -152,54 +144,21 @@ public:
|
||||
*/
|
||||
uint16_t GetUdpPort(void) const { return mUdpPort; }
|
||||
|
||||
/**
|
||||
* Notifies platform that a TREL packet is received from a peer using a different socket address than the one
|
||||
* reported earlier.
|
||||
*
|
||||
* @param[in] aPeerSockAddr The previously reported peer sock addr.
|
||||
* @param[in] aRxSockAddr The address of received packet from the same peer.
|
||||
*/
|
||||
void NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr, const Ip6::SockAddr &aRxSockAddr);
|
||||
|
||||
private:
|
||||
#if OPENTHREAD_CONFIG_TREL_PEER_TABLE_SIZE != 0
|
||||
static constexpr uint16_t kPeerPoolSize = OPENTHREAD_CONFIG_TREL_PEER_TABLE_SIZE;
|
||||
#else
|
||||
static constexpr uint16_t kExtraEntries = 32;
|
||||
static constexpr uint16_t kPeerPoolSize = Mle::kMaxRouters + Mle::kMaxChildren + kExtraEntries;
|
||||
#endif
|
||||
static const char kTxtRecordExtAddressKey[];
|
||||
static const char kTxtRecordExtPanIdKey[];
|
||||
|
||||
struct PeerInfo : public otPlatTrelPeerInfo
|
||||
{
|
||||
bool IsRemoved(void) const { return mRemoved; }
|
||||
const Ip6::SockAddr &GetSockAddr(void) const { return AsCoreType(&mSockAddr); }
|
||||
Error ParseTxtData(Mac::ExtAddress &aExtAddress, MeshCoP::ExtendedPanId &aExtPanId) const;
|
||||
};
|
||||
|
||||
explicit Interface(Instance &aInstance);
|
||||
|
||||
// Methods used by `Trel::Link`.
|
||||
void Init(void);
|
||||
void HandleExtAddressChange(void);
|
||||
void HandleExtPanIdChange(void);
|
||||
Error Send(const Packet &aPacket, bool aIsDiscovery = false);
|
||||
|
||||
// Callbacks from `otPlatTrel`.
|
||||
void HandleReceived(uint8_t *aBuffer, uint16_t aLength, const Ip6::SockAddr &aSenderAddr);
|
||||
void HandleDiscoveredPeerInfo(const PeerInfo &aInfo);
|
||||
|
||||
void RegisterService(void);
|
||||
|
||||
using RegisterServiceTask = TaskletIn<Interface, &Interface::RegisterService>;
|
||||
|
||||
bool mInitialized : 1;
|
||||
bool mEnabled : 1;
|
||||
bool mFiltered : 1;
|
||||
RegisterServiceTask mRegisterServiceTask;
|
||||
uint16_t mUdpPort;
|
||||
Packet mRxPacket;
|
||||
bool mInitialized : 1;
|
||||
bool mEnabled : 1;
|
||||
bool mFiltered : 1;
|
||||
uint16_t mUdpPort;
|
||||
Packet mRxPacket;
|
||||
};
|
||||
|
||||
} // namespace Trel
|
||||
|
||||
@@ -51,6 +51,7 @@ Link::Link(Instance &aInstance)
|
||||
, mTimer(aInstance)
|
||||
, mInterface(aInstance)
|
||||
, mPeerTable(aInstance)
|
||||
, mPeerDiscoverer(aInstance)
|
||||
{
|
||||
ClearAllBytes(mTxFrame);
|
||||
ClearAllBytes(mRxFrame);
|
||||
@@ -409,7 +410,7 @@ void Link::CheckPeerAddrOnRxSuccess(PeerSockAddrUpdateMode aMode)
|
||||
mRxPacketPeer->SetSockAddr(mRxPacketSenderAddr);
|
||||
}
|
||||
|
||||
Get<Interface>().NotifyPeerSocketAddressDifference(prevSockAddr, mRxPacketSenderAddr);
|
||||
mPeerDiscoverer.NotifyPeerSocketAddressDifference(prevSockAddr, mRxPacketSenderAddr);
|
||||
|
||||
exit:
|
||||
mRxPacketPeer = nullptr;
|
||||
@@ -496,7 +497,7 @@ void Link::HandleNotifierEvents(Events aEvents)
|
||||
{
|
||||
if (aEvents.Contains(kEventThreadExtPanIdChanged))
|
||||
{
|
||||
mInterface.HandleExtPanIdChange();
|
||||
mPeerDiscoverer.HandleExtPanIdChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "radio/trel_interface.hpp"
|
||||
#include "radio/trel_packet.hpp"
|
||||
#include "radio/trel_peer.hpp"
|
||||
#include "radio/trel_peer_discoverer.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -105,7 +106,7 @@ public:
|
||||
* Notifies TREL radio link that device's extended MAC address has changed for it to update any
|
||||
* internal address/state.
|
||||
*/
|
||||
void HandleExtAddressChange(void) { mInterface.HandleExtAddressChange(); }
|
||||
void HandleExtAddressChange(void) { mPeerDiscoverer.HandleExtAddressChange(); }
|
||||
|
||||
/**
|
||||
* Enables the TREL radio link.
|
||||
@@ -193,21 +194,22 @@ private:
|
||||
using TxTasklet = TaskletIn<Link, &Link::HandleTxTasklet>;
|
||||
using TimeoutTimer = TimerMilliIn<Link, &Link::HandleTimer>;
|
||||
|
||||
State mState;
|
||||
uint8_t mRxChannel;
|
||||
Mac::PanId mPanId;
|
||||
uint32_t mTxPacketNumber;
|
||||
TxTasklet mTxTasklet;
|
||||
TimeoutTimer mTimer;
|
||||
Interface mInterface;
|
||||
PeerTable mPeerTable;
|
||||
Ip6::SockAddr mRxPacketSenderAddr;
|
||||
Peer *mRxPacketPeer;
|
||||
Mac::RxFrame mRxFrame;
|
||||
Mac::TxFrame mTxFrame;
|
||||
uint8_t mTxPacketBuffer[kMaxHeaderSize + kMtuSize];
|
||||
uint8_t mAckPacketBuffer[kMaxHeaderSize];
|
||||
uint8_t mAckFrameBuffer[k154AckFrameSize];
|
||||
State mState;
|
||||
uint8_t mRxChannel;
|
||||
Mac::PanId mPanId;
|
||||
uint32_t mTxPacketNumber;
|
||||
TxTasklet mTxTasklet;
|
||||
TimeoutTimer mTimer;
|
||||
Interface mInterface;
|
||||
PeerTable mPeerTable;
|
||||
PeerDiscoverer mPeerDiscoverer;
|
||||
Ip6::SockAddr mRxPacketSenderAddr;
|
||||
Peer *mRxPacketPeer;
|
||||
Mac::RxFrame mRxFrame;
|
||||
Mac::TxFrame mTxFrame;
|
||||
uint8_t mTxPacketBuffer[kMaxHeaderSize + kMtuSize];
|
||||
uint8_t mAckPacketBuffer[kMaxHeaderSize];
|
||||
uint8_t mAckFrameBuffer[k154AckFrameSize];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,8 +59,8 @@ class NeighborTable;
|
||||
|
||||
namespace Trel {
|
||||
|
||||
class Interface;
|
||||
class PeerTable;
|
||||
class PeerDiscoverer;
|
||||
|
||||
/**
|
||||
* Represents a discovered TREL peer.
|
||||
@@ -74,8 +74,8 @@ class Peer : public InstanceLocatorInit,
|
||||
private NonCopyable
|
||||
|
||||
{
|
||||
friend class Interface;
|
||||
friend class PeerTable;
|
||||
friend class PeerDiscoverer;
|
||||
friend class OwnedPtr<Peer>;
|
||||
friend class OwningList<Peer>;
|
||||
friend class LinkedList<Peer>;
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements Thread Radio Encapsulation Link (TREL) peer discovery.
|
||||
*/
|
||||
|
||||
#include "trel_peer_discoverer.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
RegisterLogModule("TrelDiscoverer");
|
||||
|
||||
const char PeerDiscoverer::kTxtRecordExtAddressKey[] = "xa";
|
||||
const char PeerDiscoverer::kTxtRecordExtPanIdKey[] = "xp";
|
||||
|
||||
PeerDiscoverer::PeerDiscoverer(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mIsRunning(false)
|
||||
, mRegisterServiceTask(aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
void PeerDiscoverer::Start(void)
|
||||
{
|
||||
VerifyOrExit(!mIsRunning);
|
||||
|
||||
mIsRunning = true;
|
||||
PostRegisterServiceTask();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PeerDiscoverer::Stop(void)
|
||||
{
|
||||
VerifyOrExit(mIsRunning);
|
||||
|
||||
mIsRunning = false;
|
||||
Get<PeerTable>().Clear();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PeerDiscoverer::NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr,
|
||||
const Ip6::SockAddr &aRxSockAddr)
|
||||
{
|
||||
otPlatTrelNotifyPeerSocketAddressDifference(&GetInstance(), &aPeerSockAddr, &aRxSockAddr);
|
||||
}
|
||||
|
||||
void PeerDiscoverer::PostRegisterServiceTask(void)
|
||||
{
|
||||
if (mIsRunning)
|
||||
{
|
||||
mRegisterServiceTask.Post();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerDiscoverer::RegisterService(void)
|
||||
{
|
||||
// TXT data consists of two entries: the length fields, the
|
||||
// "key" string, "=" char, and binary representation of the MAC
|
||||
// or Extended PAN ID values.
|
||||
static constexpr uint8_t kTxtDataSize =
|
||||
/* ExtAddr */ sizeof(uint8_t) + sizeof(kTxtRecordExtAddressKey) - 1 + sizeof(char) + sizeof(Mac::ExtAddress) +
|
||||
/* ExtPanId */ sizeof(uint8_t) + sizeof(kTxtRecordExtPanIdKey) - 1 + sizeof(char) +
|
||||
sizeof(MeshCoP::ExtendedPanId);
|
||||
|
||||
uint8_t txtData[kTxtDataSize];
|
||||
Dns::TxtDataEncoder encoder(txtData, sizeof(txtData));
|
||||
uint16_t port;
|
||||
|
||||
VerifyOrExit(mIsRunning);
|
||||
|
||||
port = Get<Interface>().GetUdpPort();
|
||||
|
||||
SuccessOrAssert(encoder.AppendEntry(kTxtRecordExtAddressKey, Get<Mac::Mac>().GetExtAddress()));
|
||||
SuccessOrAssert(encoder.AppendEntry(kTxtRecordExtPanIdKey, Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
|
||||
|
||||
LogInfo("Registering DNS-SD service: port:%u, txt:\"%s=%s, %s=%s\"", port, kTxtRecordExtAddressKey,
|
||||
Get<Mac::Mac>().GetExtAddress().ToString().AsCString(), kTxtRecordExtPanIdKey,
|
||||
Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId().ToString().AsCString());
|
||||
|
||||
otPlatTrelRegisterService(&GetInstance(), port, txtData, static_cast<uint8_t>(encoder.GetLength()));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo)
|
||||
{
|
||||
Instance &instance = AsCoreType(aInstance);
|
||||
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
instance.Get<PeerDiscoverer>().HandleDiscoveredPeerInfo(*static_cast<const PeerDiscoverer::PeerInfo *>(aInfo));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PeerDiscoverer::HandleDiscoveredPeerInfo(const PeerInfo &aInfo)
|
||||
{
|
||||
Peer *peer;
|
||||
Mac::ExtAddress extAddress;
|
||||
MeshCoP::ExtendedPanId extPanId;
|
||||
bool isNew = false;
|
||||
|
||||
VerifyOrExit(mIsRunning);
|
||||
|
||||
SuccessOrExit(aInfo.ParseTxtData(extAddress, extPanId));
|
||||
|
||||
VerifyOrExit(extAddress != Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
if (aInfo.IsRemoved())
|
||||
{
|
||||
Get<PeerTable>().RemoveAndFreeAllMatching(extAddress);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// It is a new entry or an update to an existing entry. First
|
||||
// check whether we have an existing entry that matches the same
|
||||
// socket address, and remove it if it is associated with a
|
||||
// different Extended MAC address. This ensures that we do not
|
||||
// keep stale entries in the peer table.
|
||||
|
||||
peer = Get<PeerTable>().FindMatching(aInfo.GetSockAddr());
|
||||
|
||||
if ((peer != nullptr) && !peer->Matches(extAddress))
|
||||
{
|
||||
Get<PeerTable>().RemoveMatching(aInfo.GetSockAddr());
|
||||
peer = nullptr;
|
||||
}
|
||||
|
||||
if (peer == nullptr)
|
||||
{
|
||||
peer = Get<PeerTable>().FindMatching(extAddress);
|
||||
}
|
||||
|
||||
if (peer == nullptr)
|
||||
{
|
||||
peer = Get<PeerTable>().AllocateAndAddNewPeer();
|
||||
VerifyOrExit(peer != nullptr);
|
||||
|
||||
peer->SetExtAddress(extAddress);
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
VerifyOrExit((peer->GetExtPanId() != extPanId) || (peer->GetSockAddr() != aInfo.GetSockAddr()));
|
||||
}
|
||||
|
||||
peer->SetExtPanId(extPanId);
|
||||
peer->SetSockAddr(aInfo.GetSockAddr());
|
||||
|
||||
peer->Log(isNew ? Peer::kAdded : Peer::kUpdated);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Error PeerDiscoverer::PeerInfo::ParseTxtData(Mac::ExtAddress &aExtAddress, MeshCoP::ExtendedPanId &aExtPanId) const
|
||||
{
|
||||
Error error;
|
||||
Dns::TxtEntry entry;
|
||||
Dns::TxtEntry::Iterator iterator;
|
||||
bool parsedExtAddress = false;
|
||||
bool parsedExtPanId = false;
|
||||
|
||||
aExtPanId.Clear();
|
||||
|
||||
iterator.Init(mTxtData, mTxtLength);
|
||||
|
||||
while ((error = iterator.GetNextEntry(entry)) == kErrorNone)
|
||||
{
|
||||
// If the TXT data happens to have entries with key longer
|
||||
// than `kMaxIterKeyLength`, `mKey` would be `nullptr` and full
|
||||
// entry would be placed in `mValue`. We skip over such
|
||||
// entries.
|
||||
if (entry.mKey == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StringMatch(entry.mKey, kTxtRecordExtAddressKey))
|
||||
{
|
||||
VerifyOrExit(!parsedExtAddress, error = kErrorParse);
|
||||
VerifyOrExit(entry.mValueLength >= sizeof(Mac::ExtAddress), error = kErrorParse);
|
||||
aExtAddress.Set(entry.mValue);
|
||||
parsedExtAddress = true;
|
||||
}
|
||||
else if (StringMatch(entry.mKey, kTxtRecordExtPanIdKey))
|
||||
{
|
||||
VerifyOrExit(!parsedExtPanId, error = kErrorParse);
|
||||
VerifyOrExit(entry.mValueLength >= sizeof(MeshCoP::ExtendedPanId), error = kErrorParse);
|
||||
memcpy(aExtPanId.m8, entry.mValue, sizeof(MeshCoP::ExtendedPanId));
|
||||
parsedExtPanId = true;
|
||||
}
|
||||
|
||||
// Skip over and ignore any unknown keys.
|
||||
}
|
||||
|
||||
VerifyOrExit(error == kErrorNotFound);
|
||||
error = kErrorNone;
|
||||
|
||||
VerifyOrExit(parsedExtAddress && parsedExtPanId, error = kErrorParse);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2019-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread Radio Encapsulation Link (TREL) peer discovery.
|
||||
*/
|
||||
|
||||
#ifndef TREL_PEER_DISCOVERER_HPP_
|
||||
#define TREL_PEER_DISCOVERER_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#include <openthread/platform/trel.h>
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
#include "radio/trel_peer.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
class Link;
|
||||
|
||||
extern "C" void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo);
|
||||
|
||||
/**
|
||||
* Represents a TREL module responsible for peer discovery and mDNS service registration.
|
||||
*/
|
||||
class PeerDiscoverer : public InstanceLocator
|
||||
{
|
||||
friend class Link;
|
||||
friend void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Starts the peer discovery.
|
||||
*/
|
||||
void Start(void);
|
||||
|
||||
/**
|
||||
* Stops the peer discovery and clears the peer table.
|
||||
*/
|
||||
void Stop(void);
|
||||
|
||||
/**
|
||||
* Notifies that device's Extended MAC Address has changed.
|
||||
*/
|
||||
void HandleExtAddressChange(void) { PostRegisterServiceTask(); }
|
||||
|
||||
/**
|
||||
* Notifies that device's Extended PAN Identifier has changed.
|
||||
*/
|
||||
void HandleExtPanIdChange(void) { PostRegisterServiceTask(); }
|
||||
|
||||
/**
|
||||
* Notifies that a TREL packet is received from a peer using a different socket address than the one reported
|
||||
* earlier.
|
||||
*
|
||||
* @param[in] aPeerSockAddr The previously reported peer sock address.
|
||||
* @param[in] aRxSockAddr The address of received packet from the same peer.
|
||||
*/
|
||||
void NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr, const Ip6::SockAddr &aRxSockAddr);
|
||||
|
||||
private:
|
||||
static const char kTxtRecordExtAddressKey[];
|
||||
static const char kTxtRecordExtPanIdKey[];
|
||||
|
||||
struct PeerInfo : public otPlatTrelPeerInfo
|
||||
{
|
||||
bool IsRemoved(void) const { return mRemoved; }
|
||||
const Ip6::SockAddr &GetSockAddr(void) const { return AsCoreType(&mSockAddr); }
|
||||
Error ParseTxtData(Mac::ExtAddress &aExtAddress, MeshCoP::ExtendedPanId &aExtPanId) const;
|
||||
};
|
||||
|
||||
explicit PeerDiscoverer(Instance &aInstance);
|
||||
|
||||
void HandleDiscoveredPeerInfo(const PeerInfo &aInfo);
|
||||
void PostRegisterServiceTask(void);
|
||||
void RegisterService(void);
|
||||
|
||||
using RegisterServiceTask = TaskletIn<PeerDiscoverer, &PeerDiscoverer::RegisterService>;
|
||||
|
||||
bool mIsRunning;
|
||||
RegisterServiceTask mRegisterServiceTask;
|
||||
};
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_PEER_DISCOVERER_HPP_
|
||||
Reference in New Issue
Block a user