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
67static int translate_so_sockopt(int);
68static int translate_ip_sockopt(int);
69static int translate_tcp_sockopt(int);
70static int translate_domain(int);
71
72#define translate(_a_) case RUMP_##_a_: return _a_
73static int
74translate_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
97static int
98translate_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
114static int
115translate_tcp_sockopt(int lopt)
116{
117
118	switch (lopt) {
119	translate(TCP_NODELAY);
120	translate(TCP_MAXSEG);
121	default: return -1;
122	}
123}
124
125static int
126translate_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
138static void
139translate_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__
183static 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
202static int native_to_bsd_msg_flags(int);
203
204static int
205native_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
229static int
230bsd_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
247struct 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
253struct 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
263static struct sockaddr *translate_sockaddr(const struct sockaddr *,
264		uint32_t);
265static void translate_sockaddr_back(const struct sockaddr *,
266		struct rump_sockaddr *, uint32_t len);
267static struct msghdr *translate_msghdr(const struct rump_msghdr *, int *);
268static void translate_msghdr_back(const struct msghdr *, struct rump_msghdr *);
269
270#if defined(__NetBSD__)
271static struct sockaddr *
272translate_sockaddr(const struct sockaddr *addr, uint32_t len)
273{
274
275	return (struct sockaddr *)__UNCONST(addr);
276}
277
278static void
279translate_sockaddr_back(const struct sockaddr *laddr,
280		struct rump_sockaddr *baddr, uint32_t len)
281{
282
283	return;
284}
285
286static struct msghdr *
287translate_msghdr(const struct rump_msghdr *bmsg, int *flags)
288{
289
290	return (struct msghdr *)__UNCONST(bmsg);
291}
292
293static void
294translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg)
295{
296
297	return;
298}
299
300#else
301static struct sockaddr *
302translate_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_
321static int translate_domain_back(int);
322static int
323translate_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
334static void
335translate_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
348static struct msghdr *
349translate_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
377static void
378translate_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
404int
405rumpcomp_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
420int
421rumpcomp_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
440int
441rumpcomp_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
462int
463rumpcomp_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
480int
481rumpcomp_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
498int
499rumpcomp_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
518int
519rumpcomp_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
532int
533rumpcomp_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
556int
557rumpcomp_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
579int
580rumpcomp_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