Skip to content

Commit d1147d6

Browse files
authored
[trel] detect and handle socket addr discrepancy for TREL peers (openthread#10869)
This commit introduces a new mechanism for the TREL link to detect and handle discrepancies between the IPv6 address and port used by a TREL peer in a received TREL packet, and the information previously reported by the platform layer (through DNS-SD discovery) for the same peer. Ideally, the platform underlying DNS-SD should detect changes to advertised ports and addresses by peers. However, there are situations where this is not detected reliably. As a received frame over the TREL radio link is processed by the MAC or MLE layers, if the frame passes receive security checks at either layer (indicating it is a secure and authenticated/fresh frame from a valid neighbor), the TREL peer socket address is automatically updated from the received TREL packet info. This ensures the TREL peer table is updated correctly if there are changes to TREL peer addresses of valid Thread neighbors upon rx from such neighbor, increasing the robustness of the TREL link. This commit also introduces a new `otPlatTrel` platform API, `otPlatTrelNotifyPeerSocketAddressDifference()`. The TREL implementation now notifies the platform layer whenever it detects a discrepancy in a TREL peer's socket address, regardless of whether the peer table is automatically updated. This allows the platform layer to take any appropriate action, such as restarting or confirming DNS-SD service resolution query for the peer service instance and/or address resolution query for its associated host name. This commit also adds a new test that validates the newly added behavior, including the auto-update of peer table information and notification of the platform through the new API, triggered by either MLE or MAC messages over the TREL radio link.
1 parent c34484d commit d1147d6

File tree

17 files changed

+547
-41
lines changed

17 files changed

+547
-41
lines changed

examples/apps/cli/main.c

+6
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ static otError ProcessExit(void *aContext, uint8_t aArgsLength, char *aArgs[])
7272

7373
#if OPENTHREAD_EXAMPLES_SIMULATION
7474
extern otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[]);
75+
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
76+
extern otError ProcessTrelTest(void *aContext, uint8_t aArgsLength, char *aArgs[]);
77+
#endif
7578
#endif
7679

7780
static const otCliCommand kCommands[] = {
@@ -92,6 +95,9 @@ static const otCliCommand kCommands[] = {
9295
* - `nodeidfilter` : Outputs filter mode (allow-list or deny-list) and filtered node IDs.
9396
*/
9497
{"nodeidfilter", ProcessNodeIdFilter},
98+
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
99+
{"treltest", ProcessTrelTest},
100+
#endif
95101
#endif
96102
};
97103
#endif // OPENTHREAD_POSIX && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)

examples/platforms/simulation/trel.c

+95-9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include "platform-simulation.h"
3030

31+
#include <openthread/ip6.h>
3132
#include <openthread/random_noncrypto.h>
3233
#include <openthread/platform/trel.h>
3334

@@ -60,6 +61,7 @@ typedef struct Message
6061
{
6162
MessageType mType;
6263
otSockAddr mSockAddr; // Destination (when TREL_DATA_MESSAGE), or peer addr (when DNS-SD service)
64+
otSockAddr mSourceAddr; // Source address (used when TREL_DATA_MESSAGE)
6365
uint16_t mDataLength; // mData length
6466
uint8_t mData[TREL_MAX_PACKET_SIZE]; // TREL UDP packet (when TREL_DATA_MESSAGE), or service TXT data.
6567
} Message;
@@ -70,12 +72,13 @@ static Message sPendingTx[TREL_MAX_PENDING_TX];
7072
static utilsSocket sSocket;
7173
static uint16_t sPortOffset = 0;
7274
static bool sEnabled = false;
75+
static otSockAddr sSockAddr;
7376

7477
static bool sServiceRegistered = false;
75-
static uint16_t sServicePort;
7678
static uint8_t sServiceTxtLength;
7779
static char sServiceTxtData[TREL_MAX_SERVICE_TXT_DATA_LEN];
7880
static otPlatTrelCounters sCounters;
81+
static uint16_t sNotifyAddressDiffCounter = 0;
7982

8083
#if DEBUG_LOG
8184
static void dumpBuffer(const void *aBuffer, uint16_t aLength)
@@ -158,15 +161,14 @@ static void sendServiceMessage(MessageType aType)
158161
assert(sNumPendingTx < TREL_MAX_PENDING_TX);
159162
message = &sPendingTx[sNumPendingTx++];
160163

161-
message->mType = aType;
162-
memset(&message->mSockAddr, 0, sizeof(otSockAddr));
163-
message->mSockAddr.mPort = sServicePort;
164-
message->mDataLength = sServiceTxtLength;
164+
message->mType = aType;
165+
message->mSockAddr = sSockAddr;
166+
message->mDataLength = sServiceTxtLength;
165167
memcpy(message->mData, sServiceTxtData, sServiceTxtLength);
166168

167169
#if DEBUG_LOG
168170
fprintf(stderr, "\r\n[trel-sim] sendServiceMessage(%s): service-port:%u, txt-len:%u\r\n",
169-
aType == TREL_DNSSD_ADD_SERVICE_MESSAGE ? "add" : "remove", sServicePort, sServiceTxtLength);
171+
aType == TREL_DNSSD_ADD_SERVICE_MESSAGE ? "add" : "remove", sSockAddr.mPort, sServiceTxtLength);
170172
#endif
171173
}
172174

@@ -186,7 +188,8 @@ static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aL
186188
{
187189
case TREL_DATA_MESSAGE:
188190
otEXPECT(aMessage->mSockAddr.mPort == sSocket.mPort);
189-
otPlatTrelHandleReceived(aInstance, aMessage->mData, aMessage->mDataLength);
191+
otEXPECT(otIp6IsAddressEqual(&aMessage->mSockAddr.mAddress, &sSockAddr.mAddress));
192+
otPlatTrelHandleReceived(aInstance, aMessage->mData, aMessage->mDataLength, &aMessage->mSourceAddr);
190193
break;
191194

192195
case TREL_DNSSD_BROWSE_MESSAGE:
@@ -248,6 +251,21 @@ void otPlatTrelDisable(otInstance *aInstance)
248251
}
249252
}
250253

254+
void otPlatTrelNotifyPeerSocketAddressDifference(otInstance *aInstance,
255+
const otSockAddr *aPeerSockAddr,
256+
const otSockAddr *aRxSockAddr)
257+
{
258+
OT_UNUSED_VARIABLE(aInstance);
259+
OT_UNUSED_VARIABLE(aPeerSockAddr);
260+
OT_UNUSED_VARIABLE(aRxSockAddr);
261+
262+
sNotifyAddressDiffCounter++;
263+
264+
#if DEBUG_LOG
265+
fprintf(stderr, "\r\n[trel-sim] otPlatTrelNotifyPeerSocketAddressDifference()\r\n");
266+
#endif
267+
}
268+
251269
void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
252270
{
253271
OT_UNUSED_VARIABLE(aInstance);
@@ -260,7 +278,7 @@ void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint
260278
}
261279

262280
sServiceRegistered = true;
263-
sServicePort = aPort;
281+
sSockAddr.mPort = aPort;
264282
sServiceTxtLength = aTxtLength;
265283
memcpy(sServiceTxtData, aTxtData, aTxtLength);
266284

@@ -289,6 +307,7 @@ void otPlatTrelSend(otInstance *aInstance,
289307

290308
message->mType = TREL_DATA_MESSAGE;
291309
message->mSockAddr = *aDestSockAddr;
310+
message->mSourceAddr = sSockAddr;
292311
message->mDataLength = aUdpPayloadLen;
293312
memcpy(message->mData, aUdpPayload, aUdpPayloadLen);
294313

@@ -325,6 +344,10 @@ void platformTrelInit(uint32_t aSpeedUpFactor)
325344

326345
utilsInitSocket(&sSocket, TREL_SIM_PORT + sPortOffset);
327346

347+
memset(&sSockAddr, 0, sizeof(otSockAddr));
348+
sSockAddr.mAddress.mFields.m32[3] = gNodeId;
349+
sSockAddr.mPort = sSocket.mPort;
350+
328351
OT_UNUSED_VARIABLE(aSpeedUpFactor);
329352
}
330353

@@ -378,14 +401,59 @@ void otPlatTrelResetCounters(otInstance *aInstance)
378401
memset(&sCounters, 0, sizeof(sCounters));
379402
}
380403

404+
//---------------------------------------------------------------------------------------------------------------------
405+
// CLI `treltest` command
406+
407+
OT_TOOL_WEAK void otCliOutputFormat(const char *aFmt, ...) { OT_UNUSED_VARIABLE(aFmt); }
408+
409+
otError ProcessTrelTest(void *aContext, uint8_t aArgsLength, char *aArgs[])
410+
{
411+
OT_UNUSED_VARIABLE(aContext);
412+
413+
otError error = OT_ERROR_NONE;
414+
415+
otEXPECT_ACTION(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
416+
417+
if (!strcmp(aArgs[0], "sockaddr"))
418+
{
419+
char string[OT_IP6_SOCK_ADDR_STRING_SIZE];
420+
421+
otIp6SockAddrToString(&sSockAddr, string, sizeof(string));
422+
otCliOutputFormat("%s\r\n", string);
423+
}
424+
else if (!strcmp(aArgs[0], "changesockaddr"))
425+
{
426+
sSockAddr.mAddress.mFields.m32[2]++;
427+
}
428+
else if (!strcmp(aArgs[0], "changesockport"))
429+
{
430+
sSockAddr.mPort++;
431+
}
432+
else if (!strcmp(aArgs[0], "notifyaddrcounter"))
433+
{
434+
otCliOutputFormat("%u\r\n", sNotifyAddressDiffCounter);
435+
}
436+
else
437+
{
438+
error = OT_ERROR_INVALID_COMMAND;
439+
}
440+
441+
exit:
442+
return error;
443+
}
444+
381445
//---------------------------------------------------------------------------------------------------------------------
382446

383447
// This is added for RCP build to be built ok
384-
OT_TOOL_WEAK void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
448+
OT_TOOL_WEAK void otPlatTrelHandleReceived(otInstance *aInstance,
449+
uint8_t *aBuffer,
450+
uint16_t aLength,
451+
const otSockAddr *aSenderAddr)
385452
{
386453
OT_UNUSED_VARIABLE(aInstance);
387454
OT_UNUSED_VARIABLE(aBuffer);
388455
OT_UNUSED_VARIABLE(aLength);
456+
OT_UNUSED_VARIABLE(aSenderAddr);
389457

390458
assert(false);
391459
}
@@ -398,4 +466,22 @@ OT_TOOL_WEAK void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, cons
398466
assert(false);
399467
}
400468

469+
OT_TOOL_WEAK void otIp6SockAddrToString(const otSockAddr *aSockAddr, char *aBuffer, uint16_t aSize)
470+
{
471+
OT_UNUSED_VARIABLE(aSockAddr);
472+
OT_UNUSED_VARIABLE(aBuffer);
473+
OT_UNUSED_VARIABLE(aSize);
474+
475+
assert(false);
476+
}
477+
478+
OT_TOOL_WEAK bool otIp6IsAddressEqual(const otIp6Address *aFirst, const otIp6Address *aSecond)
479+
{
480+
OT_UNUSED_VARIABLE(aFirst);
481+
OT_UNUSED_VARIABLE(aSecond);
482+
483+
assert(false);
484+
return false;
485+
}
486+
401487
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE

include/openthread/instance.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
*
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*/
55-
#define OPENTHREAD_API_VERSION (467)
55+
#define OPENTHREAD_API_VERSION (468)
5656

5757
/**
5858
* @addtogroup api-instance

include/openthread/platform/trel.h

+22-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ typedef struct otPlatTrelPeerInfo
135135
*/
136136
extern void otPlatTrelHandleDiscoveredPeerInfo(otInstance *aInstance, const otPlatTrelPeerInfo *aInfo);
137137

138+
/**
139+
* Notifies platform that a TREL packet is received from a peer using a different socket address than the one reported
140+
* earlier from `otPlatTrelHandleDiscoveredPeerInfo()`.
141+
*
142+
* Ideally the platform underlying DNS-SD should detect changes to advertised port and addresses by peers, however,
143+
* there are situations where this is not detected reliably. This function signals to the platform layer than we
144+
* received a packet from a peer with it using a different port or address. This can be used by the playroom layer to
145+
* restart/confirm the DNS-SD service/address resolution for the peer service and/or take any other relevant actions.
146+
*
147+
* @param[in] aInstance The OpenThread instance.
148+
* @param[in] aPeerSockAddr The address of the peer, reported from `otPlatTrelHandleDiscoveredPeerInfo()` call.
149+
* @param[in] aRxSockAddr The address of received packet from the same peer (differs from @p aPeerSockAddr).
150+
*/
151+
void otPlatTrelNotifyPeerSocketAddressDifference(otInstance *aInstance,
152+
const otSockAddr *aPeerSockAddr,
153+
const otSockAddr *aRxSockAddr);
154+
138155
/**
139156
* Registers a new service to be advertised using DNS-SD [RFC6763].
140157
*
@@ -181,8 +198,12 @@ void otPlatTrelSend(otInstance *aInstance,
181198
* @param[in] aInstance The OpenThread instance structure.
182199
* @param[in] aBuffer A buffer containing the received UDP payload.
183200
* @param[in] aLength UDP payload length (number of bytes).
201+
* @param[in] aSockAddr The sender address.
184202
*/
185-
extern void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength);
203+
extern void otPlatTrelHandleReceived(otInstance *aInstance,
204+
uint8_t *aBuffer,
205+
uint16_t aLength,
206+
const otSockAddr *aSenderAddr);
186207

187208
/**
188209
* Represents a group of TREL related counters in the platform layer.

src/core/mac/mac.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,30 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError)
21392139
break;
21402140
}
21412141
}
2142+
2143+
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
2144+
#if OPENTHREAD_CONFIG_MULTI_RADIO
2145+
if (aFrame->GetRadioType() == kRadioTypeTrel)
2146+
#endif
2147+
{
2148+
if (error == kErrorNone)
2149+
{
2150+
// If the received frame is using TREL and is successfully
2151+
// processed, check for any discrepancy between the socket
2152+
// address of the received TREL packet and the information
2153+
// saved in the corresponding TREL peer, and signal this to
2154+
// the platform layer.
2155+
//
2156+
// If the frame used link security and was successfully
2157+
// processed, we allow the `Peer` entry socket information
2158+
// to be updated directly.
2159+
2160+
Get<Trel::Link>().CheckPeerAddrOnRxSuccess(aFrame->GetSecurityEnabled()
2161+
? Trel::Link::kAllowPeerSockAddrUpdate
2162+
: Trel::Link::kDisallowPeerSockAddrUpdate);
2163+
}
2164+
}
2165+
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
21422166
}
21432167

21442168
void Mac::UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame)

src/core/radio/trel_interface.cpp

+18-5
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ void Interface::Disable(void)
109109
return;
110110
}
111111

112+
Interface::Peer *Interface::FindPeer(const Mac::ExtAddress &aExtAddress)
113+
{
114+
return mPeerTable.FindMatching(aExtAddress);
115+
}
116+
117+
void Interface::NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr, const Ip6::SockAddr &aRxSockAddr)
118+
{
119+
otPlatTrelNotifyPeerSocketAddressDifference(&GetInstance(), &aPeerSockAddr, &aRxSockAddr);
120+
}
121+
112122
void Interface::HandleExtAddressChange(void)
113123
{
114124
VerifyOrExit(mInitialized && mEnabled);
@@ -188,7 +198,7 @@ void Interface::HandleDiscoveredPeerInfo(const Peer::Info &aInfo)
188198

189199
if (aInfo.IsRemoved())
190200
{
191-
entry = mPeerTable.FindMatching(extAddress);
201+
entry = FindPeer(extAddress);
192202
VerifyOrExit(entry != nullptr);
193203
RemovePeerEntry(*entry);
194204
ExitNow();
@@ -380,25 +390,28 @@ Error Interface::Send(const Packet &aPacket, bool aIsDiscovery)
380390
return error;
381391
}
382392

383-
extern "C" void otPlatTrelHandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
393+
extern "C" void otPlatTrelHandleReceived(otInstance *aInstance,
394+
uint8_t *aBuffer,
395+
uint16_t aLength,
396+
const otSockAddr *aSenderAddress)
384397
{
385398
Instance &instance = AsCoreType(aInstance);
386399

387400
VerifyOrExit(instance.IsInitialized());
388-
instance.Get<Interface>().HandleReceived(aBuffer, aLength);
401+
instance.Get<Interface>().HandleReceived(aBuffer, aLength, AsCoreType(aSenderAddress));
389402

390403
exit:
391404
return;
392405
}
393406

394-
void Interface::HandleReceived(uint8_t *aBuffer, uint16_t aLength)
407+
void Interface::HandleReceived(uint8_t *aBuffer, uint16_t aLength, const Ip6::SockAddr &aSenderAddr)
395408
{
396409
LogDebg("HandleReceived(aLength:%u)", aLength);
397410

398411
VerifyOrExit(mInitialized && mEnabled && !mFiltered);
399412

400413
mRxPacket.Init(aBuffer, aLength);
401-
Get<Link>().ProcessReceivedPacket(mRxPacket);
414+
Get<Link>().ProcessReceivedPacket(mRxPacket, aSenderAddr);
402415

403416
exit:
404417
return;

0 commit comments

Comments
 (0)