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 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 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 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 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 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 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 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 * 272 translate_sockaddr(const struct sockaddr *addr, uint32_t len) 273 { 274 275 return (struct sockaddr *)__UNCONST(addr); 276 } 277 278 static void 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 * 287 translate_msghdr(const struct rump_msghdr *bmsg, int *flags) 288 { 289 290 return (struct msghdr *)__UNCONST(bmsg); 291 } 292 293 static void 294 translate_msghdr_back(const struct msghdr *lmsg, struct rump_msghdr *bmsg) 295 { 296 297 return; 298 } 299 300 #else 301 static struct sockaddr * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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