xref: /aosp_15_r20/external/openthread/src/posix/platform/trel.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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