1 /*- 2 * Copyright (c) 1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 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 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 /* XXX we use functions that might not exist. */ 32 #include "opt_compat.h" 33 34 #ifndef COMPAT_43 35 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/proc.h> 40 #include <sys/systm.h> 41 #include <sys/sysproto.h> 42 #include <sys/fcntl.h> 43 #include <sys/socket.h> 44 #include <sys/uio.h> 45 46 #include <netinet/in.h> 47 #include <netinet/in_systm.h> 48 #include <netinet/ip.h> 49 50 #include <i386/linux/linux.h> 51 #include <i386/linux/linux_proto.h> 52 #include <i386/linux/linux_util.h> 53 54 static int 55 linux_to_bsd_domain(int domain) 56 { 57 switch (domain) { 58 case LINUX_AF_UNSPEC: 59 return AF_UNSPEC; 60 case LINUX_AF_UNIX: 61 return AF_LOCAL; 62 case LINUX_AF_INET: 63 return AF_INET; 64 case LINUX_AF_AX25: 65 return AF_CCITT; 66 case LINUX_AF_IPX: 67 return AF_IPX; 68 case LINUX_AF_APPLETALK: 69 return AF_APPLETALK; 70 default: 71 return -1; 72 } 73 } 74 75 static int 76 linux_to_bsd_sockopt_level(int level) 77 { 78 switch (level) { 79 case LINUX_SOL_SOCKET: 80 return SOL_SOCKET; 81 default: 82 return level; 83 } 84 } 85 86 static int linux_to_bsd_ip_sockopt(int opt) 87 { 88 switch (opt) { 89 case LINUX_IP_TOS: 90 return IP_TOS; 91 case LINUX_IP_TTL: 92 return IP_TTL; 93 case LINUX_IP_OPTIONS: 94 return IP_OPTIONS; 95 case LINUX_IP_MULTICAST_IF: 96 return IP_MULTICAST_IF; 97 case LINUX_IP_MULTICAST_TTL: 98 return IP_MULTICAST_TTL; 99 case LINUX_IP_MULTICAST_LOOP: 100 return IP_MULTICAST_LOOP; 101 case LINUX_IP_ADD_MEMBERSHIP: 102 return IP_ADD_MEMBERSHIP; 103 case LINUX_IP_DROP_MEMBERSHIP: 104 return IP_DROP_MEMBERSHIP; 105 case LINUX_IP_HDRINCL: 106 return IP_HDRINCL; 107 default: 108 return -1; 109 } 110 } 111 112 static int 113 linux_to_bsd_so_sockopt(int opt) 114 { 115 switch (opt) { 116 case LINUX_SO_DEBUG: 117 return SO_DEBUG; 118 case LINUX_SO_REUSEADDR: 119 return SO_REUSEADDR; 120 case LINUX_SO_TYPE: 121 return SO_TYPE; 122 case LINUX_SO_ERROR: 123 return SO_ERROR; 124 case LINUX_SO_DONTROUTE: 125 return SO_DONTROUTE; 126 case LINUX_SO_BROADCAST: 127 return SO_BROADCAST; 128 case LINUX_SO_SNDBUF: 129 return SO_SNDBUF; 130 case LINUX_SO_RCVBUF: 131 return SO_RCVBUF; 132 case LINUX_SO_KEEPALIVE: 133 return SO_KEEPALIVE; 134 case LINUX_SO_OOBINLINE: 135 return SO_OOBINLINE; 136 case LINUX_SO_LINGER: 137 return SO_LINGER; 138 case LINUX_SO_PRIORITY: 139 case LINUX_SO_NO_CHECK: 140 default: 141 return -1; 142 } 143 } 144 145 /* Return 0 if IP_HDRINCL is set of the given socket, not 0 otherwise */ 146 static int 147 linux_check_hdrincl(struct proc *p, int s) 148 { 149 struct getsockopt_args /* { 150 int s; 151 int level; 152 int name; 153 caddr_t val; 154 int *avalsize; 155 } */ bsd_args; 156 int error; 157 caddr_t sg, val, valsize; 158 int size_val = sizeof val; 159 int optval; 160 161 sg = stackgap_init(); 162 val = stackgap_alloc(&sg, sizeof(int)); 163 valsize = stackgap_alloc(&sg, sizeof(int)); 164 165 if ((error=copyout(&size_val, valsize, sizeof(size_val)))) 166 return error; 167 bsd_args.s = s; 168 bsd_args.level = IPPROTO_IP; 169 bsd_args.name = IP_HDRINCL; 170 bsd_args.val = val; 171 bsd_args.avalsize = (int *)valsize; 172 if ((error=getsockopt(p, &bsd_args))) 173 return error; 174 if ((error=copyin(val, &optval, sizeof(optval)))) 175 return error; 176 return optval == 0; 177 } 178 179 /* 180 * Updated sendto() when IP_HDRINCL is set: 181 * tweak endian-dependent fields in the IP packet. 182 */ 183 static int 184 linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args) 185 { 186 /* 187 * linux_ip_copysize defines how many bytes we should copy 188 * from the beginning of the IP packet before we customize it for BSD. 189 * It should include all the fields we modify (ip_len and ip_off) 190 * and be as small as possible to minimize copying overhead. 191 */ 192 #define linux_ip_copysize 8 193 194 caddr_t sg; 195 struct ip *packet; 196 struct msghdr *msg; 197 struct iovec *iov; 198 199 int error; 200 struct sendmsg_args /* { 201 int s; 202 caddr_t msg; 203 int flags; 204 } */ sendmsg_args; 205 206 /* Check the packet isn't too small before we mess with it */ 207 if (bsd_args->len < linux_ip_copysize) 208 return EINVAL; 209 210 /* 211 * Tweaking the user buffer in place would be bad manners. 212 * We create a corrected IP header with just the needed length, 213 * then use an iovec to glue it to the rest of the user packet 214 * when calling sendmsg(). 215 */ 216 sg = stackgap_init(); 217 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 218 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 219 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 220 221 /* Make a copy of the beginning of the packet to be sent */ 222 if ((error = copyin(bsd_args->buf, (caddr_t)packet, linux_ip_copysize))) 223 return error; 224 225 /* Convert fields from Linux to BSD raw IP socket format */ 226 packet->ip_len = bsd_args->len; 227 packet->ip_off = ntohs(packet->ip_off); 228 229 /* Prepare the msghdr and iovec structures describing the new packet */ 230 msg->msg_name = bsd_args->to; 231 msg->msg_namelen = bsd_args->tolen; 232 msg->msg_iov = iov; 233 msg->msg_iovlen = 2; 234 msg->msg_control = NULL; 235 msg->msg_controllen = 0; 236 msg->msg_flags = 0; 237 iov[0].iov_base = (char *)packet; 238 iov[0].iov_len = linux_ip_copysize; 239 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 240 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 241 242 sendmsg_args.s = bsd_args->s; 243 sendmsg_args.msg = (caddr_t)msg; 244 sendmsg_args.flags = bsd_args->flags; 245 return sendmsg(p, &sendmsg_args); 246 } 247 248 struct linux_socket_args { 249 int domain; 250 int type; 251 int protocol; 252 }; 253 254 static int 255 linux_socket(struct proc *p, struct linux_socket_args *args) 256 { 257 struct linux_socket_args linux_args; 258 struct socket_args /* { 259 int domain; 260 int type; 261 int protocol; 262 } */ bsd_args; 263 int error; 264 int retval_socket; 265 266 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 267 return error; 268 bsd_args.protocol = linux_args.protocol; 269 bsd_args.type = linux_args.type; 270 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 271 if (bsd_args.domain == -1) 272 return EINVAL; 273 274 retval_socket = socket(p, &bsd_args); 275 if (bsd_args.type == SOCK_RAW 276 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 277 && bsd_args.domain == AF_INET 278 && retval_socket >= 0) { 279 /* It's a raw IP socket: set the IP_HDRINCL option. */ 280 struct setsockopt_args /* { 281 int s; 282 int level; 283 int name; 284 caddr_t val; 285 int valsize; 286 } */ bsd_setsockopt_args; 287 caddr_t sg; 288 int *hdrincl; 289 290 sg = stackgap_init(); 291 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 292 *hdrincl = 1; 293 bsd_setsockopt_args.s = p->p_retval[0]; 294 bsd_setsockopt_args.level = IPPROTO_IP; 295 bsd_setsockopt_args.name = IP_HDRINCL; 296 bsd_setsockopt_args.val = (caddr_t)hdrincl; 297 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 298 /* We ignore any error returned by setsockopt() */ 299 setsockopt(p, &bsd_setsockopt_args); 300 /* Copy back the return value from socket() */ 301 p->p_retval[0] = bsd_setsockopt_args.s; 302 } 303 return retval_socket; 304 } 305 306 struct linux_bind_args { 307 int s; 308 struct sockaddr *name; 309 int namelen; 310 }; 311 312 static int 313 linux_bind(struct proc *p, struct linux_bind_args *args) 314 { 315 struct linux_bind_args linux_args; 316 struct bind_args /* { 317 int s; 318 caddr_t name; 319 int namelen; 320 } */ bsd_args; 321 int error; 322 323 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 324 return error; 325 bsd_args.s = linux_args.s; 326 bsd_args.name = (caddr_t)linux_args.name; 327 bsd_args.namelen = linux_args.namelen; 328 return bind(p, &bsd_args); 329 } 330 331 struct linux_connect_args { 332 int s; 333 struct sockaddr * name; 334 int namelen; 335 }; 336 337 static int 338 linux_connect(struct proc *p, struct linux_connect_args *args) 339 { 340 struct linux_connect_args linux_args; 341 struct connect_args /* { 342 int s; 343 caddr_t name; 344 int namelen; 345 } */ bsd_args; 346 int error; 347 348 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 349 return error; 350 bsd_args.s = linux_args.s; 351 bsd_args.name = (caddr_t)linux_args.name; 352 bsd_args.namelen = linux_args.namelen; 353 error = connect(p, &bsd_args); 354 if (error == EISCONN) { 355 /* 356 * Linux doesn't return EISCONN the first time it occurs, 357 * when on a non-blocking socket. Instead it returns the 358 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 359 */ 360 struct fcntl_args /* { 361 int fd; 362 int cmd; 363 int arg; 364 } */ bsd_fcntl_args; 365 struct getsockopt_args /* { 366 int s; 367 int level; 368 int name; 369 caddr_t val; 370 int *avalsize; 371 } */ bsd_getsockopt_args; 372 void *status, *statusl; 373 int stat, statl = sizeof stat; 374 caddr_t sg; 375 376 /* Check for non-blocking */ 377 bsd_fcntl_args.fd = linux_args.s; 378 bsd_fcntl_args.cmd = F_GETFL; 379 bsd_fcntl_args.arg = 0; 380 error = fcntl(p, &bsd_fcntl_args); 381 if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) { 382 sg = stackgap_init(); 383 status = stackgap_alloc(&sg, sizeof stat); 384 statusl = stackgap_alloc(&sg, sizeof statusl); 385 386 if ((error = copyout(&statl, statusl, sizeof statl))) 387 return error; 388 389 bsd_getsockopt_args.s = linux_args.s; 390 bsd_getsockopt_args.level = SOL_SOCKET; 391 bsd_getsockopt_args.name = SO_ERROR; 392 bsd_getsockopt_args.val = status; 393 bsd_getsockopt_args.avalsize = statusl; 394 395 error = getsockopt(p, &bsd_getsockopt_args); 396 if (error) 397 return error; 398 if ((error = copyin(status, &stat, sizeof stat))) 399 return error; 400 p->p_retval[0] = stat; 401 return 0; 402 } 403 } 404 return error; 405 } 406 407 struct linux_listen_args { 408 int s; 409 int backlog; 410 }; 411 412 static int 413 linux_listen(struct proc *p, struct linux_listen_args *args) 414 { 415 struct linux_listen_args linux_args; 416 struct listen_args /* { 417 int s; 418 int backlog; 419 } */ bsd_args; 420 int error; 421 422 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 423 return error; 424 bsd_args.s = linux_args.s; 425 bsd_args.backlog = linux_args.backlog; 426 return listen(p, &bsd_args); 427 } 428 429 struct linux_accept_args { 430 int s; 431 struct sockaddr *addr; 432 int *namelen; 433 }; 434 435 static int 436 linux_accept(struct proc *p, struct linux_accept_args *args) 437 { 438 struct linux_accept_args linux_args; 439 struct accept_args /* { 440 int s; 441 caddr_t name; 442 int *anamelen; 443 } */ bsd_args; 444 struct fcntl_args /* { 445 int fd; 446 int cmd; 447 long arg; 448 } */ f_args; 449 int error; 450 451 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 452 return error; 453 bsd_args.s = linux_args.s; 454 bsd_args.name = (caddr_t)linux_args.addr; 455 bsd_args.anamelen = linux_args.namelen; 456 error = oaccept(p, &bsd_args); 457 if (error) 458 return (error); 459 460 /* 461 * linux appears not to copy flags from the parent socket to the 462 * accepted one, so we must clear the flags in the new descriptor. 463 * Ignore any errors, because we already have an open fd. 464 */ 465 f_args.fd = p->p_retval[0]; 466 f_args.cmd = F_SETFL; 467 f_args.arg = 0; 468 (void)fcntl(p, &f_args); 469 p->p_retval[0] = f_args.fd; 470 return (0); 471 } 472 473 struct linux_getsockname_args { 474 int s; 475 struct sockaddr *addr; 476 int *namelen; 477 }; 478 479 static int 480 linux_getsockname(struct proc *p, struct linux_getsockname_args *args) 481 { 482 struct linux_getsockname_args linux_args; 483 struct getsockname_args /* { 484 int fdes; 485 caddr_t asa; 486 int *alen; 487 } */ bsd_args; 488 int error; 489 490 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 491 return error; 492 bsd_args.fdes = linux_args.s; 493 bsd_args.asa = (caddr_t) linux_args.addr; 494 bsd_args.alen = linux_args.namelen; 495 return ogetsockname(p, &bsd_args); 496 } 497 498 struct linux_getpeername_args { 499 int s; 500 struct sockaddr *addr; 501 int *namelen; 502 }; 503 504 static int 505 linux_getpeername(struct proc *p, struct linux_getpeername_args *args) 506 { 507 struct linux_getpeername_args linux_args; 508 struct ogetpeername_args /* { 509 int fdes; 510 caddr_t asa; 511 int *alen; 512 } */ bsd_args; 513 int error; 514 515 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 516 return error; 517 bsd_args.fdes = linux_args.s; 518 bsd_args.asa = (caddr_t) linux_args.addr; 519 bsd_args.alen = linux_args.namelen; 520 return ogetpeername(p, &bsd_args); 521 } 522 523 struct linux_socketpair_args { 524 int domain; 525 int type; 526 int protocol; 527 int *rsv; 528 }; 529 530 static int 531 linux_socketpair(struct proc *p, struct linux_socketpair_args *args) 532 { 533 struct linux_socketpair_args linux_args; 534 struct socketpair_args /* { 535 int domain; 536 int type; 537 int protocol; 538 int *rsv; 539 } */ bsd_args; 540 int error; 541 542 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 543 return error; 544 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 545 if (bsd_args.domain == -1) 546 return EINVAL; 547 bsd_args.type = linux_args.type; 548 bsd_args.protocol = linux_args.protocol; 549 bsd_args.rsv = linux_args.rsv; 550 return socketpair(p, &bsd_args); 551 } 552 553 struct linux_send_args { 554 int s; 555 void *msg; 556 int len; 557 int flags; 558 }; 559 560 static int 561 linux_send(struct proc *p, struct linux_send_args *args) 562 { 563 struct linux_send_args linux_args; 564 struct osend_args /* { 565 int s; 566 caddr_t buf; 567 int len; 568 int flags; 569 } */ bsd_args; 570 int error; 571 572 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 573 return error; 574 bsd_args.s = linux_args.s; 575 bsd_args.buf = linux_args.msg; 576 bsd_args.len = linux_args.len; 577 bsd_args.flags = linux_args.flags; 578 return osend(p, &bsd_args); 579 } 580 581 struct linux_recv_args { 582 int s; 583 void *msg; 584 int len; 585 int flags; 586 }; 587 588 static int 589 linux_recv(struct proc *p, struct linux_recv_args *args) 590 { 591 struct linux_recv_args linux_args; 592 struct orecv_args /* { 593 int s; 594 caddr_t buf; 595 int len; 596 int flags; 597 } */ bsd_args; 598 int error; 599 600 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 601 return error; 602 bsd_args.s = linux_args.s; 603 bsd_args.buf = linux_args.msg; 604 bsd_args.len = linux_args.len; 605 bsd_args.flags = linux_args.flags; 606 return orecv(p, &bsd_args); 607 } 608 609 struct linux_sendto_args { 610 int s; 611 void *msg; 612 int len; 613 int flags; 614 caddr_t to; 615 int tolen; 616 }; 617 618 static int 619 linux_sendto(struct proc *p, struct linux_sendto_args *args) 620 { 621 struct linux_sendto_args linux_args; 622 struct sendto_args /* { 623 int s; 624 caddr_t buf; 625 size_t len; 626 int flags; 627 caddr_t to; 628 int tolen; 629 } */ bsd_args; 630 int error; 631 632 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 633 return error; 634 bsd_args.s = linux_args.s; 635 bsd_args.buf = linux_args.msg; 636 bsd_args.len = linux_args.len; 637 bsd_args.flags = linux_args.flags; 638 bsd_args.to = linux_args.to; 639 bsd_args.tolen = linux_args.tolen; 640 641 if (linux_check_hdrincl(p, linux_args.s) == 0) 642 /* IP_HDRINCL set, tweak the packet before sending */ 643 return linux_sendto_hdrincl(p, &bsd_args); 644 645 return sendto(p, &bsd_args); 646 } 647 648 struct linux_recvfrom_args { 649 int s; 650 void *buf; 651 int len; 652 int flags; 653 caddr_t from; 654 int *fromlen; 655 }; 656 657 static int 658 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args) 659 { 660 struct linux_recvfrom_args linux_args; 661 struct recvfrom_args /* { 662 int s; 663 caddr_t buf; 664 size_t len; 665 int flags; 666 caddr_t from; 667 int *fromlenaddr; 668 } */ bsd_args; 669 int error; 670 671 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 672 return error; 673 bsd_args.s = linux_args.s; 674 bsd_args.buf = linux_args.buf; 675 bsd_args.len = linux_args.len; 676 bsd_args.flags = linux_args.flags; 677 bsd_args.from = linux_args.from; 678 bsd_args.fromlenaddr = linux_args.fromlen; 679 return orecvfrom(p, &bsd_args); 680 } 681 682 struct linux_shutdown_args { 683 int s; 684 int how; 685 }; 686 687 static int 688 linux_shutdown(struct proc *p, struct linux_shutdown_args *args) 689 { 690 struct linux_shutdown_args linux_args; 691 struct shutdown_args /* { 692 int s; 693 int how; 694 } */ bsd_args; 695 int error; 696 697 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 698 return error; 699 bsd_args.s = linux_args.s; 700 bsd_args.how = linux_args.how; 701 return shutdown(p, &bsd_args); 702 } 703 704 struct linux_setsockopt_args { 705 int s; 706 int level; 707 int optname; 708 void *optval; 709 int optlen; 710 }; 711 712 static int 713 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) 714 { 715 struct linux_setsockopt_args linux_args; 716 struct setsockopt_args /* { 717 int s; 718 int level; 719 int name; 720 caddr_t val; 721 int valsize; 722 } */ bsd_args; 723 int error, name; 724 725 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 726 return error; 727 bsd_args.s = linux_args.s; 728 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 729 switch (bsd_args.level) { 730 case SOL_SOCKET: 731 name = linux_to_bsd_so_sockopt(linux_args.optname); 732 break; 733 case IPPROTO_IP: 734 name = linux_to_bsd_ip_sockopt(linux_args.optname); 735 break; 736 case IPPROTO_TCP: 737 /* Linux TCP option values match BSD's */ 738 name = linux_args.optname; 739 break; 740 default: 741 return EINVAL; 742 } 743 if (name == -1) 744 return EINVAL; 745 bsd_args.name = name; 746 bsd_args.val = linux_args.optval; 747 bsd_args.valsize = linux_args.optlen; 748 return setsockopt(p, &bsd_args); 749 } 750 751 struct linux_getsockopt_args { 752 int s; 753 int level; 754 int optname; 755 void *optval; 756 int *optlen; 757 }; 758 759 static int 760 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) 761 { 762 struct linux_getsockopt_args linux_args; 763 struct getsockopt_args /* { 764 int s; 765 int level; 766 int name; 767 caddr_t val; 768 int *avalsize; 769 } */ bsd_args; 770 int error, name; 771 772 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 773 return error; 774 bsd_args.s = linux_args.s; 775 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 776 switch (bsd_args.level) { 777 case SOL_SOCKET: 778 name = linux_to_bsd_so_sockopt(linux_args.optname); 779 break; 780 case IPPROTO_IP: 781 name = linux_to_bsd_ip_sockopt(linux_args.optname); 782 break; 783 case IPPROTO_TCP: 784 /* Linux TCP option values match BSD's */ 785 name = linux_args.optname; 786 break; 787 default: 788 return EINVAL; 789 } 790 if (name == -1) 791 return EINVAL; 792 bsd_args.name = name; 793 bsd_args.val = linux_args.optval; 794 bsd_args.avalsize = linux_args.optlen; 795 return getsockopt(p, &bsd_args); 796 } 797 798 int 799 linux_socketcall(struct proc *p, struct linux_socketcall_args *args) 800 { 801 switch (args->what) { 802 case LINUX_SOCKET: 803 return linux_socket(p, args->args); 804 case LINUX_BIND: 805 return linux_bind(p, args->args); 806 case LINUX_CONNECT: 807 return linux_connect(p, args->args); 808 case LINUX_LISTEN: 809 return linux_listen(p, args->args); 810 case LINUX_ACCEPT: 811 return linux_accept(p, args->args); 812 case LINUX_GETSOCKNAME: 813 return linux_getsockname(p, args->args); 814 case LINUX_GETPEERNAME: 815 return linux_getpeername(p, args->args); 816 case LINUX_SOCKETPAIR: 817 return linux_socketpair(p, args->args); 818 case LINUX_SEND: 819 return linux_send(p, args->args); 820 case LINUX_RECV: 821 return linux_recv(p, args->args); 822 case LINUX_SENDTO: 823 return linux_sendto(p, args->args); 824 case LINUX_RECVFROM: 825 return linux_recvfrom(p, args->args); 826 case LINUX_SHUTDOWN: 827 return linux_shutdown(p, args->args); 828 case LINUX_SETSOCKOPT: 829 return linux_setsockopt(p, args->args); 830 case LINUX_GETSOCKOPT: 831 return linux_getsockopt(p, args->args); 832 case LINUX_SENDMSG: 833 do { 834 int error; 835 int level; 836 caddr_t control; 837 struct { 838 int s; 839 const struct msghdr *msg; 840 int flags; 841 } *uap = args->args; 842 843 error = copyin(&uap->msg->msg_control, 844 &control, sizeof(caddr_t)); 845 if (error) 846 return error; 847 if (control == NULL) 848 goto done; 849 error = copyin(&((struct cmsghdr *)control)->cmsg_level, 850 &level, sizeof(int)); 851 if (error) 852 return error; 853 if (level == 1) { 854 /* 855 * Linux thinks that SOL_SOCKET is 1; we know that it's really 856 * 0xffff, of course. 857 */ 858 level = SOL_SOCKET; 859 error = copyout(&level, &((struct cmsghdr *)control)-> 860 cmsg_level, sizeof(int)); 861 if (error) 862 return error; 863 } 864 done: 865 return sendmsg(p, args->args); 866 } while (0); 867 case LINUX_RECVMSG: 868 return recvmsg(p, args->args); 869 870 default: 871 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 872 return ENOSYS; 873 } 874 } 875