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