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