1 /*
2  *  Copyright (c) 2018, 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  * @brief
32  *   This file includes the platform UDP driver.
33  */
34 
35 #ifdef __APPLE__
36 #define __APPLE_USE_RFC_3542
37 #endif
38 
39 #include "openthread-posix-config.h"
40 #include "platform-posix.h"
41 
42 #include <arpa/inet.h>
43 #include <assert.h>
44 #include <net/if.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/select.h>
49 #include <unistd.h>
50 
51 #include <openthread/udp.h>
52 #include <openthread/platform/udp.h>
53 
54 #include "common/code_utils.hpp"
55 
56 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
57 
58 #include "posix/platform/ip6_utils.hpp"
59 #include "posix/platform/mainloop.hpp"
60 #include "posix/platform/udp.hpp"
61 
62 using namespace ot::Posix::Ip6Utils;
63 
64 namespace {
65 
66 constexpr size_t kMaxUdpSize = 1280;
67 
FdToHandle(int aFd)68 void *FdToHandle(int aFd)
69 {
70     return reinterpret_cast<void *>(aFd);
71 }
72 
FdFromHandle(void * aHandle)73 int FdFromHandle(void *aHandle)
74 {
75     return static_cast<int>(reinterpret_cast<long>(aHandle));
76 }
77 
IsLinkLocal(const struct in6_addr & aAddress)78 bool IsLinkLocal(const struct in6_addr &aAddress)
79 {
80     return aAddress.s6_addr[0] == 0xfe && aAddress.s6_addr[1] == 0x80;
81 }
82 
IsMulticast(const otIp6Address & aAddress)83 bool IsMulticast(const otIp6Address &aAddress)
84 {
85     return aAddress.mFields.m8[0] == 0xff;
86 }
87 
transmitPacket(int aFd,uint8_t * aPayload,uint16_t aLength,const otMessageInfo & aMessageInfo)88 otError transmitPacket(int aFd, uint8_t *aPayload, uint16_t aLength, const otMessageInfo &aMessageInfo)
89 {
90 #ifdef __APPLE__
91     // use fixed value for CMSG_SPACE is not a constant expression on macOS
92     constexpr size_t kBufferSize = 128;
93 #else
94     constexpr size_t kBufferSize = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
95 #endif
96     struct sockaddr_in6 peerAddr;
97     uint8_t             control[kBufferSize];
98     size_t              controlLength = 0;
99     struct iovec        iov;
100     struct msghdr       msg;
101     struct cmsghdr *    cmsg;
102     ssize_t             rval;
103     otError             error = OT_ERROR_NONE;
104 
105     memset(&peerAddr, 0, sizeof(peerAddr));
106     peerAddr.sin6_port   = htons(aMessageInfo.mPeerPort);
107     peerAddr.sin6_family = AF_INET6;
108     memcpy(&peerAddr.sin6_addr, &aMessageInfo.mPeerAddr, sizeof(peerAddr.sin6_addr));
109 
110     if (IsLinkLocal(peerAddr.sin6_addr) && !aMessageInfo.mIsHostInterface)
111     {
112         // sin6_scope_id only works for link local destinations
113         peerAddr.sin6_scope_id = gNetifIndex;
114     }
115 
116     memset(control, 0, sizeof(control));
117 
118     iov.iov_base = aPayload;
119     iov.iov_len  = aLength;
120 
121     msg.msg_name       = &peerAddr;
122     msg.msg_namelen    = sizeof(peerAddr);
123     msg.msg_control    = control;
124     msg.msg_controllen = static_cast<decltype(msg.msg_controllen)>(sizeof(control));
125     msg.msg_iov        = &iov;
126     msg.msg_iovlen     = 1;
127     msg.msg_flags      = 0;
128 
129     {
130         int hopLimit = (aMessageInfo.mHopLimit ? aMessageInfo.mHopLimit : OPENTHREAD_CONFIG_IP6_HOP_LIMIT_DEFAULT);
131 
132         cmsg             = CMSG_FIRSTHDR(&msg);
133         cmsg->cmsg_level = IPPROTO_IPV6;
134         cmsg->cmsg_type  = IPV6_HOPLIMIT;
135         cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
136 
137         memcpy(CMSG_DATA(cmsg), &hopLimit, sizeof(int));
138 
139         controlLength += CMSG_SPACE(sizeof(int));
140     }
141 
142     if (!IsMulticast(aMessageInfo.mSockAddr) &&
143         memcmp(&aMessageInfo.mSockAddr, &in6addr_any, sizeof(aMessageInfo.mSockAddr)))
144     {
145         struct in6_pktinfo pktinfo;
146 
147         cmsg             = CMSG_NXTHDR(&msg, cmsg);
148         cmsg->cmsg_level = IPPROTO_IPV6;
149         cmsg->cmsg_type  = IPV6_PKTINFO;
150         cmsg->cmsg_len   = CMSG_LEN(sizeof(pktinfo));
151 
152         pktinfo.ipi6_ifindex = aMessageInfo.mIsHostInterface ? 0 : gNetifIndex;
153 
154         memcpy(&pktinfo.ipi6_addr, &aMessageInfo.mSockAddr, sizeof(pktinfo.ipi6_addr));
155         memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo));
156 
157         controlLength += CMSG_SPACE(sizeof(pktinfo));
158     }
159 
160 #ifdef __APPLE__
161     msg.msg_controllen = static_cast<socklen_t>(controlLength);
162 #else
163     msg.msg_controllen           = controlLength;
164 #endif
165 
166     rval = sendmsg(aFd, &msg, 0);
167     VerifyOrExit(rval > 0, perror("sendmsg"));
168 
169 exit:
170     // EINVAL happens when we shift from child to router and the
171     // interface address changes. Ask callers to try again later.
172     if (rval == -1)
173     {
174         error = (errno == EINVAL) ? OT_ERROR_INVALID_STATE : OT_ERROR_FAILED;
175     }
176 
177     return error;
178 }
179 
receivePacket(int aFd,uint8_t * aPayload,uint16_t & aLength,otMessageInfo & aMessageInfo)180 otError receivePacket(int aFd, uint8_t *aPayload, uint16_t &aLength, otMessageInfo &aMessageInfo)
181 {
182     struct sockaddr_in6 peerAddr;
183     uint8_t             control[kMaxUdpSize];
184     struct iovec        iov;
185     struct msghdr       msg;
186     ssize_t             rval;
187 
188     iov.iov_base = aPayload;
189     iov.iov_len  = aLength;
190 
191     msg.msg_name       = &peerAddr;
192     msg.msg_namelen    = sizeof(peerAddr);
193     msg.msg_control    = control;
194     msg.msg_controllen = sizeof(control);
195     msg.msg_iov        = &iov;
196     msg.msg_iovlen     = 1;
197     msg.msg_flags      = 0;
198 
199     rval = recvmsg(aFd, &msg, 0);
200     VerifyOrExit(rval > 0, perror("recvmsg"));
201     aLength = static_cast<uint16_t>(rval);
202 
203     for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg))
204     {
205         if (cmsg->cmsg_level == IPPROTO_IPV6)
206         {
207             if (cmsg->cmsg_type == IPV6_HOPLIMIT)
208             {
209                 int hoplimit;
210 
211                 memcpy(&hoplimit, CMSG_DATA(cmsg), sizeof(hoplimit));
212                 aMessageInfo.mHopLimit = static_cast<uint8_t>(hoplimit);
213             }
214             else if (cmsg->cmsg_type == IPV6_PKTINFO)
215             {
216                 struct in6_pktinfo pktinfo;
217 
218                 memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
219 
220                 aMessageInfo.mIsHostInterface = (pktinfo.ipi6_ifindex != gNetifIndex);
221                 memcpy(&aMessageInfo.mSockAddr, &pktinfo.ipi6_addr, sizeof(aMessageInfo.mSockAddr));
222             }
223         }
224     }
225 
226     aMessageInfo.mPeerPort = ntohs(peerAddr.sin6_port);
227     memcpy(&aMessageInfo.mPeerAddr, &peerAddr.sin6_addr, sizeof(aMessageInfo.mPeerAddr));
228 
229 exit:
230     return rval > 0 ? OT_ERROR_NONE : OT_ERROR_FAILED;
231 }
232 
233 } // namespace
234 
otPlatUdpSocket(otUdpSocket * aUdpSocket)235 otError otPlatUdpSocket(otUdpSocket *aUdpSocket)
236 {
237     otError error = OT_ERROR_NONE;
238     int     fd;
239 
240     assert(aUdpSocket->mHandle == nullptr);
241 
242     fd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, kSocketNonBlock);
243     VerifyOrExit(fd >= 0, error = OT_ERROR_FAILED);
244 
245     aUdpSocket->mHandle = FdToHandle(fd);
246 
247 exit:
248     return error;
249 }
250 
otPlatUdpClose(otUdpSocket * aUdpSocket)251 otError otPlatUdpClose(otUdpSocket *aUdpSocket)
252 {
253     otError error = OT_ERROR_NONE;
254     int     fd;
255 
256     // Only call `close()` on platform UDP sockets.
257     // Platform UDP sockets always have valid `mHandle` upon creation.
258     VerifyOrExit(aUdpSocket->mHandle != nullptr);
259 
260     fd = FdFromHandle(aUdpSocket->mHandle);
261     VerifyOrExit(0 == close(fd), error = OT_ERROR_FAILED);
262 
263     aUdpSocket->mHandle = nullptr;
264 
265 exit:
266     return error;
267 }
268 
otPlatUdpBind(otUdpSocket * aUdpSocket)269 otError otPlatUdpBind(otUdpSocket *aUdpSocket)
270 {
271     otError error = OT_ERROR_NONE;
272     int     fd;
273 
274     assert(gNetifIndex != 0);
275     assert(aUdpSocket->mHandle != nullptr);
276     VerifyOrExit(aUdpSocket->mSockName.mPort != 0, error = OT_ERROR_INVALID_ARGS);
277     fd = FdFromHandle(aUdpSocket->mHandle);
278 
279     {
280         struct sockaddr_in6 sin6;
281 
282         memset(&sin6, 0, sizeof(struct sockaddr_in6));
283         sin6.sin6_port   = htons(aUdpSocket->mSockName.mPort);
284         sin6.sin6_family = AF_INET6;
285         memcpy(&sin6.sin6_addr, &aUdpSocket->mSockName.mAddress, sizeof(sin6.sin6_addr));
286         VerifyOrExit(0 == bind(fd, reinterpret_cast<struct sockaddr *>(&sin6), sizeof(sin6)), error = OT_ERROR_FAILED);
287     }
288 
289     {
290         int on = 1;
291         VerifyOrExit(0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)), error = OT_ERROR_FAILED);
292         VerifyOrExit(0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)), error = OT_ERROR_FAILED);
293     }
294 
295 exit:
296     if (error == OT_ERROR_FAILED)
297     {
298         otLogCritPlat("Failed to bind UDP socket: %s", strerror(errno));
299     }
300 
301     return error;
302 }
303 
otPlatUdpBindToNetif(otUdpSocket * aUdpSocket,otNetifIdentifier aNetifIdentifier)304 otError otPlatUdpBindToNetif(otUdpSocket *aUdpSocket, otNetifIdentifier aNetifIdentifier)
305 {
306     otError error = OT_ERROR_NONE;
307     int     fd    = FdFromHandle(aUdpSocket->mHandle);
308     int     one   = 1;
309     int     zero  = 0;
310 
311     switch (aNetifIdentifier)
312     {
313     case OT_NETIF_UNSPECIFIED:
314     {
315 #ifdef __linux__
316         VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, nullptr, 0) == 0, error = OT_ERROR_FAILED);
317 #else  // __NetBSD__ || __FreeBSD__ || __APPLE__
318         unsigned int netifIndex = 0;
319         VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &netifIndex, sizeof(netifIndex)) == 0,
320                      error = OT_ERROR_FAILED);
321 #endif // __linux__
322         break;
323     }
324     case OT_NETIF_THREAD:
325     {
326 #ifdef __linux__
327         VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &gNetifName, strlen(gNetifName)) == 0,
328                      error = OT_ERROR_FAILED);
329 #else  // __NetBSD__ || __FreeBSD__ || __APPLE__
330         VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &gNetifIndex, sizeof(gNetifIndex)) == 0,
331                      error = OT_ERROR_FAILED);
332 #endif // __linux__
333         break;
334     }
335     case OT_NETIF_BACKBONE:
336     {
337 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
338 #if __linux__
339         VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, gBackboneNetifName, strlen(gBackboneNetifName)) == 0,
340                      error = OT_ERROR_FAILED);
341 #else  // __NetBSD__ || __FreeBSD__ || __APPLE__
342         VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, &gBackboneNetifIndex, sizeof(gBackboneNetifIndex)) ==
343                          0,
344                      error = OT_ERROR_FAILED);
345 #endif // __linux__
346 #else
347         ExitNow(error = OT_ERROR_NOT_IMPLEMENTED);
348 #endif
349         VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&one, sizeof(one)) == 0,
350                      error = OT_ERROR_FAILED);
351 
352         break;
353     }
354     }
355 
356     VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) == 0, error = OT_ERROR_FAILED);
357 
358 exit:
359     return error;
360 }
361 
otPlatUdpConnect(otUdpSocket * aUdpSocket)362 otError otPlatUdpConnect(otUdpSocket *aUdpSocket)
363 {
364     otError             error = OT_ERROR_NONE;
365     struct sockaddr_in6 sin6;
366     int                 fd;
367     bool isDisconnect = memcmp(&aUdpSocket->mPeerName.mAddress, &in6addr_any, sizeof(in6addr_any)) == 0 &&
368                         aUdpSocket->mPeerName.mPort == 0;
369 
370     VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS);
371 
372     fd = FdFromHandle(aUdpSocket->mHandle);
373 
374     memset(&sin6, 0, sizeof(struct sockaddr_in6));
375     sin6.sin6_port = htons(aUdpSocket->mPeerName.mPort);
376     if (!isDisconnect)
377     {
378         sin6.sin6_family = AF_INET6;
379         memcpy(&sin6.sin6_addr, &aUdpSocket->mPeerName.mAddress, sizeof(sin6.sin6_addr));
380     }
381     else
382     {
383 #ifdef __APPLE__
384         sin6.sin6_family = AF_UNSPEC;
385 #else
386         char      netifName[IFNAMSIZ];
387         socklen_t len = sizeof(netifName);
388 
389         if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &netifName, &len) != 0)
390         {
391             otLogWarnPlat("Failed to read socket bound device: %s", strerror(errno));
392             len = 0;
393         }
394 
395         // There is a bug in linux that connecting to AF_UNSPEC does not disconnect.
396         // We create new socket to disconnect.
397         SuccessOrExit(error = otPlatUdpClose(aUdpSocket));
398         SuccessOrExit(error = otPlatUdpSocket(aUdpSocket));
399         SuccessOrExit(error = otPlatUdpBind(aUdpSocket));
400 
401         if (len > 0 && netifName[0] != '\0')
402         {
403             fd = FdFromHandle(aUdpSocket->mHandle);
404             VerifyOrExit(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &netifName, len) == 0, {
405                 otLogWarnPlat("Failed to bind to device: %s", strerror(errno));
406                 error = OT_ERROR_FAILED;
407             });
408         }
409 
410         ExitNow();
411 #endif
412     }
413 
414     if (connect(fd, reinterpret_cast<struct sockaddr *>(&sin6), sizeof(sin6)) != 0)
415     {
416 #ifdef __APPLE__
417         VerifyOrExit(errno == EAFNOSUPPORT && isDisconnect);
418 #endif
419         otLogWarnPlat("Failed to connect to [%s]:%u: %s", Ip6AddressString(&aUdpSocket->mPeerName.mAddress).AsCString(),
420                       aUdpSocket->mPeerName.mPort, strerror(errno));
421         error = OT_ERROR_FAILED;
422     }
423 
424 exit:
425     return error;
426 }
427 
otPlatUdpSend(otUdpSocket * aUdpSocket,otMessage * aMessage,const otMessageInfo * aMessageInfo)428 otError otPlatUdpSend(otUdpSocket *aUdpSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo)
429 {
430     otError  error = OT_ERROR_NONE;
431     int      fd;
432     uint16_t len;
433     uint8_t  payload[kMaxUdpSize];
434 
435     VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS);
436     fd = FdFromHandle(aUdpSocket->mHandle);
437 
438     len = otMessageGetLength(aMessage);
439     VerifyOrExit(len == otMessageRead(aMessage, 0, payload, len), error = OT_ERROR_INVALID_ARGS);
440 
441     if (aMessageInfo->mMulticastLoop)
442     {
443         int value = 1;
444 
445         VerifyOrDie(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &value, sizeof(value)) == 0, OT_EXIT_ERROR_ERRNO);
446     }
447 
448     error = transmitPacket(fd, payload, len, *aMessageInfo);
449 
450     if (aMessageInfo->mMulticastLoop)
451     {
452         int value = 0;
453 
454         VerifyOrDie(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &value, sizeof(value)) == 0, OT_EXIT_ERROR_ERRNO);
455     }
456 
457 exit:
458     if (error == OT_ERROR_NONE)
459     {
460         otMessageFree(aMessage);
461     }
462 
463     return error;
464 }
465 
otPlatUdpJoinMulticastGroup(otUdpSocket * aUdpSocket,otNetifIdentifier aNetifIdentifier,const otIp6Address * aAddress)466 otError otPlatUdpJoinMulticastGroup(otUdpSocket *       aUdpSocket,
467                                     otNetifIdentifier   aNetifIdentifier,
468                                     const otIp6Address *aAddress)
469 {
470     otError          error = OT_ERROR_NONE;
471     struct ipv6_mreq mreq;
472     int              fd;
473 
474     VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS);
475     fd = FdFromHandle(aUdpSocket->mHandle);
476 
477     memcpy(&mreq.ipv6mr_multiaddr, aAddress->mFields.m8, sizeof(mreq.ipv6mr_multiaddr));
478 
479     switch (aNetifIdentifier)
480     {
481     case OT_NETIF_UNSPECIFIED:
482         break;
483     case OT_NETIF_THREAD:
484         mreq.ipv6mr_interface = gNetifIndex;
485         break;
486     case OT_NETIF_BACKBONE:
487 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
488         mreq.ipv6mr_interface = gBackboneNetifIndex;
489 #else
490         ExitNow(error = OT_ERROR_NOT_IMPLEMENTED);
491 #endif
492         break;
493     }
494 
495     VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == 0 || errno == EADDRINUSE,
496                  error = OT_ERROR_FAILED);
497 
498 exit:
499     if (error != OT_ERROR_NONE)
500     {
501         otLogCritPlat("IPV6_JOIN_GROUP failed: %s", strerror(errno));
502     }
503     return error;
504 }
505 
otPlatUdpLeaveMulticastGroup(otUdpSocket * aUdpSocket,otNetifIdentifier aNetifIdentifier,const otIp6Address * aAddress)506 otError otPlatUdpLeaveMulticastGroup(otUdpSocket *       aUdpSocket,
507                                      otNetifIdentifier   aNetifIdentifier,
508                                      const otIp6Address *aAddress)
509 {
510     otError          error = OT_ERROR_NONE;
511     struct ipv6_mreq mreq;
512     int              fd;
513 
514     VerifyOrExit(aUdpSocket->mHandle != nullptr, error = OT_ERROR_INVALID_ARGS);
515     fd = FdFromHandle(aUdpSocket->mHandle);
516 
517     memcpy(&mreq.ipv6mr_multiaddr, aAddress->mFields.m8, sizeof(mreq.ipv6mr_multiaddr));
518 
519     switch (aNetifIdentifier)
520     {
521     case OT_NETIF_UNSPECIFIED:
522         break;
523     case OT_NETIF_THREAD:
524         mreq.ipv6mr_interface = gNetifIndex;
525         break;
526     case OT_NETIF_BACKBONE:
527 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
528         mreq.ipv6mr_interface = gBackboneNetifIndex;
529 #else
530         ExitNow(error = OT_ERROR_NOT_IMPLEMENTED);
531 #endif
532         break;
533     }
534 
535     VerifyOrExit(setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) == 0 || errno == EADDRINUSE,
536                  error = OT_ERROR_FAILED);
537 
538 exit:
539     if (error != OT_ERROR_NONE)
540     {
541         otLogCritPlat("IPV6_LEAVE_GROUP failed: %s", strerror(errno));
542     }
543     return error;
544 }
545 
546 namespace ot {
547 namespace Posix {
548 
Update(otSysMainloopContext & aContext)549 void Udp::Update(otSysMainloopContext &aContext)
550 {
551     VerifyOrExit(gNetifIndex != 0);
552 
553     for (otUdpSocket *socket = otUdpGetSockets(gInstance); socket != nullptr; socket = socket->mNext)
554     {
555         int fd;
556 
557         if (socket->mHandle == nullptr)
558         {
559             continue;
560         }
561 
562         fd = FdFromHandle(socket->mHandle);
563         FD_SET(fd, &aContext.mReadFdSet);
564 
565         if (aContext.mMaxFd < fd)
566         {
567             aContext.mMaxFd = fd;
568         }
569     }
570 
571 exit:
572     return;
573 }
574 
Init(const char * aIfName)575 void Udp::Init(const char *aIfName)
576 {
577     if (aIfName == nullptr)
578     {
579         DieNow(OT_EXIT_INVALID_ARGUMENTS);
580     }
581 
582     if (aIfName != gNetifName)
583     {
584         VerifyOrDie(strlen(aIfName) < sizeof(gNetifName) - 1, OT_EXIT_INVALID_ARGUMENTS);
585         assert(gNetifIndex == 0);
586         strcpy(gNetifName, aIfName);
587         gNetifIndex = if_nametoindex(gNetifName);
588         VerifyOrDie(gNetifIndex != 0, OT_EXIT_ERROR_ERRNO);
589     }
590 
591     assert(gNetifIndex != 0);
592 }
593 
SetUp(void)594 void Udp::SetUp(void)
595 {
596     Mainloop::Manager::Get().Add(*this);
597 }
598 
TearDown(void)599 void Udp::TearDown(void)
600 {
601     Mainloop::Manager::Get().Remove(*this);
602 }
603 
Deinit(void)604 void Udp::Deinit(void)
605 {
606     // TODO All platform sockets should be closed
607 }
608 
Get(void)609 Udp &Udp::Get(void)
610 {
611     static Udp sInstance;
612 
613     return sInstance;
614 }
615 
Process(const otSysMainloopContext & aContext)616 void Udp::Process(const otSysMainloopContext &aContext)
617 {
618     otMessageSettings msgSettings = {false, OT_MESSAGE_PRIORITY_NORMAL};
619 
620     for (otUdpSocket *socket = otUdpGetSockets(gInstance); socket != nullptr; socket = socket->mNext)
621     {
622         int fd = FdFromHandle(socket->mHandle);
623 
624         if (fd > 0 && FD_ISSET(fd, &aContext.mReadFdSet))
625         {
626             otMessageInfo messageInfo;
627             otMessage *   message = nullptr;
628             uint8_t       payload[kMaxUdpSize];
629             uint16_t      length = sizeof(payload);
630 
631             memset(&messageInfo, 0, sizeof(messageInfo));
632             messageInfo.mSockPort = socket->mSockName.mPort;
633 
634             if (OT_ERROR_NONE != receivePacket(fd, payload, length, messageInfo))
635             {
636                 continue;
637             }
638 
639             message = otUdpNewMessage(gInstance, &msgSettings);
640 
641             if (message == nullptr)
642             {
643                 continue;
644             }
645 
646             if (otMessageAppend(message, payload, length) != OT_ERROR_NONE)
647             {
648                 otMessageFree(message);
649                 continue;
650             }
651 
652             socket->mHandler(socket->mContext, message, &messageInfo);
653             otMessageFree(message);
654             // only process one socket a time
655             break;
656         }
657     }
658 
659     return;
660 }
661 
662 } // namespace Posix
663 } // namespace ot
664 #endif // #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
665