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 int error; 445 446 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 447 return error; 448 bsd_args.s = linux_args.s; 449 bsd_args.name = (caddr_t)linux_args.addr; 450 bsd_args.anamelen = linux_args.namelen; 451 return oaccept(p, &bsd_args); 452 } 453 454 struct linux_getsockname_args { 455 int s; 456 struct sockaddr *addr; 457 int *namelen; 458 }; 459 460 static int 461 linux_getsockname(struct proc *p, struct linux_getsockname_args *args) 462 { 463 struct linux_getsockname_args linux_args; 464 struct getsockname_args /* { 465 int fdes; 466 caddr_t asa; 467 int *alen; 468 } */ bsd_args; 469 int error; 470 471 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 472 return error; 473 bsd_args.fdes = linux_args.s; 474 bsd_args.asa = (caddr_t) linux_args.addr; 475 bsd_args.alen = linux_args.namelen; 476 return ogetsockname(p, &bsd_args); 477 } 478 479 struct linux_getpeername_args { 480 int s; 481 struct sockaddr *addr; 482 int *namelen; 483 }; 484 485 static int 486 linux_getpeername(struct proc *p, struct linux_getpeername_args *args) 487 { 488 struct linux_getpeername_args linux_args; 489 struct ogetpeername_args /* { 490 int fdes; 491 caddr_t asa; 492 int *alen; 493 } */ bsd_args; 494 int error; 495 496 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 497 return error; 498 bsd_args.fdes = linux_args.s; 499 bsd_args.asa = (caddr_t) linux_args.addr; 500 bsd_args.alen = linux_args.namelen; 501 return ogetpeername(p, &bsd_args); 502 } 503 504 struct linux_socketpair_args { 505 int domain; 506 int type; 507 int protocol; 508 int *rsv; 509 }; 510 511 static int 512 linux_socketpair(struct proc *p, struct linux_socketpair_args *args) 513 { 514 struct linux_socketpair_args linux_args; 515 struct socketpair_args /* { 516 int domain; 517 int type; 518 int protocol; 519 int *rsv; 520 } */ bsd_args; 521 int error; 522 523 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 524 return error; 525 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 526 if (bsd_args.domain == -1) 527 return EINVAL; 528 bsd_args.type = linux_args.type; 529 bsd_args.protocol = linux_args.protocol; 530 bsd_args.rsv = linux_args.rsv; 531 return socketpair(p, &bsd_args); 532 } 533 534 struct linux_send_args { 535 int s; 536 void *msg; 537 int len; 538 int flags; 539 }; 540 541 static int 542 linux_send(struct proc *p, struct linux_send_args *args) 543 { 544 struct linux_send_args linux_args; 545 struct osend_args /* { 546 int s; 547 caddr_t buf; 548 int len; 549 int flags; 550 } */ bsd_args; 551 int error; 552 553 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 554 return error; 555 bsd_args.s = linux_args.s; 556 bsd_args.buf = linux_args.msg; 557 bsd_args.len = linux_args.len; 558 bsd_args.flags = linux_args.flags; 559 return osend(p, &bsd_args); 560 } 561 562 struct linux_recv_args { 563 int s; 564 void *msg; 565 int len; 566 int flags; 567 }; 568 569 static int 570 linux_recv(struct proc *p, struct linux_recv_args *args) 571 { 572 struct linux_recv_args linux_args; 573 struct orecv_args /* { 574 int s; 575 caddr_t buf; 576 int len; 577 int flags; 578 } */ bsd_args; 579 int error; 580 581 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 582 return error; 583 bsd_args.s = linux_args.s; 584 bsd_args.buf = linux_args.msg; 585 bsd_args.len = linux_args.len; 586 bsd_args.flags = linux_args.flags; 587 return orecv(p, &bsd_args); 588 } 589 590 struct linux_sendto_args { 591 int s; 592 void *msg; 593 int len; 594 int flags; 595 caddr_t to; 596 int tolen; 597 }; 598 599 static int 600 linux_sendto(struct proc *p, struct linux_sendto_args *args) 601 { 602 struct linux_sendto_args linux_args; 603 struct sendto_args /* { 604 int s; 605 caddr_t buf; 606 size_t len; 607 int flags; 608 caddr_t to; 609 int tolen; 610 } */ bsd_args; 611 int error; 612 613 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 614 return error; 615 bsd_args.s = linux_args.s; 616 bsd_args.buf = linux_args.msg; 617 bsd_args.len = linux_args.len; 618 bsd_args.flags = linux_args.flags; 619 bsd_args.to = linux_args.to; 620 bsd_args.tolen = linux_args.tolen; 621 622 if (linux_check_hdrincl(p, linux_args.s) == 0) 623 /* IP_HDRINCL set, tweak the packet before sending */ 624 return linux_sendto_hdrincl(p, &bsd_args); 625 626 return sendto(p, &bsd_args); 627 } 628 629 struct linux_recvfrom_args { 630 int s; 631 void *buf; 632 int len; 633 int flags; 634 caddr_t from; 635 int *fromlen; 636 }; 637 638 static int 639 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args) 640 { 641 struct linux_recvfrom_args linux_args; 642 struct recvfrom_args /* { 643 int s; 644 caddr_t buf; 645 size_t len; 646 int flags; 647 caddr_t from; 648 int *fromlenaddr; 649 } */ bsd_args; 650 int error; 651 652 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 653 return error; 654 bsd_args.s = linux_args.s; 655 bsd_args.buf = linux_args.buf; 656 bsd_args.len = linux_args.len; 657 bsd_args.flags = linux_args.flags; 658 bsd_args.from = linux_args.from; 659 bsd_args.fromlenaddr = linux_args.fromlen; 660 return orecvfrom(p, &bsd_args); 661 } 662 663 struct linux_shutdown_args { 664 int s; 665 int how; 666 }; 667 668 static int 669 linux_shutdown(struct proc *p, struct linux_shutdown_args *args) 670 { 671 struct linux_shutdown_args linux_args; 672 struct shutdown_args /* { 673 int s; 674 int how; 675 } */ bsd_args; 676 int error; 677 678 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 679 return error; 680 bsd_args.s = linux_args.s; 681 bsd_args.how = linux_args.how; 682 return shutdown(p, &bsd_args); 683 } 684 685 struct linux_setsockopt_args { 686 int s; 687 int level; 688 int optname; 689 void *optval; 690 int optlen; 691 }; 692 693 static int 694 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) 695 { 696 struct linux_setsockopt_args linux_args; 697 struct setsockopt_args /* { 698 int s; 699 int level; 700 int name; 701 caddr_t val; 702 int valsize; 703 } */ bsd_args; 704 int error, name; 705 706 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 707 return error; 708 bsd_args.s = linux_args.s; 709 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 710 switch (bsd_args.level) { 711 case SOL_SOCKET: 712 name = linux_to_bsd_so_sockopt(linux_args.optname); 713 break; 714 case IPPROTO_IP: 715 name = linux_to_bsd_ip_sockopt(linux_args.optname); 716 break; 717 case IPPROTO_TCP: 718 /* Linux TCP option values match BSD's */ 719 name = linux_args.optname; 720 break; 721 default: 722 return EINVAL; 723 } 724 if (name == -1) 725 return EINVAL; 726 bsd_args.name = name; 727 bsd_args.val = linux_args.optval; 728 bsd_args.valsize = linux_args.optlen; 729 return setsockopt(p, &bsd_args); 730 } 731 732 struct linux_getsockopt_args { 733 int s; 734 int level; 735 int optname; 736 void *optval; 737 int *optlen; 738 }; 739 740 static int 741 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) 742 { 743 struct linux_getsockopt_args linux_args; 744 struct getsockopt_args /* { 745 int s; 746 int level; 747 int name; 748 caddr_t val; 749 int *avalsize; 750 } */ bsd_args; 751 int error, name; 752 753 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 754 return error; 755 bsd_args.s = linux_args.s; 756 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 757 switch (bsd_args.level) { 758 case SOL_SOCKET: 759 name = linux_to_bsd_so_sockopt(linux_args.optname); 760 break; 761 case IPPROTO_IP: 762 name = linux_to_bsd_ip_sockopt(linux_args.optname); 763 break; 764 case IPPROTO_TCP: 765 /* Linux TCP option values match BSD's */ 766 name = linux_args.optname; 767 break; 768 default: 769 return EINVAL; 770 } 771 if (name == -1) 772 return EINVAL; 773 bsd_args.name = name; 774 bsd_args.val = linux_args.optval; 775 bsd_args.avalsize = linux_args.optlen; 776 return getsockopt(p, &bsd_args); 777 } 778 779 int 780 linux_socketcall(struct proc *p, struct linux_socketcall_args *args) 781 { 782 switch (args->what) { 783 case LINUX_SOCKET: 784 return linux_socket(p, args->args); 785 case LINUX_BIND: 786 return linux_bind(p, args->args); 787 case LINUX_CONNECT: 788 return linux_connect(p, args->args); 789 case LINUX_LISTEN: 790 return linux_listen(p, args->args); 791 case LINUX_ACCEPT: 792 return linux_accept(p, args->args); 793 case LINUX_GETSOCKNAME: 794 return linux_getsockname(p, args->args); 795 case LINUX_GETPEERNAME: 796 return linux_getpeername(p, args->args); 797 case LINUX_SOCKETPAIR: 798 return linux_socketpair(p, args->args); 799 case LINUX_SEND: 800 return linux_send(p, args->args); 801 case LINUX_RECV: 802 return linux_recv(p, args->args); 803 case LINUX_SENDTO: 804 return linux_sendto(p, args->args); 805 case LINUX_RECVFROM: 806 return linux_recvfrom(p, args->args); 807 case LINUX_SHUTDOWN: 808 return linux_shutdown(p, args->args); 809 case LINUX_SETSOCKOPT: 810 return linux_setsockopt(p, args->args); 811 case LINUX_GETSOCKOPT: 812 return linux_getsockopt(p, args->args); 813 case LINUX_SENDMSG: 814 do { 815 int error; 816 int level; 817 caddr_t control; 818 struct { 819 int s; 820 const struct msghdr *msg; 821 int flags; 822 } *uap = args->args; 823 824 error = copyin(&uap->msg->msg_control, 825 &control, sizeof(caddr_t)); 826 if (error) 827 return error; 828 if (control == NULL) 829 goto done; 830 error = copyin(&((struct cmsghdr *)control)->cmsg_level, 831 &level, sizeof(int)); 832 if (error) 833 return error; 834 if (level == 1) { 835 /* 836 * Linux thinks that SOL_SOCKET is 1; we know that it's really 837 * 0xffff, of course. 838 */ 839 level = SOL_SOCKET; 840 error = copyout(&level, &((struct cmsghdr *)control)-> 841 cmsg_level, sizeof(int)); 842 if (error) 843 return error; 844 } 845 done: 846 return sendmsg(p, args->args); 847 } while (0); 848 case LINUX_RECVMSG: 849 return recvmsg(p, args->args); 850 851 default: 852 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 853 return ENOSYS; 854 } 855 } 856