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