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