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