1 /*
2  *  Copyright (c) 2019, 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 #if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET && !defined(__linux__)
39 #error "netlink socket use is only supported on linux platform"
40 #endif
41 
42 #include <arpa/inet.h>
43 #include <assert.h>
44 #include <fcntl.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <unistd.h>
50 #if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
51 #include <linux/if_tun.h>
52 #include <linux/netlink.h>
53 #include <linux/rtnetlink.h>
54 #endif
55 
56 #include <openthread/platform/trel-udp6.h>
57 
58 #include "common/code_utils.hpp"
59 #include "common/logging.hpp"
60 #include "posix/platform/radio_url.hpp"
61 
62 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
63 
64 #define TREL_MAX_PACKET_SIZE 1400
65 #define TREL_PACKET_POOL_SIZE 5
66 
67 #define USEC_PER_MSEC 1000u
68 #define TREL_SOCKET_BIND_MAX_WAIT_TIME_MSEC 4000u
69 
70 #define TREL_UNICAST_ADDRESS_PREFIX_LEN 64
71 #define TREL_UNICAST_ADDRESS_SCOPE 2 // The unicast address is link-local
72 
73 typedef struct TxPacket
74 {
75     struct TxPacket *mNext;
76     uint8_t          mBuffer[TREL_MAX_PACKET_SIZE];
77     uint16_t         mLength;
78     otIp6Address     mDestAddress;
79 } TxPacket;
80 
81 static uint8_t      sRxPacketBuffer[TREL_MAX_PACKET_SIZE];
82 static uint16_t     sRxPacketLength;
83 static TxPacket     sTxPacketPool[TREL_PACKET_POOL_SIZE];
84 static TxPacket *   sFreeTxPacketHead;  // A singly linked list of free/available `TxPacket` from pool.
85 static TxPacket *   sTxPacketQueueTail; // A circular linked list for queued tx packets.
86 static char         sInterfaceName[IFNAMSIZ + 1];
87 static bool         sInitialized     = false;
88 static bool         sEnabled         = false;
89 static int          sInterfaceIndex  = -1;
90 static int          sMulticastSocket = -1;
91 static int          sSocket          = -1;
92 static uint16_t     sUdpPort         = 0;
93 static otIp6Address sInterfaceAddress;
94 
95 #if OPENTHREAD_CONFIG_LOG_PLATFORM
96 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_CRIT)
Ip6AddrToString(const void * aAddress)97 static const char *Ip6AddrToString(const void *aAddress)
98 {
99     static char string[INET6_ADDRSTRLEN];
100     return inet_ntop(AF_INET6, aAddress, string, sizeof(string));
101 }
102 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_CRIT)
103 
104 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG)
BufferToString(const uint8_t * aBuffer,uint16_t aLength)105 static const char *BufferToString(const uint8_t *aBuffer, uint16_t aLength)
106 {
107     const uint16_t kMaxWrite = 16;
108     static char    string[1600];
109 
110     uint16_t num = 0;
111     char *   cur = &string[0];
112     char *   end = &string[sizeof(string) - 1];
113 
114     cur += snprintf(cur, (uint16_t)(end - cur), "[(len:%d) ", aLength);
115     VerifyOrExit(cur < end);
116 
117     while (aLength-- && (num < kMaxWrite))
118     {
119         cur += snprintf(cur, (uint16_t)(end - cur), "%02x ", *aBuffer++);
120         VerifyOrExit(cur < end);
121 
122         num++;
123     }
124 
125     if (aLength != 0)
126     {
127         cur += snprintf(cur, (uint16_t)(end - cur), "... ");
128         VerifyOrExit(cur < end);
129     }
130 
131     *cur++ = ']';
132     VerifyOrExit(cur < end);
133 
134     *cur++ = '\0';
135 
136 exit:
137     *end = '\0';
138     return string;
139 }
140 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG)
141 #endif // OPENTHREAD_CONFIG_LOG_PLATFORM
142 
143 #if OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
144 
UpdateUnicastAddress(const otIp6Address * aUnicastAddress,bool aToAdd)145 static void UpdateUnicastAddress(const otIp6Address *aUnicastAddress, bool aToAdd)
146 {
147     int            netlinkSocket;
148     int            ret;
149     struct rtattr *rta;
150 
151     struct
152     {
153         struct nlmsghdr  nh;
154         struct ifaddrmsg ifa;
155         char             buf[64];
156     } request;
157 
158     netlinkSocket = SocketWithCloseExec(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, kSocketNonBlock);
159     VerifyOrDie(netlinkSocket >= 0, OT_EXIT_ERROR_ERRNO);
160 
161     memset(&request, 0, sizeof(request));
162 
163     request.nh.nlmsg_len   = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
164     request.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
165     request.nh.nlmsg_type  = aToAdd ? RTM_NEWADDR : RTM_DELADDR;
166     request.nh.nlmsg_pid   = 0;
167     request.nh.nlmsg_seq   = 0;
168 
169     request.ifa.ifa_family    = AF_INET6;
170     request.ifa.ifa_prefixlen = TREL_UNICAST_ADDRESS_PREFIX_LEN;
171     request.ifa.ifa_flags     = IFA_F_NODAD;
172     request.ifa.ifa_scope     = TREL_UNICAST_ADDRESS_SCOPE;
173     request.ifa.ifa_index     = (unsigned int)(sInterfaceIndex);
174 
175     rta = reinterpret_cast<struct rtattr *>((reinterpret_cast<char *>(&request)) + NLMSG_ALIGN(request.nh.nlmsg_len));
176     rta->rta_type = IFA_LOCAL;
177     rta->rta_len  = RTA_LENGTH(sizeof(otIp6Address));
178 
179     memcpy(RTA_DATA(rta), aUnicastAddress, sizeof(otIp6Address));
180 
181     request.nh.nlmsg_len = NLMSG_ALIGN(request.nh.nlmsg_len) + rta->rta_len;
182 
183     ret = send(netlinkSocket, &request, request.nh.nlmsg_len, 0);
184     VerifyOrDie(ret != -1, OT_EXIT_ERROR_ERRNO);
185 
186     close(netlinkSocket);
187 }
188 
AddUnicastAddress(const otIp6Address * aUnicastAddress)189 static void AddUnicastAddress(const otIp6Address *aUnicastAddress)
190 {
191     otLogDebgPlat("[trel] AddUnicastAddress(%s)", Ip6AddrToString(aUnicastAddress));
192     UpdateUnicastAddress(aUnicastAddress, /* aToAdd */ true);
193 }
194 
RemoveUnicastAddress(const otIp6Address * aUnicastAddress)195 static void RemoveUnicastAddress(const otIp6Address *aUnicastAddress)
196 {
197     otLogDebgPlat("[trel] RemoveUnicastAddress(%s)", Ip6AddrToString(aUnicastAddress));
198     UpdateUnicastAddress(aUnicastAddress, /* aToAdd */ false);
199 }
200 
201 #else // OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
202 
AddUnicastAddress(const otIp6Address * aUnicastAddress)203 static void AddUnicastAddress(const otIp6Address *aUnicastAddress)
204 {
205     int mgmtFd;
206     int ret;
207     struct in6_ifreq
208     {
209         struct in6_addr ifr6_addr;
210         uint32_t        ifr6_prefixlen;
211         int             ifr6_ifindex;
212     } ifr6;
213 
214     otLogDebgPlat("[trel] AddUnicastAddress(%s)", Ip6AddrToString(aUnicastAddress));
215 
216     mgmtFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
217     VerifyOrDie(mgmtFd >= 0, OT_EXIT_ERROR_ERRNO);
218 
219     memcpy(&ifr6.ifr6_addr, aUnicastAddress, sizeof(otIp6Address));
220     ifr6.ifr6_prefixlen = 64;
221     ifr6.ifr6_ifindex   = sInterfaceIndex;
222 
223     ret = ioctl(mgmtFd, SIOCSIFADDR, &ifr6);
224 
225     if (!(ret == 0 || errno == EALREADY || errno == EEXIST))
226     {
227         otLogCritPlat("[trel] Failed to add unicast address %s on TREL netif \"%s\"", Ip6AddrToString(aUnicastAddress),
228                       sInterfaceName);
229         DieNow(OT_EXIT_ERROR_ERRNO);
230     }
231 
232     close(mgmtFd);
233 }
234 
RemoveUnicastAddress(const otIp6Address * aUnicastAddress)235 static void RemoveUnicastAddress(const otIp6Address *aUnicastAddress)
236 {
237     int mgmtFd;
238     int ret;
239     struct in6_ifreq
240     {
241         struct in6_addr ifr6_addr;
242         uint32_t        ifr6_prefixlen;
243         int             ifr6_ifindex;
244     } ifr6;
245 
246     otLogDebgPlat("[trel] RemoveUnicastAddress(%s)", Ip6AddrToString(aUnicastAddress));
247 
248     mgmtFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
249     VerifyOrDie(mgmtFd >= 0, OT_EXIT_ERROR_ERRNO);
250 
251     memcpy(&ifr6.ifr6_addr, aUnicastAddress, sizeof(otIp6Address));
252     ifr6.ifr6_prefixlen = 64;
253     ifr6.ifr6_ifindex   = sInterfaceIndex;
254 
255     ret = ioctl(mgmtFd, SIOCDIFADDR, &ifr6);
256 
257     VerifyOrDie(ret == 0, OT_EXIT_ERROR_ERRNO);
258 
259     close(mgmtFd);
260 }
261 
262 #endif // OPENTHREAD_CONFIG_POSIX_TREL_USE_NETLINK_SOCKET
263 
PrepareSocket(void)264 static void PrepareSocket(void)
265 {
266     int                 val;
267     struct sockaddr_in6 sockAddr;
268     uint64_t            startTime;
269     bool                isSocketBound = false;
270 
271     otLogDebgPlat("[trel] PrepareSocket()");
272 
273     sSocket = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, 0, kSocketNonBlock);
274     VerifyOrDie(sSocket >= 0, OT_EXIT_ERROR_ERRNO);
275 
276     // Set the multicast interface index (for tx), disable loop back
277     // of multicast tx and set the multicast hop limit to 1 to reach
278     // a single sub-net.
279 
280     val = sInterfaceIndex;
281     VerifyOrDie(setsockopt(sSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
282 
283     val = 0;
284     VerifyOrDie(setsockopt(sSocket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
285 
286     val = 1;
287     VerifyOrDie(setsockopt(sSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
288     VerifyOrDie(setsockopt(sSocket, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
289 
290     val = 1;
291     VerifyOrDie(setsockopt(sSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
292 
293     // Make the socket non-blocking to allow immediate tx attempt.
294     val = fcntl(sSocket, F_GETFL, 0);
295     VerifyOrDie(val != -1, OT_EXIT_ERROR_ERRNO);
296     val = val | O_NONBLOCK;
297     VerifyOrDie(fcntl(sSocket, F_SETFL, val) == 0, OT_EXIT_ERROR_ERRNO);
298 
299     // Bind the socket. The address to which we want to bind the
300     // socket, is itself added earlier above. The address therefore
301     // may not be immediately available/ready on the interface and the
302     // socket `bind()` call may fail with `EADDRNOTAVAIL` error. In
303     // such a case, we keep trying up to a maximum wait time.
304 
305     memset(&sockAddr, 0, sizeof(sockAddr));
306     sockAddr.sin6_family = AF_INET6;
307     sockAddr.sin6_port   = htons(sUdpPort);
308     memcpy(&sockAddr.sin6_addr, &sInterfaceAddress, sizeof(otIp6Address));
309     sockAddr.sin6_scope_id = (uint32_t)sInterfaceIndex;
310 
311     startTime = otPlatTimeGet();
312 
313     while (otPlatTimeGet() - startTime < TREL_SOCKET_BIND_MAX_WAIT_TIME_MSEC * USEC_PER_MSEC)
314     {
315         if (bind(sSocket, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) != -1)
316         {
317             isSocketBound = true;
318             break;
319         }
320 
321         if (errno == EADDRNOTAVAIL)
322         {
323             continue;
324         }
325 
326         otLogCritPlat("[trel] Failed to bind socket to %s (port %d) on TREL netif \"%s\"",
327                       Ip6AddrToString(&sInterfaceAddress), sUdpPort, sInterfaceName);
328         DieNow(OT_EXIT_ERROR_ERRNO);
329     }
330 
331     if (!isSocketBound)
332     {
333         otLogCritPlat("[trel] Timed out waiting for address %s to become available for binding on TREL "
334                       "netif \"%s\" - timeout %lu (ms)",
335                       Ip6AddrToString(&sInterfaceAddress), sInterfaceName, TREL_SOCKET_BIND_MAX_WAIT_TIME_MSEC);
336         DieNow(OT_EXIT_ERROR_ERRNO);
337     }
338 }
339 
SendPacket(const uint8_t * aBuffer,uint16_t aLength,const otIp6Address * aDestAddress)340 static otError SendPacket(const uint8_t *aBuffer, uint16_t aLength, const otIp6Address *aDestAddress)
341 {
342     otError             error = OT_ERROR_NONE;
343     struct sockaddr_in6 sockAddr;
344     ssize_t             ret;
345 
346     VerifyOrExit(sSocket >= 0, error = OT_ERROR_INVALID_STATE);
347 
348     memset(&sockAddr, 0, sizeof(sockAddr));
349     sockAddr.sin6_family = AF_INET6;
350     sockAddr.sin6_port   = htons(sUdpPort);
351     memcpy(&sockAddr.sin6_addr, aDestAddress, sizeof(otIp6Address));
352 
353     ret = sendto(sSocket, aBuffer, aLength, 0, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
354 
355     if (ret != aLength)
356     {
357         otLogDebgPlat("[trel] SendPacket() -- sendto() failed errno %d", errno);
358 
359         switch (errno)
360         {
361         case ENETUNREACH:
362         case ENETDOWN:
363         case EHOSTUNREACH:
364             error = OT_ERROR_ABORT;
365             break;
366 
367         default:
368             error = OT_ERROR_INVALID_STATE;
369         }
370     }
371 
372 exit:
373     otLogDebgPlat("[trel] SendPacket(%s) err:%s pkt:%s", Ip6AddrToString(aDestAddress), otThreadErrorToString(error),
374                   BufferToString(aBuffer, aLength));
375 
376     return error;
377 }
378 
ReceivePacket(int aSocket,otInstance * aInstance)379 static void ReceivePacket(int aSocket, otInstance *aInstance)
380 {
381     struct sockaddr_in6 sockAddr;
382     socklen_t           sockAddrLen = sizeof(sockAddr);
383     ssize_t             ret;
384 
385     memset(&sockAddr, 0, sizeof(sockAddr));
386 
387     ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr,
388                    &sockAddrLen);
389     VerifyOrDie(ret >= 0, OT_EXIT_ERROR_ERRNO);
390 
391     sRxPacketLength = (uint16_t)(ret);
392 
393     if (sRxPacketLength > sizeof(sRxPacketBuffer))
394     {
395         sRxPacketLength = sizeof(sRxPacketLength);
396     }
397 
398     otLogDebgPlat("[trel] ReceivePacket() - received from %s port:%d, id:%d, pkt:%s",
399                   Ip6AddrToString(&sockAddr.sin6_addr), ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id,
400                   BufferToString(sRxPacketBuffer, sRxPacketLength));
401 
402     if (sEnabled)
403     {
404         otPlatTrelUdp6HandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength);
405     }
406 }
407 
InitPacketQueue(void)408 static void InitPacketQueue(void)
409 {
410     sTxPacketQueueTail = NULL;
411 
412     // Chain all the packets in pool in the free linked list.
413     sFreeTxPacketHead = NULL;
414 
415     for (uint16_t index = 0; index < OT_ARRAY_LENGTH(sTxPacketPool); index++)
416     {
417         TxPacket *packet = &sTxPacketPool[index];
418 
419         packet->mNext     = sFreeTxPacketHead;
420         sFreeTxPacketHead = packet;
421     }
422 }
423 
SendQueuedPackets(void)424 static void SendQueuedPackets(void)
425 {
426     while (sTxPacketQueueTail != NULL)
427     {
428         TxPacket *packet = sTxPacketQueueTail->mNext; // tail->mNext is the head of the list.
429 
430         if (SendPacket(packet->mBuffer, packet->mLength, &packet->mDestAddress) == OT_ERROR_INVALID_STATE)
431         {
432             otLogDebgPlat("[trel] SendQueuedPackets() - SendPacket() would block");
433             break;
434         }
435 
436         // Remove the `packet` from the packet queue (circular
437         // linked list).
438 
439         if (packet == sTxPacketQueueTail)
440         {
441             sTxPacketQueueTail = NULL;
442         }
443         else
444         {
445             sTxPacketQueueTail->mNext = packet->mNext;
446         }
447 
448         // Add the `packet` to the free packet singly linked list.
449 
450         packet->mNext     = sFreeTxPacketHead;
451         sFreeTxPacketHead = packet;
452     }
453 }
454 
EnqueuePacket(const uint8_t * aBuffer,uint16_t aLength,const otIp6Address * aDestAddress)455 static otError EnqueuePacket(const uint8_t *aBuffer, uint16_t aLength, const otIp6Address *aDestAddress)
456 {
457     otError   error = OT_ERROR_NONE;
458     TxPacket *packet;
459 
460     // Allocate an available packet entry (from the free packet list)
461     // and copy the packet content into it.
462 
463     VerifyOrExit(sFreeTxPacketHead != NULL, error = OT_ERROR_NO_BUFS);
464     packet            = sFreeTxPacketHead;
465     sFreeTxPacketHead = sFreeTxPacketHead->mNext;
466 
467     memcpy(packet->mBuffer, aBuffer, aLength);
468     packet->mLength      = aLength;
469     packet->mDestAddress = *aDestAddress;
470 
471     // Add packet to the tail of TxPacketQueue circular linked-list.
472 
473     if (sTxPacketQueueTail == NULL)
474     {
475         packet->mNext      = packet;
476         sTxPacketQueueTail = packet;
477     }
478     else
479     {
480         packet->mNext             = sTxPacketQueueTail->mNext;
481         sTxPacketQueueTail->mNext = packet;
482         sTxPacketQueueTail        = packet;
483     }
484 
485     otLogDebgPlat("[trel] EnqueuePacket(%s) - %s", Ip6AddrToString(aDestAddress), BufferToString(aBuffer, aLength));
486 
487 exit:
488     return error;
489 }
490 
491 //---------------------------------------------------------------------------------------------------------------------
492 // otPlatTrelUdp6
493 
otPlatTrelUdp6Init(otInstance * aInstance,const otIp6Address * aUnicastAddress,uint16_t aUdpPort)494 void otPlatTrelUdp6Init(otInstance *aInstance, const otIp6Address *aUnicastAddress, uint16_t aUdpPort)
495 {
496     OT_UNUSED_VARIABLE(aInstance);
497 
498     int                 val;
499     struct sockaddr_in6 sockAddr;
500 
501     VerifyOrExit(sEnabled);
502 
503     otLogDebgPlat("[trel] otPlatTrelUdp6Init(%s, port:%d)", Ip6AddrToString(aUnicastAddress), aUdpPort);
504 
505     sUdpPort          = aUdpPort;
506     sInterfaceAddress = *aUnicastAddress;
507     sInterfaceIndex   = (int)if_nametoindex(sInterfaceName);
508 
509     if (sInterfaceIndex <= 0)
510     {
511         otLogCritPlat("[trel] Failed to find index of TREL netif \"%s\"", sInterfaceName);
512         DieNow(OT_EXIT_ERROR_ERRNO);
513     }
514 
515     AddUnicastAddress(aUnicastAddress);
516 
517     sMulticastSocket = socket(AF_INET6, SOCK_DGRAM, 0);
518     VerifyOrDie(sMulticastSocket >= 0, OT_EXIT_ERROR_ERRNO);
519 
520     val = 1;
521     VerifyOrDie(setsockopt(sMulticastSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
522     VerifyOrDie(setsockopt(sMulticastSocket, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) == 0, OT_EXIT_ERROR_ERRNO);
523 
524     // To receive from multicast addresses, the socket need to be
525     // bound to `in6addr_any` address.
526     memset(&sockAddr, 0, sizeof(sockAddr));
527     sockAddr.sin6_family   = AF_INET6;
528     sockAddr.sin6_port     = htons(sUdpPort);
529     sockAddr.sin6_addr     = in6addr_any;
530     sockAddr.sin6_scope_id = (uint32_t)sInterfaceIndex;
531 
532     if (bind(sMulticastSocket, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) == -1)
533     {
534         otLogCritPlat("[trel] Failed to bind multicast socket to any address on TREL netif \"%s\"", sInterfaceName);
535         DieNow(OT_EXIT_ERROR_ERRNO);
536     }
537 
538     PrepareSocket();
539 
540 exit:
541     return;
542 }
543 
otPlatTrelUdp6UpdateAddress(otInstance * aInstance,const otIp6Address * aUnicastAddress)544 void otPlatTrelUdp6UpdateAddress(otInstance *aInstance, const otIp6Address *aUnicastAddress)
545 {
546     OT_UNUSED_VARIABLE(aInstance);
547 
548     VerifyOrExit(sEnabled);
549 
550     assert(sSocket >= 0);
551 
552     otLogDebgPlat("[trel] otPlatTrelUdp6UpdateAddress(%s)", Ip6AddrToString(aUnicastAddress));
553 
554     VerifyOrExit(memcmp(aUnicastAddress, &sInterfaceAddress, sizeof(otIp6Address)) != 0);
555 
556     close(sSocket);
557     RemoveUnicastAddress(&sInterfaceAddress);
558 
559     sInterfaceAddress = *aUnicastAddress;
560     AddUnicastAddress(aUnicastAddress);
561 
562     PrepareSocket();
563 
564 exit:
565     return;
566 }
567 
otPlatTrelUdp6SubscribeMulticastAddress(otInstance * aInstance,const otIp6Address * aMulticastAddress)568 void otPlatTrelUdp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aMulticastAddress)
569 {
570     OT_UNUSED_VARIABLE(aInstance);
571 
572     struct ipv6_mreq mr;
573 
574     VerifyOrExit(sEnabled);
575 
576     assert(sMulticastSocket != -1);
577 
578     memcpy(&mr.ipv6mr_multiaddr, aMulticastAddress, sizeof(otIp6Address));
579     mr.ipv6mr_interface = (unsigned int)sInterfaceIndex;
580     VerifyOrDie(setsockopt(sMulticastSocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mr, sizeof(mr)) == 0, OT_EXIT_ERROR_ERRNO);
581 
582     otLogDebgPlat("[trel] otPlatTrelUdp6SubscribeMulticastAddress(%s)", Ip6AddrToString(aMulticastAddress));
583 
584 exit:
585     return;
586 }
587 
otPlatTrelUdp6SendTo(otInstance * aInstance,const uint8_t * aBuffer,uint16_t aLength,const otIp6Address * aDestAddress)588 otError otPlatTrelUdp6SendTo(otInstance *        aInstance,
589                              const uint8_t *     aBuffer,
590                              uint16_t            aLength,
591                              const otIp6Address *aDestAddress)
592 {
593     OT_UNUSED_VARIABLE(aInstance);
594 
595     otError error = OT_ERROR_NONE;
596 
597     VerifyOrExit(sEnabled);
598 
599     assert(aLength <= TREL_MAX_PACKET_SIZE);
600 
601     otLogDebgPlat("[trel] otPlatTrelUdp6SendTo(%s) %s", Ip6AddrToString(aDestAddress),
602                   BufferToString(aBuffer, aLength));
603 
604     // We try to send the packet immediately. If it fails (e.g.,
605     // network is down) `SendPacket()` returns `OT_ERROR_ABORT`. If
606     // the send operation would block (e.g., socket is not yet ready
607     // or is out of buffer) we get `OT_ERROR_INVALID_STATE`. In that
608     // case we enqueue the packet to send it later when socket becomes
609     // ready.
610 
611     error = SendPacket(aBuffer, aLength, aDestAddress);
612 
613     if (error == OT_ERROR_INVALID_STATE)
614     {
615         error = EnqueuePacket(aBuffer, aLength, aDestAddress);
616 
617         if (error != OT_ERROR_NONE)
618         {
619             error = OT_ERROR_ABORT;
620         }
621     }
622 
623 exit:
624     return error;
625 }
626 
otPlatTrelUdp6SetTestMode(otInstance * aInstance,bool aEnable)627 otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable)
628 {
629     OT_UNUSED_VARIABLE(aInstance);
630 
631     otError error = OT_ERROR_NONE;
632 
633     VerifyOrExit(aEnable != sEnabled);
634 
635     if (aEnable)
636     {
637         VerifyOrExit(sInitialized, error = OT_ERROR_FAILED);
638     }
639 
640     sEnabled = aEnable;
641 
642     if (!sEnabled)
643     {
644         InitPacketQueue();
645     }
646 
647 exit:
648     return error;
649 }
650 
651 //---------------------------------------------------------------------------------------------------------------------
652 // platformTrel system
653 
platformTrelInit(const char * aTrelUrl)654 void platformTrelInit(const char *aTrelUrl)
655 {
656     assert(!sInitialized);
657 
658     if (aTrelUrl != NULL)
659     {
660         ot::Posix::RadioUrl url(aTrelUrl);
661 
662         strncpy(sInterfaceName, url.GetPath(), sizeof(sInterfaceName) - 1);
663     }
664     else
665     {
666         strncpy(sInterfaceName, OPENTHREAD_CONFIG_POSIX_APP_TREL_INTERFACE_NAME, sizeof(sInterfaceName) - 1);
667     }
668 
669     sInterfaceName[sizeof(sInterfaceName) - 1] = 0;
670     otLogDebgPlat("[trel] platformTrelInit(InterfaceName:\"%s\")", sInterfaceName);
671 
672     InitPacketQueue();
673 
674     // Disable trel platform when interface name is empty.
675     sInitialized = (sInterfaceName[0] != '\0');
676     sEnabled     = sInitialized;
677 }
678 
platformTrelDeinit(void)679 void platformTrelDeinit(void)
680 {
681     VerifyOrExit(sInitialized);
682 
683     if (sSocket != -1)
684     {
685         close(sSocket);
686     }
687 
688     if (sMulticastSocket != -1)
689     {
690         close(sMulticastSocket);
691     }
692 
693     if (!otIp6IsAddressUnspecified(&sInterfaceAddress))
694     {
695         RemoveUnicastAddress(&sInterfaceAddress);
696     }
697 
698     sInitialized = false;
699     sEnabled     = false;
700 
701     otLogDebgPlat("[trel] platformTrelDeinit()");
702 exit:
703     return;
704 }
705 
platformTrelUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,int * aMaxFd,struct timeval * aTimeout)706 void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd, struct timeval *aTimeout)
707 {
708     OT_UNUSED_VARIABLE(aTimeout);
709 
710     assert((aReadFdSet != NULL) && (aWriteFdSet != NULL) && (aMaxFd != NULL) && (aTimeout != NULL));
711     VerifyOrExit((sSocket >= 0) && (sMulticastSocket >= 0));
712 
713     FD_SET(sMulticastSocket, aReadFdSet);
714     FD_SET(sSocket, aReadFdSet);
715 
716     if (sTxPacketQueueTail != NULL)
717     {
718         FD_SET(sSocket, aWriteFdSet);
719     }
720 
721     if (*aMaxFd < sMulticastSocket)
722     {
723         *aMaxFd = sMulticastSocket;
724     }
725 
726     if (*aMaxFd < sSocket)
727     {
728         *aMaxFd = sSocket;
729     }
730 
731 exit:
732     return;
733 }
734 
platformTrelProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)735 void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
736 {
737     VerifyOrExit((sSocket >= 0) && (sMulticastSocket >= 0));
738 
739     if (FD_ISSET(sSocket, aWriteFdSet))
740     {
741         SendQueuedPackets();
742     }
743 
744     if (FD_ISSET(sSocket, aReadFdSet))
745     {
746         ReceivePacket(sSocket, aInstance);
747     }
748 
749     if (FD_ISSET(sMulticastSocket, aReadFdSet))
750     {
751         ReceivePacket(sMulticastSocket, aInstance);
752     }
753 
754 exit:
755     return;
756 }
757 
758 #endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
759