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