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