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