1 /**
2 * Copyright (c) 2023-2024 Marcin Niestroj
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 *
10 * Linux (bottom) side of NSOS (Native Simulator Offloaded Sockets).
11 */
12
13 #define _DEFAULT_SOURCE
14
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <netdb.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
20 #include <poll.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/epoll.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27
28 #include "nsos.h"
29 #include "nsos_errno.h"
30 #include "nsos_fcntl.h"
31 #include "nsos_netdb.h"
32 #include "nsos_socket.h"
33
34 #include "board_soc.h"
35 #include "irq_ctrl.h"
36 #include "nsi_hws_models_if.h"
37 #include "nsi_tasks.h"
38 #include "nsi_tracing.h"
39
40 #include <stdio.h>
41
42 static int nsos_epoll_fd;
43 static int nsos_adapt_nfds;
44
45 #ifndef ARRAY_SIZE
46 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
47 #endif
48
49 #ifndef CONTAINER_OF
50 #define CONTAINER_OF(ptr, type, field) \
51 ((type *)(((char *)(ptr)) - offsetof(type, field)))
52 #endif
53
nsos_adapt_get_errno(void)54 int nsos_adapt_get_errno(void)
55 {
56 return errno_to_nsos_mid(errno);
57 }
58
socket_family_from_nsos_mid(int family_mid,int * family)59 static int socket_family_from_nsos_mid(int family_mid, int *family)
60 {
61 switch (family_mid) {
62 case NSOS_MID_AF_UNSPEC:
63 *family = AF_UNSPEC;
64 break;
65 case NSOS_MID_AF_INET:
66 *family = AF_INET;
67 break;
68 case NSOS_MID_AF_INET6:
69 *family = AF_INET6;
70 break;
71 default:
72 nsi_print_warning("%s: socket family %d not supported\n", __func__, family_mid);
73 return -NSOS_MID_EAFNOSUPPORT;
74 }
75
76 return 0;
77 }
78
socket_family_to_nsos_mid(int family,int * family_mid)79 static int socket_family_to_nsos_mid(int family, int *family_mid)
80 {
81 switch (family) {
82 case AF_UNSPEC:
83 *family_mid = NSOS_MID_AF_UNSPEC;
84 break;
85 case AF_INET:
86 *family_mid = NSOS_MID_AF_INET;
87 break;
88 case AF_INET6:
89 *family_mid = NSOS_MID_AF_INET6;
90 break;
91 default:
92 nsi_print_warning("%s: socket family %d not supported\n", __func__, family);
93 return -NSOS_MID_EAFNOSUPPORT;
94 }
95
96 return 0;
97 }
98
socket_proto_from_nsos_mid(int proto_mid,int * proto)99 static int socket_proto_from_nsos_mid(int proto_mid, int *proto)
100 {
101 switch (proto_mid) {
102 case NSOS_MID_IPPROTO_IP:
103 *proto = IPPROTO_IP;
104 break;
105 case NSOS_MID_IPPROTO_ICMP:
106 *proto = IPPROTO_ICMP;
107 break;
108 case NSOS_MID_IPPROTO_IGMP:
109 *proto = IPPROTO_IGMP;
110 break;
111 case NSOS_MID_IPPROTO_IPIP:
112 *proto = IPPROTO_IPIP;
113 break;
114 case NSOS_MID_IPPROTO_TCP:
115 *proto = IPPROTO_TCP;
116 break;
117 case NSOS_MID_IPPROTO_UDP:
118 *proto = IPPROTO_UDP;
119 break;
120 case NSOS_MID_IPPROTO_IPV6:
121 *proto = IPPROTO_IPV6;
122 break;
123 case NSOS_MID_IPPROTO_RAW:
124 *proto = IPPROTO_RAW;
125 break;
126 default:
127 nsi_print_warning("%s: socket protocol %d not supported\n", __func__, proto_mid);
128 return -NSOS_MID_EPROTONOSUPPORT;
129 }
130
131 return 0;
132 }
133
socket_proto_to_nsos_mid(int proto,int * proto_mid)134 static int socket_proto_to_nsos_mid(int proto, int *proto_mid)
135 {
136 switch (proto) {
137 case IPPROTO_IP:
138 *proto_mid = NSOS_MID_IPPROTO_IP;
139 break;
140 case IPPROTO_ICMP:
141 *proto_mid = NSOS_MID_IPPROTO_ICMP;
142 break;
143 case IPPROTO_IGMP:
144 *proto_mid = NSOS_MID_IPPROTO_IGMP;
145 break;
146 case IPPROTO_IPIP:
147 *proto_mid = NSOS_MID_IPPROTO_IPIP;
148 break;
149 case IPPROTO_TCP:
150 *proto_mid = NSOS_MID_IPPROTO_TCP;
151 break;
152 case IPPROTO_UDP:
153 *proto_mid = NSOS_MID_IPPROTO_UDP;
154 break;
155 case IPPROTO_IPV6:
156 *proto_mid = NSOS_MID_IPPROTO_IPV6;
157 break;
158 case IPPROTO_RAW:
159 *proto_mid = NSOS_MID_IPPROTO_RAW;
160 break;
161 default:
162 nsi_print_warning("%s: socket protocol %d not supported\n", __func__, proto);
163 return -NSOS_MID_EPROTONOSUPPORT;
164 }
165
166 return 0;
167 }
168
socket_type_from_nsos_mid(int type_mid,int * type)169 static int socket_type_from_nsos_mid(int type_mid, int *type)
170 {
171 switch (type_mid) {
172 case NSOS_MID_SOCK_STREAM:
173 *type = SOCK_STREAM;
174 break;
175 case NSOS_MID_SOCK_DGRAM:
176 *type = SOCK_DGRAM;
177 break;
178 case NSOS_MID_SOCK_RAW:
179 *type = SOCK_RAW;
180 break;
181 default:
182 nsi_print_warning("%s: socket type %d not supported\n", __func__, type_mid);
183 return -NSOS_MID_ESOCKTNOSUPPORT;
184 }
185
186 return 0;
187 }
188
socket_type_to_nsos_mid(int type,int * type_mid)189 static int socket_type_to_nsos_mid(int type, int *type_mid)
190 {
191 switch (type) {
192 case SOCK_STREAM:
193 *type_mid = NSOS_MID_SOCK_STREAM;
194 break;
195 case SOCK_DGRAM:
196 *type_mid = NSOS_MID_SOCK_DGRAM;
197 break;
198 case SOCK_RAW:
199 *type_mid = NSOS_MID_SOCK_RAW;
200 break;
201 default:
202 nsi_print_warning("%s: socket type %d not supported\n", __func__, type);
203 return -NSOS_MID_ESOCKTNOSUPPORT;
204 }
205
206 return 0;
207 }
208
socket_flags_from_nsos_mid(int flags_mid)209 static int socket_flags_from_nsos_mid(int flags_mid)
210 {
211 int flags = 0;
212
213 nsos_socket_flag_convert(&flags_mid, NSOS_MID_MSG_PEEK,
214 &flags, MSG_PEEK);
215 nsos_socket_flag_convert(&flags_mid, NSOS_MID_MSG_TRUNC,
216 &flags, MSG_TRUNC);
217 nsos_socket_flag_convert(&flags_mid, NSOS_MID_MSG_DONTWAIT,
218 &flags, MSG_DONTWAIT);
219 nsos_socket_flag_convert(&flags_mid, NSOS_MID_MSG_WAITALL,
220 &flags, MSG_WAITALL);
221
222 if (flags_mid != 0) {
223 return -NSOS_MID_EINVAL;
224 }
225
226 return flags;
227 }
228
nsos_adapt_socket(int family_mid,int type_mid,int proto_mid)229 int nsos_adapt_socket(int family_mid, int type_mid, int proto_mid)
230 {
231 int family;
232 int type;
233 int proto;
234 int ret;
235
236 ret = socket_family_from_nsos_mid(family_mid, &family);
237 if (ret < 0) {
238 return ret;
239 }
240
241 ret = socket_type_from_nsos_mid(type_mid, &type);
242 if (ret < 0) {
243 return ret;
244 }
245
246 ret = socket_proto_from_nsos_mid(proto_mid, &proto);
247 if (ret < 0) {
248 return ret;
249 }
250
251 ret = socket(family, type, proto);
252 if (ret < 0) {
253 return -errno_to_nsos_mid(errno);
254 }
255
256 return ret;
257 }
258
sockaddr_from_nsos_mid(struct sockaddr ** addr,socklen_t * addrlen,const struct nsos_mid_sockaddr * addr_mid,size_t addrlen_mid)259 static int sockaddr_from_nsos_mid(struct sockaddr **addr, socklen_t *addrlen,
260 const struct nsos_mid_sockaddr *addr_mid, size_t addrlen_mid)
261 {
262 if (!addr_mid || addrlen_mid == 0) {
263 *addr = NULL;
264 *addrlen = 0;
265
266 return 0;
267 }
268
269 switch (addr_mid->sa_family) {
270 case NSOS_MID_AF_INET: {
271 const struct nsos_mid_sockaddr_in *addr_in_mid =
272 (const struct nsos_mid_sockaddr_in *)addr_mid;
273 struct sockaddr_in *addr_in = (struct sockaddr_in *)*addr;
274
275 addr_in->sin_family = AF_INET;
276 addr_in->sin_port = addr_in_mid->sin_port;
277 addr_in->sin_addr.s_addr = addr_in_mid->sin_addr;
278
279 *addrlen = sizeof(*addr_in);
280
281 return 0;
282 }
283 case NSOS_MID_AF_INET6: {
284 const struct nsos_mid_sockaddr_in6 *addr_in_mid =
285 (const struct nsos_mid_sockaddr_in6 *)addr_mid;
286 struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)*addr;
287
288 addr_in->sin6_family = AF_INET6;
289 addr_in->sin6_port = addr_in_mid->sin6_port;
290 addr_in->sin6_flowinfo = 0;
291 memcpy(addr_in->sin6_addr.s6_addr, addr_in_mid->sin6_addr,
292 sizeof(addr_in->sin6_addr.s6_addr));
293 addr_in->sin6_scope_id = addr_in_mid->sin6_scope_id;
294
295 *addrlen = sizeof(*addr_in);
296
297 return 0;
298 }
299 }
300
301 return -NSOS_MID_EINVAL;
302 }
303
sockaddr_to_nsos_mid(const struct sockaddr * addr,socklen_t addrlen,struct nsos_mid_sockaddr * addr_mid,size_t * addrlen_mid)304 static int sockaddr_to_nsos_mid(const struct sockaddr *addr, socklen_t addrlen,
305 struct nsos_mid_sockaddr *addr_mid, size_t *addrlen_mid)
306 {
307 if (!addr || addrlen == 0) {
308 *addrlen_mid = 0;
309
310 return 0;
311 }
312
313 switch (addr->sa_family) {
314 case AF_INET: {
315 struct nsos_mid_sockaddr_in *addr_in_mid =
316 (struct nsos_mid_sockaddr_in *)addr_mid;
317 const struct sockaddr_in *addr_in = (const struct sockaddr_in *)addr;
318
319 if (addr_in_mid) {
320 addr_in_mid->sin_family = NSOS_MID_AF_INET;
321 addr_in_mid->sin_port = addr_in->sin_port;
322 addr_in_mid->sin_addr = addr_in->sin_addr.s_addr;
323 }
324
325 if (addrlen_mid) {
326 *addrlen_mid = sizeof(*addr_in);
327 }
328
329 return 0;
330 }
331 case AF_INET6: {
332 struct nsos_mid_sockaddr_in6 *addr_in_mid =
333 (struct nsos_mid_sockaddr_in6 *)addr_mid;
334 const struct sockaddr_in6 *addr_in = (const struct sockaddr_in6 *)addr;
335
336 if (addr_in_mid) {
337 addr_in_mid->sin6_family = NSOS_MID_AF_INET6;
338 addr_in_mid->sin6_port = addr_in->sin6_port;
339 memcpy(addr_in_mid->sin6_addr, addr_in->sin6_addr.s6_addr,
340 sizeof(addr_in_mid->sin6_addr));
341 addr_in_mid->sin6_scope_id = addr_in->sin6_scope_id;
342 }
343
344 if (addrlen_mid) {
345 *addrlen_mid = sizeof(*addr_in);
346 }
347
348 return 0;
349 }
350 }
351
352 nsi_print_warning("%s: socket family %d not supported\n", __func__, addr->sa_family);
353
354 return -NSOS_MID_EINVAL;
355 }
356
nsos_adapt_bind(int fd,const struct nsos_mid_sockaddr * addr_mid,size_t addrlen_mid)357 int nsos_adapt_bind(int fd, const struct nsos_mid_sockaddr *addr_mid, size_t addrlen_mid)
358 {
359 struct sockaddr_storage addr_storage;
360 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
361 socklen_t addrlen;
362 int ret;
363
364 ret = sockaddr_from_nsos_mid(&addr, &addrlen, addr_mid, addrlen_mid);
365 if (ret < 0) {
366 return ret;
367 }
368
369 ret = bind(fd, addr, addrlen);
370 if (ret < 0) {
371 return -errno_to_nsos_mid(errno);
372 }
373
374 return ret;
375 }
376
nsos_adapt_connect(int fd,const struct nsos_mid_sockaddr * addr_mid,size_t addrlen_mid)377 int nsos_adapt_connect(int fd, const struct nsos_mid_sockaddr *addr_mid, size_t addrlen_mid)
378 {
379 struct sockaddr_storage addr_storage;
380 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
381 socklen_t addrlen;
382 int ret;
383
384 ret = sockaddr_from_nsos_mid(&addr, &addrlen, addr_mid, addrlen_mid);
385 if (ret < 0) {
386 return ret;
387 }
388
389 ret = connect(fd, addr, addrlen);
390 if (ret < 0) {
391 return -errno_to_nsos_mid(errno);
392 }
393
394 return ret;
395 }
396
nsos_adapt_listen(int fd,int backlog)397 int nsos_adapt_listen(int fd, int backlog)
398 {
399 int ret;
400
401 ret = listen(fd, backlog);
402 if (ret < 0) {
403 return -errno_to_nsos_mid(errno);
404 }
405
406 return ret;
407 }
408
nsos_adapt_accept(int fd,struct nsos_mid_sockaddr * addr_mid,size_t * addrlen_mid)409 int nsos_adapt_accept(int fd, struct nsos_mid_sockaddr *addr_mid, size_t *addrlen_mid)
410 {
411 struct sockaddr_storage addr_storage;
412 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
413 socklen_t addrlen = sizeof(addr_storage);
414 int ret;
415 int err;
416
417 ret = accept(fd, addr, &addrlen);
418 if (ret < 0) {
419 return -errno_to_nsos_mid(errno);
420 }
421
422 err = sockaddr_to_nsos_mid(addr, addrlen, addr_mid, addrlen_mid);
423 if (err) {
424 close(ret);
425 return err;
426 }
427
428 return ret;
429 }
430
nsos_adapt_sendto(int fd,const void * buf,size_t len,int flags,const struct nsos_mid_sockaddr * addr_mid,size_t addrlen_mid)431 int nsos_adapt_sendto(int fd, const void *buf, size_t len, int flags,
432 const struct nsos_mid_sockaddr *addr_mid, size_t addrlen_mid)
433 {
434 struct sockaddr_storage addr_storage;
435 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
436 socklen_t addrlen;
437 int ret;
438
439 ret = sockaddr_from_nsos_mid(&addr, &addrlen, addr_mid, addrlen_mid);
440 if (ret < 0) {
441 return ret;
442 }
443
444 ret = sendto(fd, buf, len,
445 socket_flags_from_nsos_mid(flags) | MSG_NOSIGNAL,
446 addr, addrlen);
447 if (ret < 0) {
448 return -errno_to_nsos_mid(errno);
449 }
450
451 return ret;
452 }
453
nsos_adapt_sendmsg(int fd,const struct nsos_mid_msghdr * msg_mid,int flags)454 int nsos_adapt_sendmsg(int fd, const struct nsos_mid_msghdr *msg_mid, int flags)
455 {
456 struct sockaddr_storage addr_storage;
457 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
458 struct msghdr msg;
459 struct iovec *msg_iov;
460 socklen_t addrlen;
461 int ret;
462
463 ret = sockaddr_from_nsos_mid(&addr, &addrlen, msg_mid->msg_name, msg_mid->msg_namelen);
464 if (ret < 0) {
465 return ret;
466 }
467
468 msg_iov = calloc(msg_mid->msg_iovlen, sizeof(*msg_iov));
469 if (!msg_iov) {
470 ret = -ENOMEM;
471 return ret;
472 }
473
474 for (size_t i = 0; i < msg_mid->msg_iovlen; i++) {
475 msg_iov[i].iov_base = msg_mid->msg_iov[i].iov_base;
476 msg_iov[i].iov_len = msg_mid->msg_iov[i].iov_len;
477 }
478
479 msg.msg_name = addr;
480 msg.msg_namelen = addrlen;
481 msg.msg_iov = msg_iov;
482 msg.msg_iovlen = msg_mid->msg_iovlen;
483 msg.msg_control = NULL;
484 msg.msg_controllen = 0;
485 msg.msg_flags = 0;
486
487 ret = sendmsg(fd, &msg, socket_flags_from_nsos_mid(flags) | MSG_NOSIGNAL);
488 if (ret < 0) {
489 ret = -errno_to_nsos_mid(errno);
490 }
491
492 free(msg_iov);
493
494 return ret;
495 }
496
nsos_adapt_recvfrom(int fd,void * buf,size_t len,int flags,struct nsos_mid_sockaddr * addr_mid,size_t * addrlen_mid)497 int nsos_adapt_recvfrom(int fd, void *buf, size_t len, int flags,
498 struct nsos_mid_sockaddr *addr_mid, size_t *addrlen_mid)
499 {
500 struct sockaddr_storage addr_storage;
501 struct sockaddr *addr = (struct sockaddr *)&addr_storage;
502 socklen_t addrlen = sizeof(addr_storage);
503 int ret;
504 int err;
505
506 ret = recvfrom(fd, buf, len, socket_flags_from_nsos_mid(flags),
507 addr, &addrlen);
508 if (ret < 0) {
509 return -errno_to_nsos_mid(errno);
510 }
511
512 err = sockaddr_to_nsos_mid(addr, addrlen, addr_mid, addrlen_mid);
513 if (err) {
514 return err;
515 }
516
517 return ret;
518 }
519
nsos_adapt_getsockopt_int(int fd,int level,int optname,void * optval,size_t * nsos_mid_optlen)520 static int nsos_adapt_getsockopt_int(int fd, int level, int optname,
521 void *optval, size_t *nsos_mid_optlen)
522 {
523 socklen_t optlen = *nsos_mid_optlen;
524 int ret;
525
526 ret = getsockopt(fd, level, optname, optval, &optlen);
527 if (ret < 0) {
528 return -errno_to_nsos_mid(errno);
529 }
530
531 *nsos_mid_optlen = optlen;
532
533 return 0;
534 }
535
nsos_adapt_getsockopt(int fd,int nsos_mid_level,int nsos_mid_optname,void * nsos_mid_optval,size_t * nsos_mid_optlen)536 int nsos_adapt_getsockopt(int fd, int nsos_mid_level, int nsos_mid_optname,
537 void *nsos_mid_optval, size_t *nsos_mid_optlen)
538 {
539 switch (nsos_mid_level) {
540 case NSOS_MID_SOL_SOCKET:
541 switch (nsos_mid_optname) {
542 case NSOS_MID_SO_ERROR: {
543 int err;
544 socklen_t optlen = sizeof(err);
545 int ret;
546
547 ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
548 if (ret < 0) {
549 return -errno_to_nsos_mid(errno);
550 }
551
552 *(int *)nsos_mid_optval = errno_to_nsos_mid(err);
553
554 return 0;
555 }
556 case NSOS_MID_SO_TYPE: {
557 int type;
558 socklen_t optlen = sizeof(type);
559 int ret;
560 int err;
561
562 ret = getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
563 if (ret < 0) {
564 return -errno_to_nsos_mid(errno);
565 }
566
567 err = socket_type_to_nsos_mid(type, nsos_mid_optval);
568 if (err) {
569 return err;
570 }
571
572 return 0;
573 }
574 case NSOS_MID_SO_PROTOCOL: {
575 int proto;
576 socklen_t optlen = sizeof(proto);
577 int ret;
578 int err;
579
580 ret = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
581 if (ret < 0) {
582 return -errno_to_nsos_mid(errno);
583 }
584
585 err = socket_proto_to_nsos_mid(proto, nsos_mid_optval);
586 if (err) {
587 return err;
588 }
589
590 return 0;
591 }
592 case NSOS_MID_SO_DOMAIN: {
593 int family;
594 socklen_t optlen = sizeof(family);
595 int ret;
596 int err;
597
598 ret = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &family, &optlen);
599 if (ret < 0) {
600 return -errno_to_nsos_mid(errno);
601 }
602
603 err = socket_family_to_nsos_mid(family, nsos_mid_optval);
604 if (err) {
605 return err;
606 }
607
608 return 0;
609 }
610 case NSOS_MID_SO_RCVBUF:
611 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_RCVBUF,
612 nsos_mid_optval, nsos_mid_optlen);
613 case NSOS_MID_SO_SNDBUF:
614 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_SNDBUF,
615 nsos_mid_optval, nsos_mid_optlen);
616 case NSOS_MID_SO_REUSEADDR:
617 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR,
618 nsos_mid_optval, nsos_mid_optlen);
619 case NSOS_MID_SO_REUSEPORT:
620 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT,
621 nsos_mid_optval, nsos_mid_optlen);
622 case NSOS_MID_SO_LINGER:
623 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_LINGER,
624 nsos_mid_optval, nsos_mid_optlen);
625 case NSOS_MID_SO_KEEPALIVE:
626 return nsos_adapt_getsockopt_int(fd, SOL_SOCKET, SO_KEEPALIVE,
627 nsos_mid_optval, nsos_mid_optlen);
628 }
629 break;
630
631 case NSOS_MID_IPPROTO_TCP:
632 switch (nsos_mid_optname) {
633 case NSOS_MID_TCP_NODELAY:
634 return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY,
635 nsos_mid_optval, nsos_mid_optlen);
636 case NSOS_MID_TCP_KEEPIDLE:
637 return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPIDLE,
638 nsos_mid_optval, nsos_mid_optlen);
639 case NSOS_MID_TCP_KEEPINTVL:
640 return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPINTVL,
641 nsos_mid_optval, nsos_mid_optlen);
642 case NSOS_MID_TCP_KEEPCNT:
643 return nsos_adapt_getsockopt_int(fd, IPPROTO_TCP, TCP_KEEPCNT,
644 nsos_mid_optval, nsos_mid_optlen);
645 }
646 break;
647
648 case NSOS_MID_IPPROTO_IPV6:
649 switch (nsos_mid_optname) {
650 case NSOS_MID_IPV6_V6ONLY:
651 return nsos_adapt_getsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY,
652 nsos_mid_optval, nsos_mid_optlen);
653 }
654 break;
655 }
656
657 return -NSOS_MID_EOPNOTSUPP;
658 }
659
nsos_adapt_setsockopt_int(int fd,int level,int optname,const void * optval,size_t optlen)660 static int nsos_adapt_setsockopt_int(int fd, int level, int optname,
661 const void *optval, size_t optlen)
662 {
663 int ret;
664
665 ret = setsockopt(fd, level, optname, optval, optlen);
666 if (ret < 0) {
667 return -errno_to_nsos_mid(errno);
668 }
669
670 return 0;
671 }
672
nsos_adapt_setsockopt(int fd,int nsos_mid_level,int nsos_mid_optname,const void * nsos_mid_optval,size_t nsos_mid_optlen)673 int nsos_adapt_setsockopt(int fd, int nsos_mid_level, int nsos_mid_optname,
674 const void *nsos_mid_optval, size_t nsos_mid_optlen)
675 {
676 switch (nsos_mid_level) {
677 case NSOS_MID_SOL_SOCKET:
678 switch (nsos_mid_optname) {
679 case NSOS_MID_SO_PRIORITY:
680 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY,
681 nsos_mid_optval, nsos_mid_optlen);
682
683 case NSOS_MID_SO_RCVTIMEO: {
684 const struct nsos_mid_timeval *nsos_mid_tv = nsos_mid_optval;
685 struct timeval tv = {
686 .tv_sec = nsos_mid_tv->tv_sec,
687 .tv_usec = nsos_mid_tv->tv_usec,
688 };
689 int ret;
690
691 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
692 &tv, sizeof(tv));
693 if (ret < 0) {
694 return -errno_to_nsos_mid(errno);
695 }
696
697 return 0;
698 }
699 case NSOS_MID_SO_SNDTIMEO: {
700 const struct nsos_mid_timeval *nsos_mid_tv = nsos_mid_optval;
701 struct timeval tv = {
702 .tv_sec = nsos_mid_tv->tv_sec,
703 .tv_usec = nsos_mid_tv->tv_usec,
704 };
705 int ret;
706
707 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
708 &tv, sizeof(tv));
709 if (ret < 0) {
710 return -errno_to_nsos_mid(errno);
711 }
712
713 return 0;
714 }
715 case NSOS_MID_SO_RCVBUF:
716 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF,
717 nsos_mid_optval, nsos_mid_optlen);
718 case NSOS_MID_SO_SNDBUF:
719 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF,
720 nsos_mid_optval, nsos_mid_optlen);
721 case NSOS_MID_SO_REUSEADDR:
722 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR,
723 nsos_mid_optval, nsos_mid_optlen);
724 case NSOS_MID_SO_REUSEPORT:
725 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT,
726 nsos_mid_optval, nsos_mid_optlen);
727 case NSOS_MID_SO_LINGER:
728 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_LINGER,
729 nsos_mid_optval, nsos_mid_optlen);
730 case NSOS_MID_SO_KEEPALIVE:
731 return nsos_adapt_setsockopt_int(fd, SOL_SOCKET, SO_KEEPALIVE,
732 nsos_mid_optval, nsos_mid_optlen);
733 }
734 break;
735
736 case NSOS_MID_IPPROTO_TCP:
737 switch (nsos_mid_optname) {
738 case NSOS_MID_TCP_NODELAY:
739 return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY,
740 nsos_mid_optval, nsos_mid_optlen);
741 case NSOS_MID_TCP_KEEPIDLE:
742 return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPIDLE,
743 nsos_mid_optval, nsos_mid_optlen);
744 case NSOS_MID_TCP_KEEPINTVL:
745 return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPINTVL,
746 nsos_mid_optval, nsos_mid_optlen);
747 case NSOS_MID_TCP_KEEPCNT:
748 return nsos_adapt_setsockopt_int(fd, IPPROTO_TCP, TCP_KEEPCNT,
749 nsos_mid_optval, nsos_mid_optlen);
750 }
751 break;
752
753 case NSOS_MID_IPPROTO_IPV6:
754 switch (nsos_mid_optname) {
755 case NSOS_MID_IPV6_V6ONLY:
756 return nsos_adapt_setsockopt_int(fd, IPPROTO_IPV6, IPV6_V6ONLY,
757 nsos_mid_optval, nsos_mid_optlen);
758 }
759 break;
760 }
761
762 return -NSOS_MID_EOPNOTSUPP;
763 }
764
765 #define MAP_POLL_EPOLL(_event_from, _event_to) \
766 if (events_from & (_event_from)) { \
767 events_from &= ~(_event_from); \
768 events_to |= _event_to; \
769 }
770
nsos_poll_to_epoll_events(int events_from)771 static int nsos_poll_to_epoll_events(int events_from)
772 {
773 int events_to = 0;
774
775 MAP_POLL_EPOLL(POLLIN, EPOLLIN);
776 MAP_POLL_EPOLL(POLLOUT, EPOLLOUT);
777 MAP_POLL_EPOLL(POLLERR, EPOLLERR);
778 MAP_POLL_EPOLL(POLLHUP, EPOLLHUP);
779
780 return events_to;
781 }
782
nsos_epoll_to_poll_events(int events_from)783 static int nsos_epoll_to_poll_events(int events_from)
784 {
785 int events_to = 0;
786
787 MAP_POLL_EPOLL(EPOLLIN, POLLIN);
788 MAP_POLL_EPOLL(EPOLLOUT, POLLOUT);
789 MAP_POLL_EPOLL(EPOLLERR, POLLERR);
790 MAP_POLL_EPOLL(EPOLLHUP, POLLHUP);
791
792 return events_to;
793 }
794
795 #undef MAP_POLL_EPOLL
796
797 static uint64_t nsos_adapt_poll_time = NSI_NEVER;
798
nsos_adapt_poll_add(struct nsos_mid_pollfd * pollfd)799 void nsos_adapt_poll_add(struct nsos_mid_pollfd *pollfd)
800 {
801 struct epoll_event ev = {
802 .data.ptr = pollfd,
803 .events = nsos_poll_to_epoll_events(pollfd->events),
804 };
805 int err;
806
807 nsos_adapt_nfds++;
808
809 err = epoll_ctl(nsos_epoll_fd, EPOLL_CTL_ADD, pollfd->fd, &ev);
810 if (err) {
811 nsi_print_error_and_exit("error in EPOLL_CTL_ADD: errno=%d\n", errno);
812 return;
813 }
814
815 nsos_adapt_poll_time = nsi_hws_get_time() + 1;
816 nsi_hws_find_next_event();
817 }
818
nsos_adapt_poll_remove(struct nsos_mid_pollfd * pollfd)819 void nsos_adapt_poll_remove(struct nsos_mid_pollfd *pollfd)
820 {
821 int err;
822
823 err = epoll_ctl(nsos_epoll_fd, EPOLL_CTL_DEL, pollfd->fd, NULL);
824 if (err) {
825 nsi_print_error_and_exit("error in EPOLL_CTL_DEL: errno=%d\n", errno);
826 return;
827 }
828
829 nsos_adapt_nfds--;
830 }
831
nsos_adapt_poll_update(struct nsos_mid_pollfd * pollfd)832 void nsos_adapt_poll_update(struct nsos_mid_pollfd *pollfd)
833 {
834 struct pollfd fds = {
835 .fd = pollfd->fd,
836 .events = pollfd->events,
837 };
838 int ret;
839
840 ret = poll(&fds, 1, 0);
841 if (ret < 0) {
842 nsi_print_error_and_exit("error in poll(): errno=%d\n", errno);
843 return;
844 }
845
846 if (ret > 0) {
847 pollfd->revents = fds.revents;
848 }
849 }
850
851 struct nsos_addrinfo_wrap {
852 struct nsos_mid_addrinfo addrinfo_mid;
853 struct nsos_mid_sockaddr_storage addr_storage;
854 struct addrinfo *addrinfo;
855 };
856
addrinfo_to_nsos_mid(struct addrinfo * res,struct nsos_mid_addrinfo ** mid_res)857 static int addrinfo_to_nsos_mid(struct addrinfo *res,
858 struct nsos_mid_addrinfo **mid_res)
859 {
860 struct nsos_addrinfo_wrap *nsos_res_wraps;
861 size_t idx_res = 0;
862 size_t n_res = 0;
863 int ret;
864
865 for (struct addrinfo *res_p = res; res_p; res_p = res_p->ai_next) {
866 n_res++;
867 }
868
869 if (n_res == 0) {
870 return 0;
871 }
872
873 nsos_res_wraps = calloc(n_res, sizeof(*nsos_res_wraps));
874 if (!nsos_res_wraps) {
875 return -NSOS_MID_ENOMEM;
876 }
877
878 for (struct addrinfo *res_p = res; res_p; res_p = res_p->ai_next, idx_res++) {
879 struct nsos_addrinfo_wrap *wrap = &nsos_res_wraps[idx_res];
880
881 wrap->addrinfo = res_p;
882
883 wrap->addrinfo_mid.ai_flags = res_p->ai_flags;
884
885 ret = socket_family_to_nsos_mid(res_p->ai_family, &wrap->addrinfo_mid.ai_family);
886 if (ret < 0) {
887 goto free_wraps;
888 }
889
890 ret = socket_type_to_nsos_mid(res_p->ai_socktype, &wrap->addrinfo_mid.ai_socktype);
891 if (ret < 0) {
892 goto free_wraps;
893 }
894
895 ret = socket_proto_to_nsos_mid(res_p->ai_protocol, &wrap->addrinfo_mid.ai_protocol);
896 if (ret < 0) {
897 goto free_wraps;
898 }
899
900 wrap->addrinfo_mid.ai_addr =
901 (struct nsos_mid_sockaddr *)&wrap->addr_storage;
902 wrap->addrinfo_mid.ai_addrlen = sizeof(wrap->addr_storage);
903
904 ret = sockaddr_to_nsos_mid(res_p->ai_addr, res_p->ai_addrlen,
905 wrap->addrinfo_mid.ai_addr,
906 &wrap->addrinfo_mid.ai_addrlen);
907 if (ret < 0) {
908 goto free_wraps;
909 }
910
911 wrap->addrinfo_mid.ai_canonname =
912 res_p->ai_canonname ? strdup(res_p->ai_canonname) : NULL;
913 wrap->addrinfo_mid.ai_next = &wrap[1].addrinfo_mid;
914 }
915
916 nsos_res_wraps[n_res - 1].addrinfo_mid.ai_next = NULL;
917
918 *mid_res = &nsos_res_wraps->addrinfo_mid;
919
920 return 0;
921
922 free_wraps:
923 for (struct nsos_mid_addrinfo *res_p = &nsos_res_wraps[0].addrinfo_mid;
924 res_p;
925 res_p = res_p->ai_next) {
926 free(res_p->ai_canonname);
927 }
928
929 free(nsos_res_wraps);
930
931 return ret;
932 }
933
nsos_adapt_getaddrinfo(const char * node,const char * service,const struct nsos_mid_addrinfo * hints_mid,struct nsos_mid_addrinfo ** res_mid,int * system_errno)934 int nsos_adapt_getaddrinfo(const char *node, const char *service,
935 const struct nsos_mid_addrinfo *hints_mid,
936 struct nsos_mid_addrinfo **res_mid,
937 int *system_errno)
938 {
939 struct addrinfo hints;
940 struct addrinfo *res = NULL;
941 int ret;
942
943 if (hints_mid) {
944 hints.ai_flags = hints_mid->ai_flags;
945
946 ret = socket_family_from_nsos_mid(hints_mid->ai_family, &hints.ai_family);
947 if (ret < 0) {
948 *system_errno = -ret;
949 return NSOS_MID_EAI_SYSTEM;
950 }
951
952 ret = socket_type_from_nsos_mid(hints_mid->ai_socktype, &hints.ai_socktype);
953 if (ret < 0) {
954 *system_errno = -ret;
955 return NSOS_MID_EAI_SYSTEM;
956 }
957
958 ret = socket_proto_from_nsos_mid(hints_mid->ai_protocol, &hints.ai_protocol);
959 if (ret < 0) {
960 *system_errno = -ret;
961 return NSOS_MID_EAI_SYSTEM;
962 }
963 }
964
965 ret = getaddrinfo(node, service,
966 hints_mid ? &hints : NULL,
967 &res);
968 if (ret < 0) {
969 return ret;
970 }
971
972 ret = addrinfo_to_nsos_mid(res, res_mid);
973 if (ret < 0) {
974 *system_errno = -ret;
975 return NSOS_MID_EAI_SYSTEM;
976 }
977
978 return ret;
979 }
980
nsos_adapt_freeaddrinfo(struct nsos_mid_addrinfo * res_mid)981 void nsos_adapt_freeaddrinfo(struct nsos_mid_addrinfo *res_mid)
982 {
983 struct nsos_addrinfo_wrap *wrap =
984 CONTAINER_OF(res_mid, struct nsos_addrinfo_wrap, addrinfo_mid);
985
986 for (struct nsos_mid_addrinfo *res_p = res_mid; res_p; res_p = res_p->ai_next) {
987 free(res_p->ai_canonname);
988 }
989
990 freeaddrinfo(wrap->addrinfo);
991 free(wrap);
992 }
993
nsos_adapt_fcntl_getfl(int fd)994 int nsos_adapt_fcntl_getfl(int fd)
995 {
996 int flags;
997
998 flags = fcntl(fd, F_GETFL);
999
1000 return fl_to_nsos_mid(flags);
1001 }
1002
nsos_adapt_fcntl_setfl(int fd,int flags)1003 int nsos_adapt_fcntl_setfl(int fd, int flags)
1004 {
1005 int ret;
1006
1007 ret = fcntl(fd, F_SETFL, fl_from_nsos_mid(flags));
1008 if (ret < 0) {
1009 return -errno_to_nsos_mid(errno);
1010 }
1011
1012 return 0;
1013 }
1014
nsos_adapt_fionread(int fd,int * avail)1015 int nsos_adapt_fionread(int fd, int *avail)
1016 {
1017 int ret;
1018
1019 ret = ioctl(fd, FIONREAD, avail);
1020 if (ret < 0) {
1021 return -errno_to_nsos_mid(errno);
1022 }
1023
1024 return 0;
1025 }
1026
nsos_adapt_dup(int oldfd)1027 int nsos_adapt_dup(int oldfd)
1028 {
1029 int ret;
1030
1031 ret = dup(oldfd);
1032 if (ret < 0) {
1033 return -errno_to_nsos_mid(errno);
1034 }
1035
1036 return ret;
1037 }
1038
nsos_adapt_init(void)1039 static void nsos_adapt_init(void)
1040 {
1041 nsos_epoll_fd = epoll_create(1);
1042 if (nsos_epoll_fd < 0) {
1043 nsi_print_error_and_exit("error from epoll_create(): errno=%d\n", errno);
1044 return;
1045 }
1046 }
1047
1048 NSI_TASK(nsos_adapt_init, HW_INIT, 500);
1049
nsos_adapt_poll_triggered(void)1050 static void nsos_adapt_poll_triggered(void)
1051 {
1052 static struct epoll_event events[1024];
1053 int ret;
1054
1055 if (nsos_adapt_nfds == 0) {
1056 nsos_adapt_poll_time = NSI_NEVER;
1057 return;
1058 }
1059
1060 ret = epoll_wait(nsos_epoll_fd, events, ARRAY_SIZE(events), 0);
1061 if (ret < 0) {
1062 if (errno == EINTR) {
1063 nsi_print_warning("interrupted epoll_wait()\n");
1064 nsos_adapt_poll_time = nsi_hws_get_time() + 1;
1065 return;
1066 }
1067
1068 nsi_print_error_and_exit("error in nsos_adapt poll(): errno=%d\n", errno);
1069
1070 nsos_adapt_poll_time = NSI_NEVER;
1071 return;
1072 }
1073
1074 for (int i = 0; i < ret; i++) {
1075 struct nsos_mid_pollfd *pollfd = events[i].data.ptr;
1076
1077 pollfd->revents = nsos_epoll_to_poll_events(events[i].events);
1078 }
1079
1080 if (ret > 0) {
1081 hw_irq_ctrl_set_irq(NSOS_IRQ);
1082 nsos_adapt_poll_time = nsi_hws_get_time() + 1;
1083 } else {
1084 nsos_adapt_poll_time = nsi_hws_get_time() + NSOS_EPOLL_WAIT_INTERVAL;
1085 }
1086 }
1087
1088 NSI_HW_EVENT(nsos_adapt_poll_time, nsos_adapt_poll_triggered, 500);
1089