xref: /netbsd-src/sys/rump/net/lib/libsockin/sockin_user.c (revision e0888b5db503563672b46c6c42066b880d4c1460)
1 /*	$NetBSD: sockin_user.c,v 1.4 2019/03/26 08:56:17 bad Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #ifdef __KERNEL_RCSID
30 __KERNEL_RCSID(0, "$NetBSD: sockin_user.c,v 1.4 2019/03/26 08:56:17 bad Exp $");
31 #endif
32 
33 /* for struct msghdr content visibility */
34 #define _XOPEN_SOURCE 4
35 #define _XOPEN_SOURCE_EXTENDED 1
36 
37 #ifndef _KERNEL
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 
41 #include <errno.h>
42 #include <poll.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdint.h>
46 
47 #include <rump/rumpuser_component.h>
48 #include <rump/rumpdefs.h>
49 
50 #include "sockin_user.h"
51 
52 #define seterror(_v_) if ((_v_) == -1) rv = errno; else rv = 0;
53 
54 #ifndef __arraycount
55 #define __arraycount(a) (sizeof(a) / sizeof(*a))
56 #endif
57 
58 #ifndef __UNCONST
59 #define __UNCONST(a) ((void*)(const void*)a)
60 #endif
61 
62 #include <netinet/in.h>
63 #include <netinet/tcp.h>
64 #include <netinet/udp.h>
65 
66 
67 static int translate_so_sockopt(int);
68 static int translate_ip_sockopt(int);
69 static int translate_tcp_sockopt(int);
70 static int translate_domain(int);
71 
72 #define translate(_a_) case RUMP_##_a_: return _a_
73 static int
translate_so_sockopt(int lopt)74 translate_so_sockopt(int lopt)
75 {
76 
77 	switch (lopt) {
78 	translate(SO_DEBUG);
79 #ifndef SO_REUSEPORT
80 	case RUMP_SO_REUSEPORT: return SO_REUSEADDR;
81 #else
82 	translate(SO_REUSEPORT);
83 #endif
84 	translate(SO_TYPE);
85 	translate(SO_ERROR);
86 	translate(SO_DONTROUTE);
87 	translate(SO_BROADCAST);
88 	translate(SO_SNDBUF);
89 	translate(SO_RCVBUF);
90 	translate(SO_KEEPALIVE);
91 	translate(SO_OOBINLINE);
92 	translate(SO_LINGER);
93 	default: return -1;
94 	}
95 }
96 
97 static int
translate_ip_sockopt(int lopt)98 translate_ip_sockopt(int lopt)
99 {
100 
101 	switch (lopt) {
102 	translate(IP_TOS);
103 	translate(IP_TTL);
104 	translate(IP_HDRINCL);
105 	translate(IP_MULTICAST_TTL);
106 	translate(IP_MULTICAST_LOOP);
107 	translate(IP_MULTICAST_IF);
108 	translate(IP_ADD_MEMBERSHIP);
109 	translate(IP_DROP_MEMBERSHIP);
110 	default: return -1;
111 	}
112 }
113 
114 static int
translate_tcp_sockopt(int lopt)115 translate_tcp_sockopt(int lopt)
116 {
117 
118 	switch (lopt) {
119 	translate(TCP_NODELAY);
120 	translate(TCP_MAXSEG);
121 	default: return -1;
122 	}
123 }
124 
125 static int
translate_domain(int domain)126 translate_domain(int domain)
127 {
128 
129 	switch (domain) {
130 	translate(AF_INET);
131 	translate(AF_INET6);
132 	default: return AF_UNSPEC;
133 	}
134 }
135 
136 #undef translate
137 
138 static void
translate_sockopt(int * levelp,int * namep)139 translate_sockopt(int *levelp, int *namep)
140 {
141 	int level, name;
142 
143 	level = *levelp;
144 	name = *namep;
145 
146 	switch (level) {
147 	case RUMP_SOL_SOCKET:
148 		level = SOL_SOCKET;
149 		name = translate_so_sockopt(name);
150 		break;
151 	case RUMP_IPPROTO_IP:
152 #ifdef SOL_IP
153 		level = SOL_IP;
154 #else
155 		level = IPPROTO_IP;
156 #endif
157 		name = translate_ip_sockopt(name);
158 		break;
159 	case RUMP_IPPROTO_TCP:
160 #ifdef SOL_TCP
161 		level = SOL_TCP;
162 #else
163 		level = IPPROTO_TCP;
164 #endif
165 		name = translate_tcp_sockopt(name);
166 		break;
167 	case RUMP_IPPROTO_UDP:
168 #ifdef SOL_UDP
169 		level = SOL_UDP;
170 #else
171 		level = IPPROTO_UDP;
172 #endif
173 		name = -1;
174 		break;
175 	default:
176 		level = -1;
177 	}
178 	*levelp = level;
179 	*namep = name;
180 }
181 
182 #ifndef __NetBSD__
183 static const struct {
184 	int bfl;
185 	int lfl;
186 } bsd_to_native_msg_flags_[] = {
187 	{RUMP_MSG_OOB,		MSG_OOB},
188 	{RUMP_MSG_PEEK,		MSG_PEEK},
189 	{RUMP_MSG_DONTROUTE,	MSG_DONTROUTE},
190 	{RUMP_MSG_EOR,		MSG_EOR},
191 	{RUMP_MSG_TRUNC,	MSG_TRUNC},
192 	{RUMP_MSG_CTRUNC,	MSG_CTRUNC},
193 	{RUMP_MSG_WAITALL,	MSG_WAITALL},
194 	{RUMP_MSG_DONTWAIT,	MSG_DONTWAIT},
195 
196 	/* might be better to always set NOSIGNAL ... */
197 #ifdef MSG_NOSIGNAL
198 	{RUMP_MSG_NOSIGNAL,	MSG_NOSIGNAL},
199 #endif
200 };
201 
202 static int native_to_bsd_msg_flags(int);
203 
204 static int
native_to_bsd_msg_flags(int lflag)205 native_to_bsd_msg_flags(int lflag)
206 {
207 	unsigned int i;
208 	int bfl, lfl;
209 	int bflag = 0;
210 
211 	if (lflag == 0)
212 		return (0);
213 
214 	for(i = 0; i < __arraycount(bsd_to_native_msg_flags_); i++) {
215 		bfl = bsd_to_native_msg_flags_[i].bfl;
216 		lfl = bsd_to_native_msg_flags_[i].lfl;
217 
218 		if (lflag & lfl) {
219 			lflag ^= lfl;
220 			bflag |= bfl;
221 		}
222 	}
223 	if (lflag != 0)
224 		return (-1);
225 
226 	return (bflag);
227 }
228 
229 static int
bsd_to_native_msg_flags(int bflag)230 bsd_to_native_msg_flags(int bflag)
231 {
232 	unsigned int i;
233 	int lflag = 0;
234 
235 	if (bflag == 0)
236 		return (0);
237 
238 	for(i = 0; i < __arraycount(bsd_to_native_msg_flags_); i++) {
239 		if (bflag & bsd_to_native_msg_flags_[i].bfl)
240 			lflag |= bsd_to_native_msg_flags_[i].lfl;
241 	}
242 
243 	return (lflag);
244 }
245 #endif
246 
247 struct rump_sockaddr {
248 	uint8_t	sa_len;	    /* total length */
249 	uint8_t	sa_family;	/* address family */
250 	char	sa_data[14];	/* actually longer; address value */
251 };
252 
253 struct rump_msghdr {
254 	void		*msg_name;	/* optional address */
255 	uint32_t	msg_namelen;	/* size of address */
256 	struct iovec	*msg_iov;	/* scatter/gather array */
257 	int		msg_iovlen;	/* # elements in msg_iov */
258 	void		*msg_control;	/* ancillary data, see below */
259 	uint32_t	msg_controllen;	/* ancillary data buffer len */
260 	int		msg_flags;	/* flags on received message */
261 };
262 
263 static struct sockaddr *translate_sockaddr(const struct sockaddr *,
264 		uint32_t);
265 static void translate_sockaddr_back(const struct sockaddr *,
266 		struct rump_sockaddr *, uint32_t len);
267 static struct msghdr *translate_msghdr(const struct rump_msghdr *, int *);
268 static void translate_msghdr_back(const struct msghdr *, struct rump_msghdr *);
269 
270 #if defined(__NetBSD__)
271 static struct sockaddr *
translate_sockaddr(const struct sockaddr * addr,uint32_t len)272 translate_sockaddr(const struct sockaddr *addr, uint32_t len)
273 {
274 
275 	return (struct sockaddr *)__UNCONST(addr);
276 }
277 
278 static void
translate_sockaddr_back(const struct sockaddr * laddr,struct rump_sockaddr * baddr,uint32_t len)279 translate_sockaddr_back(const struct sockaddr *laddr,
280 		struct rump_sockaddr *baddr, uint32_t len)
281 {
282 
283 	return;
284 }
285 
286 static struct msghdr *
translate_msghdr(const struct rump_msghdr * bmsg,int * flags)287 translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
288 {
289 
290 	return (struct msghdr *)__UNCONST(bmsg);
291 }
292 
293 static void
translate_msghdr_back(const struct msghdr * lmsg,struct rump_msghdr * bmsg)294 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
295 {
296 
297 	return;
298 }
299 
300 #else
301 static struct sockaddr *
translate_sockaddr(const struct sockaddr * addr,uint32_t len)302 translate_sockaddr(const struct sockaddr *addr, uint32_t len)
303 {
304 	struct sockaddr *laddr;
305 	const struct rump_sockaddr *baddr;
306 
307 	baddr = (const struct rump_sockaddr *)addr;
308 	laddr = malloc(len);
309 	if (laddr == NULL)
310 		return NULL;
311 	memcpy(laddr, baddr, len);
312 	laddr->sa_family = translate_domain(baddr->sa_family);
313 	/* No sa_len for Linux and SunOS */
314 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
315 	laddr->sa_len = len;
316 #endif
317 	return laddr;
318 }
319 
320 #define translate_back(_a_) case _a_: return RUMP_##_a_
321 static int translate_domain_back(int);
322 static int
translate_domain_back(int domain)323 translate_domain_back(int domain)
324 {
325 
326 	switch (domain) {
327 	translate_back(AF_INET);
328 	translate_back(AF_INET6);
329 	default: return RUMP_AF_UNSPEC;
330 	}
331 }
332 #undef translate_back
333 
334 static void
translate_sockaddr_back(const struct sockaddr * laddr,struct rump_sockaddr * baddr,uint32_t len)335 translate_sockaddr_back(const struct sockaddr *laddr,
336 		struct rump_sockaddr *baddr,
337 		uint32_t len)
338 {
339 
340 	if (baddr != NULL) {
341 		memcpy(baddr, laddr, len);
342 		baddr->sa_family = translate_domain_back(laddr->sa_family);
343 		baddr->sa_len = len;
344 	}
345 	free(__UNCONST(laddr));
346 }
347 
348 static struct msghdr *
translate_msghdr(const struct rump_msghdr * bmsg,int * flags)349 translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
350 {
351 	struct msghdr *rv;
352 
353 	*flags = bsd_to_native_msg_flags(*flags);
354 	if (*flags < 0)
355 		*flags = 0;
356 
357 	rv = malloc(sizeof(*rv));
358 	rv->msg_namelen = bmsg->msg_namelen;
359 	rv->msg_iov = bmsg->msg_iov;
360 	rv->msg_iovlen = bmsg->msg_iovlen;
361 	rv->msg_control = bmsg->msg_control;
362 	rv->msg_controllen = bmsg->msg_controllen;
363 	rv->msg_flags = 0;
364 
365 	if (bmsg->msg_name != NULL) {
366 		rv->msg_name = translate_sockaddr(bmsg->msg_name,
367 				bmsg->msg_namelen);
368 		if (rv->msg_name == NULL) {
369 			free(rv);
370 			return NULL;
371 		}
372 	} else
373 		rv->msg_name = NULL;
374 	return rv;
375 }
376 
377 static void
translate_msghdr_back(const struct msghdr * lmsg,struct rump_msghdr * bmsg)378 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
379 {
380 
381 	if (bmsg == NULL) {
382 		if (lmsg->msg_name != NULL)
383 			free(lmsg->msg_name);
384 		free(__UNCONST(lmsg));
385 		return;
386 	}
387 	bmsg->msg_namelen = lmsg->msg_namelen;
388 	bmsg->msg_iov = lmsg->msg_iov;
389 	bmsg->msg_iovlen = lmsg->msg_iovlen;
390 	bmsg->msg_control = lmsg->msg_control;
391 	bmsg->msg_controllen = lmsg->msg_controllen;
392 	bmsg->msg_flags = native_to_bsd_msg_flags(lmsg->msg_flags);
393 
394 	if (lmsg->msg_name != NULL)
395 		translate_sockaddr_back(lmsg->msg_name, bmsg->msg_name,
396 				bmsg->msg_namelen);
397 	else
398 		bmsg->msg_name = NULL;
399 
400 	free(__UNCONST(lmsg));
401 }
402 #endif
403 
404 int
rumpcomp_sockin_socket(int domain,int type,int proto,int * s)405 rumpcomp_sockin_socket(int domain, int type, int proto, int *s)
406 {
407 	void *cookie;
408 	int rv;
409 
410 	domain = translate_domain(domain);
411 
412 	cookie = rumpuser_component_unschedule();
413 	*s = socket(domain, type, proto);
414 	seterror(*s);
415 	rumpuser_component_schedule(cookie);
416 
417 	return rumpuser_component_errtrans(rv);
418 }
419 
420 int
rumpcomp_sockin_sendmsg(int s,const struct msghdr * msg,int flags,size_t * snd)421 rumpcomp_sockin_sendmsg(int s, const struct msghdr *msg, int flags, size_t *snd)
422 {
423 	void *cookie;
424 	ssize_t nn;
425 	int rv;
426 
427 	msg = translate_msghdr((struct rump_msghdr *)msg, &flags);
428 
429 	cookie = rumpuser_component_unschedule();
430 	nn = sendmsg(s, msg, flags);
431 	seterror(nn);
432 	*snd = (size_t)nn;
433 	rumpuser_component_schedule(cookie);
434 
435 	translate_msghdr_back(msg, NULL);
436 
437 	return rumpuser_component_errtrans(rv);
438 }
439 
440 int
rumpcomp_sockin_recvmsg(int s,struct msghdr * msg,int flags,size_t * rcv)441 rumpcomp_sockin_recvmsg(int s, struct msghdr *msg, int flags, size_t *rcv)
442 {
443 	void *cookie;
444 	ssize_t nn;
445 	int rv;
446 	struct rump_msghdr *saveptr;
447 
448 	saveptr = (struct rump_msghdr *)msg;
449 	msg = translate_msghdr(saveptr, &flags);
450 
451 	cookie = rumpuser_component_unschedule();
452 	nn = recvmsg(s, msg, flags);
453 	seterror(nn);
454 	*rcv = (size_t)nn;
455 	rumpuser_component_schedule(cookie);
456 
457 	translate_msghdr_back(msg, saveptr);
458 
459 	return rumpuser_component_errtrans(rv);
460 }
461 
462 int
rumpcomp_sockin_connect(int s,const struct sockaddr * name,int len)463 rumpcomp_sockin_connect(int s, const struct sockaddr *name, int len)
464 {
465 	void *cookie;
466 	int rv;
467 
468 	name = translate_sockaddr(name, len);
469 
470 	cookie = rumpuser_component_unschedule();
471 	rv = connect(s, name, (socklen_t)len);
472 	seterror(rv);
473 	rumpuser_component_schedule(cookie);
474 
475 	translate_sockaddr_back(name, NULL, len);
476 
477 	return rumpuser_component_errtrans(rv);
478 }
479 
480 int
rumpcomp_sockin_bind(int s,const struct sockaddr * name,int len)481 rumpcomp_sockin_bind(int s, const struct sockaddr *name, int len)
482 {
483 	void *cookie;
484 	int rv;
485 
486 	name = translate_sockaddr(name, len);
487 
488 	cookie = rumpuser_component_unschedule();
489 	rv = bind(s, name, (socklen_t)len);
490 	seterror(rv);
491 	rumpuser_component_schedule(cookie);
492 
493 	translate_sockaddr_back(name, NULL, len);
494 
495 	return rumpuser_component_errtrans(rv);
496 }
497 
498 int
rumpcomp_sockin_accept(int s,struct sockaddr * name,int * lenp,int * s2)499 rumpcomp_sockin_accept(int s, struct sockaddr *name, int *lenp, int *s2)
500 {
501 	void *cookie;
502 	int rv;
503 	struct rump_sockaddr *saveptr;
504 
505 	saveptr = (struct rump_sockaddr *)name;
506 	name = translate_sockaddr(name, *lenp);
507 
508 	cookie = rumpuser_component_unschedule();
509 	*s2 = accept(s, name, (socklen_t *)lenp);
510 	seterror(*s2);
511 	rumpuser_component_schedule(cookie);
512 
513 	translate_sockaddr_back(name, saveptr, *lenp);
514 
515 	return rumpuser_component_errtrans(rv);
516 }
517 
518 int
rumpcomp_sockin_listen(int s,int backlog)519 rumpcomp_sockin_listen(int s, int backlog)
520 {
521 	void *cookie;
522 	int rv;
523 
524 	cookie = rumpuser_component_unschedule();
525 	rv = listen(s, backlog);
526 	seterror(rv);
527 	rumpuser_component_schedule(cookie);
528 
529 	return rumpuser_component_errtrans(rv);
530 }
531 
532 int
rumpcomp_sockin_getname(int s,struct sockaddr * so,int * lenp,enum rumpcomp_sockin_getnametype which)533 rumpcomp_sockin_getname(int s, struct sockaddr *so, int *lenp,
534 	enum rumpcomp_sockin_getnametype which)
535 {
536 	socklen_t slen = *lenp;
537 	int rv;
538 	struct rump_sockaddr *saveptr;
539 
540 	saveptr = (struct rump_sockaddr *)so;
541 	so = translate_sockaddr(so, *lenp);
542 
543 	if (which == RUMPCOMP_SOCKIN_SOCKNAME)
544 		rv = getsockname(s, so, &slen);
545 	else
546 		rv = getpeername(s, so, &slen);
547 
548 	seterror(rv);
549 	translate_sockaddr_back(so, saveptr, *lenp);
550 
551 	*lenp = slen;
552 
553 	return rumpuser_component_errtrans(rv);
554 }
555 
556 int
rumpcomp_sockin_setsockopt(int s,int level,int name,const void * data,int dlen)557 rumpcomp_sockin_setsockopt(int s, int level, int name,
558 	const void *data, int dlen)
559 {
560 	socklen_t slen = dlen;
561 	int rv;
562 
563 	translate_sockopt(&level, &name);
564 	if (level == -1 || name == -1) {
565 #ifdef SETSOCKOPT_STRICT
566 		errno = EINVAL;
567 		rv = -1;
568 #else
569 		rv = 0;
570 #endif
571 	} else
572 		rv = setsockopt(s, level, name, data, slen);
573 
574 	seterror(rv);
575 
576 	return rumpuser_component_errtrans(rv);
577 }
578 
579 int
rumpcomp_sockin_poll(struct pollfd * fds,int nfds,int timeout,int * nready)580 rumpcomp_sockin_poll(struct pollfd *fds, int nfds, int timeout, int *nready)
581 {
582 	void *cookie;
583 	int rv;
584 
585 	cookie = rumpuser_component_unschedule();
586 	*nready = poll(fds, (nfds_t)nfds, timeout);
587 	seterror(*nready);
588 	rumpuser_component_schedule(cookie);
589 
590 	return rumpuser_component_errtrans(rv);
591 }
592 #endif
593