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