1 /*
2 * Copyright (c) 2019-2021, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements platform for TREL using IPv6/UDP socket under POSIX.
32 */
33
34 #include "openthread-posix-config.h"
35
36 #include "platform-posix.h"
37
38 #include <arpa/inet.h>
39 #include <assert.h>
40 #include <fcntl.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <unistd.h>
44
45 #include <openthread/logging.h>
46 #include <openthread/openthread-system.h>
47 #include <openthread/platform/trel.h>
48
49 #include "logger.hpp"
50 #include "radio_url.hpp"
51 #include "system.hpp"
52 #include "common/code_utils.hpp"
53
54 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
55
56 static constexpr uint16_t kMaxPacketSize = 1400; // The max size of a TREL packet.
57
58 typedef struct TxPacket
59 {
60 struct TxPacket *mNext;
61 uint8_t mBuffer[kMaxPacketSize];
62 uint16_t mLength;
63 otSockAddr mDestSockAddr;
64 } TxPacket;
65
66 static uint8_t sRxPacketBuffer[kMaxPacketSize];
67 static uint16_t sRxPacketLength;
68 static TxPacket sTxPacketPool[OPENTHREAD_POSIX_CONFIG_TREL_TX_PACKET_POOL_SIZE];
69 static TxPacket *sFreeTxPacketHead; // A singly linked list of free/available `TxPacket` from pool.
70 static TxPacket *sTxPacketQueueTail; // A circular linked list for queued tx packets.
71 static otPlatTrelCounters sCounters;
72
73 static char sInterfaceName[IFNAMSIZ + 1];
74 static bool sInitialized = false;
75 static bool sEnabled = false;
76 static int sSocket = -1;
77
78 static const char kLogModuleName[] = "Trel";
79
LogCrit(const char * aFormat,...)80 static void LogCrit(const char *aFormat, ...)
81 {
82 va_list args;
83
84 va_start(args, aFormat);
85 otLogPlatArgs(OT_LOG_LEVEL_CRIT, kLogModuleName, aFormat, args);
86 va_end(args);
87 }
88
LogWarn(const char * aFormat,...)89 static void LogWarn(const char *aFormat, ...)
90 {
91 va_list args;
92
93 va_start(args, aFormat);
94 otLogPlatArgs(OT_LOG_LEVEL_WARN, kLogModuleName, aFormat, args);
95 va_end(args);
96 }
97
LogNote(const char * aFormat,...)98 static void LogNote(const char *aFormat, ...)
99 {
100 va_list args;
101
102 va_start(args, aFormat);
103 otLogPlatArgs(OT_LOG_LEVEL_NOTE, kLogModuleName, aFormat, args);
104 va_end(args);
105 }
106
LogInfo(const char * aFormat,...)107 static void LogInfo(const char *aFormat, ...)
108 {
109 va_list args;
110
111 va_start(args, aFormat);
112 otLogPlatArgs(OT_LOG_LEVEL_INFO, kLogModuleName, aFormat, args);
113 va_end(args);
114 }
115
LogDebg(const char * aFormat,...)116 static void LogDebg(const char *aFormat, ...)
117 {
118 va_list args;
119
120 va_start(args, aFormat);
121 otLogPlatArgs(OT_LOG_LEVEL_DEBG, kLogModuleName, aFormat, args);
122 va_end(args);
123 }
124
Ip6AddrToString(const void * aAddress)125 static const char *Ip6AddrToString(const void *aAddress)
126 {
127 static char string[INET6_ADDRSTRLEN];
128 return inet_ntop(AF_INET6, aAddress, string, sizeof(string));
129 }
130
BufferToString(const uint8_t * aBuffer,uint16_t aLength)131 static const char *BufferToString(const uint8_t *aBuffer, uint16_t aLength)
132 {
133 const uint16_t kMaxWrite = 16;
134 static char string[1600];
135
136 uint16_t num = 0;
137 char *cur = &string[0];
138 char *end = &string[sizeof(string) - 1];
139
140 cur += snprintf(cur, (uint16_t)(end - cur), "[(len:%d) ", aLength);
141 VerifyOrExit(cur < end);
142
143 while (aLength-- && (num < kMaxWrite))
144 {
145 cur += snprintf(cur, (uint16_t)(end - cur), "%02x ", *aBuffer++);
146 VerifyOrExit(cur < end);
147
148 num++;
149 }
150
151 if (aLength != 0)
152 {
153 cur += snprintf(cur, (uint16_t)(end - cur), "... ");
154 VerifyOrExit(cur < end);
155 }
156
157 *cur++ = ']';
158 VerifyOrExit(cur < end);
159
160 *cur = '\0';
161
162 exit:
163 *end = '\0';
164 return string;
165 }
166
PrepareSocket(uint16_t & aUdpPort)167 static void PrepareSocket(uint16_t &aUdpPort)
168 {
169 int val;
170 struct sockaddr_in6 sockAddr;
171 socklen_t sockLen;
172
173 LogDebg("PrepareSocket()");
174
175 sSocket = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, 0, kSocketNonBlock);
176 VerifyOrDie(sSocket >= 0, OT_EXIT_ERROR_ERRNO);
177
178 // Make the socket non-blocking to allow immediate tx attempt.
179 val = fcntl(sSocket, F_GETFL, 0);
180 VerifyOrDie(val != -1, OT_EXIT_ERROR_ERRNO);
181 val = val | O_NONBLOCK;
182 VerifyOrDie(fcntl(sSocket, F_SETFL, val) == 0, OT_EXIT_ERROR_ERRNO);
183
184 // Bind the socket.
185
186 memset(&sockAddr, 0, sizeof(sockAddr));
187 sockAddr.sin6_family = AF_INET6;
188 sockAddr.sin6_addr = in6addr_any;
189 sockAddr.sin6_port = OPENTHREAD_POSIX_CONFIG_TREL_UDP_PORT;
190
191 if (bind(sSocket, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) == -1)
192 {
193 LogCrit("Failed to bind socket");
194 DieNow(OT_EXIT_ERROR_ERRNO);
195 }
196
197 #ifdef __linux__
198 // Bind to the TREL interface
199 if (setsockopt(sSocket, SOL_SOCKET, SO_BINDTODEVICE, sInterfaceName, strlen(sInterfaceName)) < 0)
200 {
201 LogCrit("Failed to bind socket to the interface %s", sInterfaceName);
202 DieNow(OT_EXIT_ERROR_ERRNO);
203 }
204 #endif
205
206 sockLen = sizeof(sockAddr);
207
208 if (getsockname(sSocket, (struct sockaddr *)&sockAddr, &sockLen) == -1)
209 {
210 LogCrit("Failed to get the socket name");
211 DieNow(OT_EXIT_ERROR_ERRNO);
212 }
213
214 aUdpPort = ntohs(sockAddr.sin6_port);
215 }
216
SendPacket(const uint8_t * aBuffer,uint16_t aLength,const otSockAddr * aDestSockAddr)217 static otError SendPacket(const uint8_t *aBuffer, uint16_t aLength, const otSockAddr *aDestSockAddr)
218 {
219 otError error = OT_ERROR_NONE;
220 struct sockaddr_in6 sockAddr;
221 ssize_t ret;
222
223 VerifyOrExit(sSocket >= 0, error = OT_ERROR_INVALID_STATE);
224
225 memset(&sockAddr, 0, sizeof(sockAddr));
226 sockAddr.sin6_family = AF_INET6;
227 sockAddr.sin6_port = htons(aDestSockAddr->mPort);
228 memcpy(&sockAddr.sin6_addr, &aDestSockAddr->mAddress, sizeof(otIp6Address));
229
230 ret = sendto(sSocket, aBuffer, aLength, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
231
232 if (ret != aLength)
233 {
234 LogDebg("SendPacket() -- sendto() failed errno %d", errno);
235
236 switch (errno)
237 {
238 case ENETUNREACH:
239 case ENETDOWN:
240 case EHOSTUNREACH:
241 error = OT_ERROR_ABORT;
242 break;
243
244 default:
245 error = OT_ERROR_INVALID_STATE;
246 }
247 }
248 else
249 {
250 ++sCounters.mTxPackets;
251 sCounters.mTxBytes += aLength;
252 }
253
254 exit:
255 LogDebg("SendPacket([%s]:%u) err:%s pkt:%s", Ip6AddrToString(&aDestSockAddr->mAddress), aDestSockAddr->mPort,
256 otThreadErrorToString(error), BufferToString(aBuffer, aLength));
257 if (error != OT_ERROR_NONE)
258 {
259 ++sCounters.mTxFailure;
260 }
261 return error;
262 }
263
ReceivePacket(int aSocket,otInstance * aInstance)264 static void ReceivePacket(int aSocket, otInstance *aInstance)
265 {
266 struct sockaddr_in6 sockAddr;
267 socklen_t sockAddrLen = sizeof(sockAddr);
268 ssize_t ret;
269
270 memset(&sockAddr, 0, sizeof(sockAddr));
271
272 ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr,
273 &sockAddrLen);
274 VerifyOrDie(ret >= 0, OT_EXIT_ERROR_ERRNO);
275
276 sRxPacketLength = (uint16_t)(ret);
277
278 if (sRxPacketLength > sizeof(sRxPacketBuffer))
279 {
280 sRxPacketLength = sizeof(sRxPacketLength);
281 }
282
283 LogDebg("ReceivePacket() - received from [%s]:%d, id:%d, pkt:%s", Ip6AddrToString(&sockAddr.sin6_addr),
284 ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id, BufferToString(sRxPacketBuffer, sRxPacketLength));
285
286 if (sEnabled)
287 {
288 ++sCounters.mRxPackets;
289 sCounters.mRxBytes += sRxPacketLength;
290 otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength);
291 }
292 }
293
InitPacketQueue(void)294 static void InitPacketQueue(void)
295 {
296 sTxPacketQueueTail = NULL;
297
298 // Chain all the packets in pool in the free linked list.
299 sFreeTxPacketHead = NULL;
300
301 for (uint16_t index = 0; index < OT_ARRAY_LENGTH(sTxPacketPool); index++)
302 {
303 TxPacket *packet = &sTxPacketPool[index];
304
305 packet->mNext = sFreeTxPacketHead;
306 sFreeTxPacketHead = packet;
307 }
308 }
309
SendQueuedPackets(void)310 static void SendQueuedPackets(void)
311 {
312 while (sTxPacketQueueTail != NULL)
313 {
314 TxPacket *packet = sTxPacketQueueTail->mNext; // tail->mNext is the head of the list.
315
316 if (SendPacket(packet->mBuffer, packet->mLength, &packet->mDestSockAddr) == OT_ERROR_INVALID_STATE)
317 {
318 LogDebg("SendQueuedPackets() - SendPacket() would block");
319 break;
320 }
321
322 // Remove the `packet` from the packet queue (circular
323 // linked list).
324
325 if (packet == sTxPacketQueueTail)
326 {
327 sTxPacketQueueTail = NULL;
328 }
329 else
330 {
331 sTxPacketQueueTail->mNext = packet->mNext;
332 }
333
334 // Add the `packet` to the free packet singly linked list.
335
336 packet->mNext = sFreeTxPacketHead;
337 sFreeTxPacketHead = packet;
338 }
339 }
340
EnqueuePacket(const uint8_t * aBuffer,uint16_t aLength,const otSockAddr * aDestSockAddr)341 static void EnqueuePacket(const uint8_t *aBuffer, uint16_t aLength, const otSockAddr *aDestSockAddr)
342 {
343 TxPacket *packet;
344
345 // Allocate an available packet entry (from the free packet list)
346 // and copy the packet content into it.
347
348 VerifyOrExit(sFreeTxPacketHead != NULL, LogWarn("EnqueuePacket failed, queue is full"));
349 packet = sFreeTxPacketHead;
350 sFreeTxPacketHead = sFreeTxPacketHead->mNext;
351
352 memcpy(packet->mBuffer, aBuffer, aLength);
353 packet->mLength = aLength;
354 packet->mDestSockAddr = *aDestSockAddr;
355
356 // Add packet to the tail of TxPacketQueue circular linked-list.
357
358 if (sTxPacketQueueTail == NULL)
359 {
360 packet->mNext = packet;
361 sTxPacketQueueTail = packet;
362 }
363 else
364 {
365 packet->mNext = sTxPacketQueueTail->mNext;
366 sTxPacketQueueTail->mNext = packet;
367 sTxPacketQueueTail = packet;
368 }
369
370 LogDebg("EnqueuePacket([%s]:%u) - %s", Ip6AddrToString(&aDestSockAddr->mAddress), aDestSockAddr->mPort,
371 BufferToString(aBuffer, aLength));
372
373 exit:
374 return;
375 }
376
ResetCounters()377 static void ResetCounters() { memset(&sCounters, 0, sizeof(sCounters)); }
378
379 //---------------------------------------------------------------------------------------------------------------------
380 // trelDnssd
381 //
382 // The functions below are tied to mDNS or DNS-SD library being used on
383 // a device and need to be implemented per project/platform. A weak empty
384 // implementation is provided here which describes the expected
385 // behavior. They need to be overridden during project/platform
386 // integration.
387
trelDnssdInitialize(const char * aTrelNetif)388 OT_TOOL_WEAK void trelDnssdInitialize(const char *aTrelNetif)
389 {
390 // This function initialize the TREL DNS-SD module on the given
391 // TREL Network Interface.
392
393 OT_UNUSED_VARIABLE(aTrelNetif);
394 }
395
trelDnssdStartBrowse(void)396 OT_TOOL_WEAK void trelDnssdStartBrowse(void)
397 {
398 // This function initiates an ongoing DNS-SD browse on the service
399 // name "_trel._udp" within the local browsing domain to discover
400 // other devices supporting TREL. The ongoing browse will produce
401 // two different types of events: `add` events and `remove` events.
402 // When the browse is started, it should produce an `add` event for
403 // every TREL peer currently present on the network. Whenever a
404 // TREL peer goes offline, a "remove" event should be produced.
405 // `Remove` events are not guaranteed, however. When a TREL service
406 // instance is discovered, a new ongoing DNS-SD query for an AAAA
407 // record MUST be started on the hostname indicated in the SRV
408 // record of the discovered instance. If multiple host IPv6
409 // addressees are discovered for a peer, one with highest scope
410 // among all addresses MUST be reported (if there are multiple
411 // address at same scope, one must be selected randomly).
412 //
413 // The platform MUST signal back the discovered peer info using
414 // `otPlatTrelHandleDiscoveredPeerInfo()` callback. This callback
415 // MUST be invoked when a new peer is discovered, or when there is
416 // a change in an existing entry (e.g., new TXT record or new port
417 // number or new IPv6 address), or when the peer is removed.
418 }
419
trelDnssdStopBrowse(void)420 OT_TOOL_WEAK void trelDnssdStopBrowse(void)
421 {
422 // This function stops the ongoing DNS-SD browse started from an
423 // earlier call to `trelDnssdStartBrowse()`.
424 }
425
trelDnssdRegisterService(uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)426 OT_TOOL_WEAK void trelDnssdRegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
427 {
428 // This function registers a new service to be advertised using
429 // DNS-SD.
430 //
431 // The service name is "_trel._udp". The platform should use its own
432 // hostname, which when combined with the service name and the
433 // local DNS-SD domain name will produce the full service instance
434 // name, for example "example-host._trel._udp.local.".
435 //
436 // The domain under which the service instance name appears will
437 // be 'local' for mDNS, and will be whatever domain is used for
438 // service registration in the case of a non-mDNS local DNS-SD
439 // service.
440 //
441 // A subsequent call to this function updates the previous service.
442 // It is used to update the TXT record data and/or the port
443 // number.
444 //
445 // The `aTxtData` buffer is not persisted after the return from this
446 // function. The platform layer MUST not keep the pointer and
447 // instead copy the content if needed.
448
449 OT_UNUSED_VARIABLE(aPort);
450 OT_UNUSED_VARIABLE(aTxtData);
451 OT_UNUSED_VARIABLE(aTxtLength);
452 }
453
trelDnssdRemoveService(void)454 OT_TOOL_WEAK void trelDnssdRemoveService(void)
455 {
456 // This function removes any previously registered "_trel._udp"
457 // service using `platTrelRegisterService()`. Device must stop
458 // advertising TREL service after this call.
459 }
460
trelDnssdUpdateFdSet(otSysMainloopContext * aContext)461 OT_TOOL_WEAK void trelDnssdUpdateFdSet(otSysMainloopContext *aContext)
462 {
463 // This function can be used to update the file descriptor sets
464 // by DNS-SD layer (if needed).
465
466 OT_UNUSED_VARIABLE(aContext);
467 }
468
trelDnssdProcess(otInstance * aInstance,const otSysMainloopContext * aContext)469 OT_TOOL_WEAK void trelDnssdProcess(otInstance *aInstance, const otSysMainloopContext *aContext)
470 {
471 // This function performs processing by DNS-SD (if needed).
472
473 OT_UNUSED_VARIABLE(aInstance);
474 OT_UNUSED_VARIABLE(aContext);
475 }
476
477 //---------------------------------------------------------------------------------------------------------------------
478 // otPlatTrel
479
otPlatTrelEnable(otInstance * aInstance,uint16_t * aUdpPort)480 void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort)
481 {
482 OT_UNUSED_VARIABLE(aInstance);
483
484 VerifyOrExit(!IsSystemDryRun());
485
486 VerifyOrExit(sInitialized && !sEnabled);
487
488 PrepareSocket(*aUdpPort);
489 trelDnssdStartBrowse();
490
491 sEnabled = true;
492
493 exit:
494 return;
495 }
496
otPlatTrelDisable(otInstance * aInstance)497 void otPlatTrelDisable(otInstance *aInstance)
498 {
499 OT_UNUSED_VARIABLE(aInstance);
500
501 VerifyOrExit(!IsSystemDryRun());
502
503 VerifyOrExit(sInitialized && sEnabled);
504
505 close(sSocket);
506 sSocket = -1;
507 trelDnssdStopBrowse();
508 trelDnssdRemoveService();
509 sEnabled = false;
510
511 exit:
512 return;
513 }
514
otPlatTrelSend(otInstance * aInstance,const uint8_t * aUdpPayload,uint16_t aUdpPayloadLen,const otSockAddr * aDestSockAddr)515 void otPlatTrelSend(otInstance *aInstance,
516 const uint8_t *aUdpPayload,
517 uint16_t aUdpPayloadLen,
518 const otSockAddr *aDestSockAddr)
519 {
520 OT_UNUSED_VARIABLE(aInstance);
521
522 VerifyOrExit(!IsSystemDryRun());
523
524 VerifyOrExit(sEnabled);
525
526 assert(aUdpPayloadLen <= kMaxPacketSize);
527
528 // We try to send the packet immediately. If it fails (e.g.,
529 // network is down) `SendPacket()` returns `OT_ERROR_ABORT`. If
530 // the send operation would block (e.g., socket is not yet ready
531 // or is out of buffer) we get `OT_ERROR_INVALID_STATE`. In that
532 // case we enqueue the packet to send it later when socket becomes
533 // ready.
534
535 if ((sTxPacketQueueTail != NULL) ||
536 (SendPacket(aUdpPayload, aUdpPayloadLen, aDestSockAddr) == OT_ERROR_INVALID_STATE))
537 {
538 EnqueuePacket(aUdpPayload, aUdpPayloadLen, aDestSockAddr);
539 }
540
541 exit:
542 return;
543 }
544
otPlatTrelRegisterService(otInstance * aInstance,uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)545 void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
546 {
547 OT_UNUSED_VARIABLE(aInstance);
548 VerifyOrExit(!IsSystemDryRun());
549
550 VerifyOrExit(sEnabled);
551
552 trelDnssdRegisterService(aPort, aTxtData, aTxtLength);
553
554 exit:
555 return;
556 }
557
558 // We keep counters at the platform layer because TREL failures can only be captured accurately within
559 // the platform layer as the platform sometimes only queues the packet and the packet will be sent later
560 // and the error is only known after sent.
otPlatTrelGetCounters(otInstance * aInstance)561 const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance)
562 {
563 OT_UNUSED_VARIABLE(aInstance);
564 return &sCounters;
565 }
566
otPlatTrelResetCounters(otInstance * aInstance)567 void otPlatTrelResetCounters(otInstance *aInstance)
568 {
569 OT_UNUSED_VARIABLE(aInstance);
570 ResetCounters();
571 }
572
otSysTrelInit(const char * aInterfaceName)573 void otSysTrelInit(const char *aInterfaceName)
574 {
575 // To silence "unused function" warning.
576 (void)LogCrit;
577 (void)LogWarn;
578 (void)LogInfo;
579 (void)LogNote;
580 (void)LogDebg;
581
582 LogDebg("otSysTrelInit(aInterfaceName:\"%s\")", aInterfaceName != nullptr ? aInterfaceName : "");
583
584 VerifyOrExit(!sInitialized && !sEnabled && aInterfaceName != nullptr);
585
586 strncpy(sInterfaceName, aInterfaceName, sizeof(sInterfaceName) - 1);
587 sInterfaceName[sizeof(sInterfaceName) - 1] = '\0';
588
589 trelDnssdInitialize(sInterfaceName);
590
591 InitPacketQueue();
592 sInitialized = true;
593
594 ResetCounters();
595
596 exit:
597 return;
598 }
599
otSysTrelDeinit(void)600 void otSysTrelDeinit(void) { platformTrelDeinit(); }
601
602 //---------------------------------------------------------------------------------------------------------------------
603 // platformTrel system
604
platformTrelInit(const char * aTrelUrl)605 void platformTrelInit(const char *aTrelUrl)
606 {
607 LogDebg("platformTrelInit(aTrelUrl:\"%s\")", aTrelUrl != nullptr ? aTrelUrl : "");
608
609 if (aTrelUrl != nullptr)
610 {
611 ot::Posix::RadioUrl url(aTrelUrl);
612
613 otSysTrelInit(url.GetPath());
614 }
615 }
616
platformTrelDeinit(void)617 void platformTrelDeinit(void)
618 {
619 VerifyOrExit(sInitialized && !sEnabled);
620
621 sInterfaceName[0] = '\0';
622 sInitialized = false;
623 LogDebg("platformTrelDeinit()");
624
625 exit:
626 return;
627 }
628
platformTrelUpdateFdSet(otSysMainloopContext * aContext)629 void platformTrelUpdateFdSet(otSysMainloopContext *aContext)
630 {
631 assert(aContext != nullptr);
632
633 VerifyOrExit(sEnabled);
634
635 FD_SET(sSocket, &aContext->mReadFdSet);
636
637 if (sTxPacketQueueTail != nullptr)
638 {
639 FD_SET(sSocket, &aContext->mWriteFdSet);
640 }
641
642 if (aContext->mMaxFd < sSocket)
643 {
644 aContext->mMaxFd = sSocket;
645 }
646
647 trelDnssdUpdateFdSet(aContext);
648
649 exit:
650 return;
651 }
652
platformTrelProcess(otInstance * aInstance,const otSysMainloopContext * aContext)653 void platformTrelProcess(otInstance *aInstance, const otSysMainloopContext *aContext)
654 {
655 VerifyOrExit(sEnabled);
656
657 if (FD_ISSET(sSocket, &aContext->mWriteFdSet))
658 {
659 SendQueuedPackets();
660 }
661
662 if (FD_ISSET(sSocket, &aContext->mReadFdSet))
663 {
664 ReceivePacket(sSocket, aInstance);
665 }
666
667 trelDnssdProcess(aInstance, aContext);
668
669 exit:
670 return;
671 }
672
673 #endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
674