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/file.h> 44 #include <sys/socket.h> 45 #include <sys/socketvar.h> 46 #include <sys/uio.h> 47 48 #include <netinet/in.h> 49 #include <netinet/in_systm.h> 50 #include <netinet/ip.h> 51 52 #include <machine/../linux/linux.h> 53 #include <machine/../linux/linux_proto.h> 54 #include <compat/linux/linux_socket.h> 55 #include <compat/linux/linux_util.h> 56 57 /* 58 * FreeBSD's socket calls require the sockaddr struct length to agree 59 * with the address family. Linux does not, so we must force it. 60 */ 61 static int 62 linux_to_bsd_namelen(caddr_t name, int namelen) 63 { 64 uint16_t family; /* XXX must match Linux sockaddr */ 65 66 if (copyin(name, &family, sizeof(family))) 67 return namelen; 68 69 switch (family) { 70 case AF_INET: 71 return sizeof(struct sockaddr_in); 72 case AF_INET6: 73 return sizeof(struct sockaddr_in6); 74 } 75 return namelen; 76 } 77 78 #ifndef __alpha__ 79 static int 80 linux_to_bsd_domain(int domain) 81 { 82 83 switch (domain) { 84 case LINUX_AF_UNSPEC: 85 return (AF_UNSPEC); 86 case LINUX_AF_UNIX: 87 return (AF_LOCAL); 88 case LINUX_AF_INET: 89 return (AF_INET); 90 case LINUX_AF_AX25: 91 return (AF_CCITT); 92 case LINUX_AF_IPX: 93 return (AF_IPX); 94 case LINUX_AF_APPLETALK: 95 return (AF_APPLETALK); 96 } 97 return (-1); 98 } 99 100 static int 101 linux_to_bsd_sockopt_level(int level) 102 { 103 104 switch (level) { 105 case LINUX_SOL_SOCKET: 106 return (SOL_SOCKET); 107 } 108 return (level); 109 } 110 111 static int 112 linux_to_bsd_ip_sockopt(int opt) 113 { 114 115 switch (opt) { 116 case LINUX_IP_TOS: 117 return (IP_TOS); 118 case LINUX_IP_TTL: 119 return (IP_TTL); 120 case LINUX_IP_OPTIONS: 121 return (IP_OPTIONS); 122 case LINUX_IP_MULTICAST_IF: 123 return (IP_MULTICAST_IF); 124 case LINUX_IP_MULTICAST_TTL: 125 return (IP_MULTICAST_TTL); 126 case LINUX_IP_MULTICAST_LOOP: 127 return (IP_MULTICAST_LOOP); 128 case LINUX_IP_ADD_MEMBERSHIP: 129 return (IP_ADD_MEMBERSHIP); 130 case LINUX_IP_DROP_MEMBERSHIP: 131 return (IP_DROP_MEMBERSHIP); 132 case LINUX_IP_HDRINCL: 133 return (IP_HDRINCL); 134 } 135 return (-1); 136 } 137 138 static int 139 linux_to_bsd_so_sockopt(int opt) 140 { 141 142 switch (opt) { 143 case LINUX_SO_DEBUG: 144 return (SO_DEBUG); 145 case LINUX_SO_REUSEADDR: 146 return (SO_REUSEADDR); 147 case LINUX_SO_TYPE: 148 return (SO_TYPE); 149 case LINUX_SO_ERROR: 150 return (SO_ERROR); 151 case LINUX_SO_DONTROUTE: 152 return (SO_DONTROUTE); 153 case LINUX_SO_BROADCAST: 154 return (SO_BROADCAST); 155 case LINUX_SO_SNDBUF: 156 return (SO_SNDBUF); 157 case LINUX_SO_RCVBUF: 158 return (SO_RCVBUF); 159 case LINUX_SO_KEEPALIVE: 160 return (SO_KEEPALIVE); 161 case LINUX_SO_OOBINLINE: 162 return (SO_OOBINLINE); 163 case LINUX_SO_LINGER: 164 return (SO_LINGER); 165 } 166 return (-1); 167 } 168 169 static int 170 linux_to_bsd_msg_flags(int flags) 171 { 172 int ret_flags = 0; 173 174 if (flags & LINUX_MSG_OOB) 175 ret_flags |= MSG_OOB; 176 if (flags & LINUX_MSG_PEEK) 177 ret_flags |= MSG_PEEK; 178 if (flags & LINUX_MSG_DONTROUTE) 179 ret_flags |= MSG_DONTROUTE; 180 if (flags & LINUX_MSG_CTRUNC) 181 ret_flags |= MSG_CTRUNC; 182 if (flags & LINUX_MSG_TRUNC) 183 ret_flags |= MSG_TRUNC; 184 if (flags & LINUX_MSG_DONTWAIT) 185 ret_flags |= MSG_DONTWAIT; 186 if (flags & LINUX_MSG_EOR) 187 ret_flags |= MSG_EOR; 188 if (flags & LINUX_MSG_WAITALL) 189 ret_flags |= MSG_WAITALL; 190 #if 0 /* not handled */ 191 if (flags & LINUX_MSG_PROXY) 192 ; 193 if (flags & LINUX_MSG_FIN) 194 ; 195 if (flags & LINUX_MSG_SYN) 196 ; 197 if (flags & LINUX_MSG_CONFIRM) 198 ; 199 if (flags & LINUX_MSG_RST) 200 ; 201 if (flags & LINUX_MSG_ERRQUEUE) 202 ; 203 if (flags & LINUX_MSG_NOSIGNAL) 204 ; 205 #endif 206 return ret_flags; 207 } 208 209 /* Return 0 if IP_HDRINCL is set for the given socket. */ 210 static int 211 linux_check_hdrincl(struct thread *td, int s) 212 { 213 struct getsockopt_args /* { 214 int s; 215 int level; 216 int name; 217 caddr_t val; 218 int *avalsize; 219 } */ bsd_args; 220 int error; 221 caddr_t sg, val, valsize; 222 int size_val = sizeof val; 223 int optval; 224 225 sg = stackgap_init(); 226 val = stackgap_alloc(&sg, sizeof(int)); 227 valsize = stackgap_alloc(&sg, sizeof(int)); 228 229 if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 230 return (error); 231 232 bsd_args.s = s; 233 bsd_args.level = IPPROTO_IP; 234 bsd_args.name = IP_HDRINCL; 235 bsd_args.val = val; 236 bsd_args.avalsize = (int *)valsize; 237 if ((error = getsockopt(td, &bsd_args))) 238 return (error); 239 240 if ((error = copyin(val, &optval, sizeof(optval)))) 241 return (error); 242 243 return (optval == 0); 244 } 245 246 /* 247 * Updated sendto() when IP_HDRINCL is set: 248 * tweak endian-dependent fields in the IP packet. 249 */ 250 static int 251 linux_sendto_hdrincl(struct thread *td, struct sendto_args *bsd_args) 252 { 253 /* 254 * linux_ip_copysize defines how many bytes we should copy 255 * from the beginning of the IP packet before we customize it for BSD. 256 * It should include all the fields we modify (ip_len and ip_off) 257 * and be as small as possible to minimize copying overhead. 258 */ 259 #define linux_ip_copysize 8 260 261 caddr_t sg; 262 struct ip *packet; 263 struct msghdr *msg; 264 struct iovec *iov; 265 266 int error; 267 struct sendmsg_args /* { 268 int s; 269 caddr_t msg; 270 int flags; 271 } */ sendmsg_args; 272 273 /* Check the packet isn't too small before we mess with it */ 274 if (bsd_args->len < linux_ip_copysize) 275 return (EINVAL); 276 277 /* 278 * Tweaking the user buffer in place would be bad manners. 279 * We create a corrected IP header with just the needed length, 280 * then use an iovec to glue it to the rest of the user packet 281 * when calling sendmsg(). 282 */ 283 sg = stackgap_init(); 284 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 285 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 286 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 287 288 /* Make a copy of the beginning of the packet to be sent */ 289 if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize))) 290 return (error); 291 292 /* Convert fields from Linux to BSD raw IP socket format */ 293 packet->ip_len = bsd_args->len; 294 packet->ip_off = ntohs(packet->ip_off); 295 296 /* Prepare the msghdr and iovec structures describing the new packet */ 297 msg->msg_name = bsd_args->to; 298 msg->msg_namelen = bsd_args->tolen; 299 msg->msg_iov = iov; 300 msg->msg_iovlen = 2; 301 msg->msg_control = NULL; 302 msg->msg_controllen = 0; 303 msg->msg_flags = 0; 304 iov[0].iov_base = (char *)packet; 305 iov[0].iov_len = linux_ip_copysize; 306 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 307 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 308 309 sendmsg_args.s = bsd_args->s; 310 sendmsg_args.msg = (caddr_t)msg; 311 sendmsg_args.flags = bsd_args->flags; 312 return (sendmsg(td, &sendmsg_args)); 313 } 314 315 struct linux_socket_args { 316 int domain; 317 int type; 318 int protocol; 319 }; 320 321 static int 322 linux_socket(struct thread *td, struct linux_socket_args *args) 323 { 324 struct linux_socket_args linux_args; 325 struct socket_args /* { 326 int domain; 327 int type; 328 int protocol; 329 } */ bsd_args; 330 int error; 331 int retval_socket; 332 333 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 334 return (error); 335 336 bsd_args.protocol = linux_args.protocol; 337 bsd_args.type = linux_args.type; 338 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 339 if (bsd_args.domain == -1) 340 return (EINVAL); 341 342 retval_socket = socket(td, &bsd_args); 343 if (bsd_args.type == SOCK_RAW 344 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 345 && bsd_args.domain == AF_INET 346 && retval_socket >= 0) { 347 /* It's a raw IP socket: set the IP_HDRINCL option. */ 348 struct setsockopt_args /* { 349 int s; 350 int level; 351 int name; 352 caddr_t val; 353 int valsize; 354 } */ bsd_setsockopt_args; 355 caddr_t sg; 356 int *hdrincl; 357 358 sg = stackgap_init(); 359 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 360 *hdrincl = 1; 361 bsd_setsockopt_args.s = td->td_retval[0]; 362 bsd_setsockopt_args.level = IPPROTO_IP; 363 bsd_setsockopt_args.name = IP_HDRINCL; 364 bsd_setsockopt_args.val = (caddr_t)hdrincl; 365 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 366 /* We ignore any error returned by setsockopt() */ 367 setsockopt(td, &bsd_setsockopt_args); 368 /* Copy back the return value from socket() */ 369 td->td_retval[0] = bsd_setsockopt_args.s; 370 } 371 372 return (retval_socket); 373 } 374 375 struct linux_bind_args { 376 int s; 377 struct sockaddr *name; 378 int namelen; 379 }; 380 381 static int 382 linux_bind(struct thread *td, struct linux_bind_args *args) 383 { 384 struct linux_bind_args linux_args; 385 struct bind_args /* { 386 int s; 387 caddr_t name; 388 int namelen; 389 } */ bsd_args; 390 int error; 391 392 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 393 return (error); 394 395 bsd_args.s = linux_args.s; 396 bsd_args.name = (caddr_t)linux_args.name; 397 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 398 return (bind(td, &bsd_args)); 399 } 400 401 struct linux_connect_args { 402 int s; 403 struct sockaddr * name; 404 int namelen; 405 }; 406 int linux_connect(struct thread *, struct linux_connect_args *); 407 #endif /* !__alpha__*/ 408 409 int 410 linux_connect(struct thread *td, struct linux_connect_args *args) 411 { 412 struct linux_connect_args linux_args; 413 struct connect_args /* { 414 int s; 415 caddr_t name; 416 int namelen; 417 } */ bsd_args; 418 struct socket *so; 419 struct file *fp; 420 int error; 421 422 #ifdef __alpha__ 423 bcopy(args, &linux_args, sizeof(linux_args)); 424 #else 425 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 426 return (error); 427 #endif /* __alpha__ */ 428 429 bsd_args.s = linux_args.s; 430 bsd_args.name = (caddr_t)linux_args.name; 431 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 432 error = connect(td, &bsd_args); 433 if (error != EISCONN) 434 return (error); 435 436 /* 437 * Linux doesn't return EISCONN the first time it occurs, 438 * when on a non-blocking socket. Instead it returns the 439 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 440 */ 441 error = holdsock(td->td_proc->p_fd, linux_args.s, &fp); 442 if (error) 443 return (error); 444 error = EISCONN; 445 if (fp->f_flag & FNONBLOCK) { 446 so = (struct socket *)fp->f_data; 447 if (so->so_emuldata == 0) 448 error = so->so_error; 449 so->so_emuldata = (void *)1; 450 } 451 fdrop(fp, td); 452 return (error); 453 } 454 455 #ifndef __alpha__ 456 457 struct linux_listen_args { 458 int s; 459 int backlog; 460 }; 461 462 static int 463 linux_listen(struct thread *td, struct linux_listen_args *args) 464 { 465 struct linux_listen_args linux_args; 466 struct listen_args /* { 467 int s; 468 int backlog; 469 } */ bsd_args; 470 int error; 471 472 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 473 return (error); 474 475 bsd_args.s = linux_args.s; 476 bsd_args.backlog = linux_args.backlog; 477 return (listen(td, &bsd_args)); 478 } 479 480 struct linux_accept_args { 481 int s; 482 struct sockaddr *addr; 483 int *namelen; 484 }; 485 486 static int 487 linux_accept(struct thread *td, struct linux_accept_args *args) 488 { 489 struct linux_accept_args linux_args; 490 struct accept_args /* { 491 int s; 492 caddr_t name; 493 int *anamelen; 494 } */ bsd_args; 495 struct fcntl_args /* { 496 int fd; 497 int cmd; 498 long arg; 499 } */ f_args; 500 int error; 501 502 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 503 return (error); 504 505 bsd_args.s = linux_args.s; 506 bsd_args.name = (caddr_t)linux_args.addr; 507 bsd_args.anamelen = linux_args.namelen; 508 error = oaccept(td, &bsd_args); 509 if (error) 510 return (error); 511 512 /* 513 * linux appears not to copy flags from the parent socket to the 514 * accepted one, so we must clear the flags in the new descriptor. 515 * Ignore any errors, because we already have an open fd. 516 */ 517 f_args.fd = td->td_retval[0]; 518 f_args.cmd = F_SETFL; 519 f_args.arg = 0; 520 (void)fcntl(td, &f_args); 521 td->td_retval[0] = f_args.fd; 522 return (0); 523 } 524 525 struct linux_getsockname_args { 526 int s; 527 struct sockaddr *addr; 528 int *namelen; 529 }; 530 531 static int 532 linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 533 { 534 struct linux_getsockname_args linux_args; 535 struct getsockname_args /* { 536 int fdes; 537 caddr_t asa; 538 int *alen; 539 } */ bsd_args; 540 int error; 541 542 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 543 return (error); 544 545 bsd_args.fdes = linux_args.s; 546 bsd_args.asa = (caddr_t) linux_args.addr; 547 bsd_args.alen = linux_args.namelen; 548 return (ogetsockname(td, &bsd_args)); 549 } 550 551 struct linux_getpeername_args { 552 int s; 553 struct sockaddr *addr; 554 int *namelen; 555 }; 556 557 static int 558 linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 559 { 560 struct linux_getpeername_args linux_args; 561 struct ogetpeername_args /* { 562 int fdes; 563 caddr_t asa; 564 int *alen; 565 } */ bsd_args; 566 int error; 567 568 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 569 return (error); 570 571 bsd_args.fdes = linux_args.s; 572 bsd_args.asa = (caddr_t) linux_args.addr; 573 bsd_args.alen = linux_args.namelen; 574 return (ogetpeername(td, &bsd_args)); 575 } 576 577 struct linux_socketpair_args { 578 int domain; 579 int type; 580 int protocol; 581 int *rsv; 582 }; 583 584 static int 585 linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 586 { 587 struct linux_socketpair_args linux_args; 588 struct socketpair_args /* { 589 int domain; 590 int type; 591 int protocol; 592 int *rsv; 593 } */ bsd_args; 594 int error; 595 596 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 597 return (error); 598 599 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 600 if (bsd_args.domain == -1) 601 return (EINVAL); 602 603 bsd_args.type = linux_args.type; 604 bsd_args.protocol = linux_args.protocol; 605 bsd_args.rsv = linux_args.rsv; 606 return (socketpair(td, &bsd_args)); 607 } 608 609 struct linux_send_args { 610 int s; 611 void *msg; 612 int len; 613 int flags; 614 }; 615 616 static int 617 linux_send(struct thread *td, struct linux_send_args *args) 618 { 619 struct linux_send_args linux_args; 620 struct osend_args /* { 621 int s; 622 caddr_t buf; 623 int len; 624 int flags; 625 } */ bsd_args; 626 int error; 627 628 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 629 return (error); 630 631 bsd_args.s = linux_args.s; 632 bsd_args.buf = linux_args.msg; 633 bsd_args.len = linux_args.len; 634 bsd_args.flags = linux_args.flags; 635 return (osend(td, &bsd_args)); 636 } 637 638 struct linux_recv_args { 639 int s; 640 void *msg; 641 int len; 642 int flags; 643 }; 644 645 static int 646 linux_recv(struct thread *td, struct linux_recv_args *args) 647 { 648 struct linux_recv_args linux_args; 649 struct orecv_args /* { 650 int s; 651 caddr_t buf; 652 int len; 653 int flags; 654 } */ bsd_args; 655 int error; 656 657 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 658 return (error); 659 660 bsd_args.s = linux_args.s; 661 bsd_args.buf = linux_args.msg; 662 bsd_args.len = linux_args.len; 663 bsd_args.flags = linux_args.flags; 664 return (orecv(td, &bsd_args)); 665 } 666 667 struct linux_sendto_args { 668 int s; 669 void *msg; 670 int len; 671 int flags; 672 caddr_t to; 673 int tolen; 674 }; 675 676 static int 677 linux_sendto(struct thread *td, struct linux_sendto_args *args) 678 { 679 struct linux_sendto_args linux_args; 680 struct sendto_args /* { 681 int s; 682 caddr_t buf; 683 size_t len; 684 int flags; 685 caddr_t to; 686 int tolen; 687 } */ bsd_args; 688 int error; 689 690 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 691 return (error); 692 693 bsd_args.s = linux_args.s; 694 bsd_args.buf = linux_args.msg; 695 bsd_args.len = linux_args.len; 696 bsd_args.flags = linux_args.flags; 697 bsd_args.to = linux_args.to; 698 bsd_args.tolen = linux_args.tolen; 699 700 if (linux_check_hdrincl(td, linux_args.s) == 0) 701 /* IP_HDRINCL set, tweak the packet before sending */ 702 return (linux_sendto_hdrincl(td, &bsd_args)); 703 704 return (sendto(td, &bsd_args)); 705 } 706 707 struct linux_recvfrom_args { 708 int s; 709 void *buf; 710 int len; 711 int flags; 712 caddr_t from; 713 int *fromlen; 714 }; 715 716 static int 717 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 718 { 719 struct linux_recvfrom_args linux_args; 720 struct recvfrom_args /* { 721 int s; 722 caddr_t buf; 723 size_t len; 724 int flags; 725 caddr_t from; 726 int *fromlenaddr; 727 } */ bsd_args; 728 int error; 729 730 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 731 return (error); 732 733 bsd_args.s = linux_args.s; 734 bsd_args.buf = linux_args.buf; 735 bsd_args.len = linux_args.len; 736 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 737 bsd_args.from = linux_args.from; 738 bsd_args.fromlenaddr = linux_args.fromlen; 739 return (orecvfrom(td, &bsd_args)); 740 } 741 742 struct linux_recvmsg_args { 743 int s; 744 struct msghdr *msg; 745 int flags; 746 }; 747 748 static int 749 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 750 { 751 struct linux_recvmsg_args linux_args; 752 struct recvmsg_args /* { 753 int s; 754 struct msghdr *msg; 755 int flags; 756 } */ bsd_args; 757 int error; 758 759 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 760 return (error); 761 762 bsd_args.s = linux_args.s; 763 bsd_args.msg = linux_args.msg; 764 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 765 return (recvmsg(td, &bsd_args)); 766 } 767 768 struct linux_shutdown_args { 769 int s; 770 int how; 771 }; 772 773 static int 774 linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 775 { 776 struct linux_shutdown_args linux_args; 777 struct shutdown_args /* { 778 int s; 779 int how; 780 } */ bsd_args; 781 int error; 782 783 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 784 return (error); 785 786 bsd_args.s = linux_args.s; 787 bsd_args.how = linux_args.how; 788 return (shutdown(td, &bsd_args)); 789 } 790 791 struct linux_setsockopt_args { 792 int s; 793 int level; 794 int optname; 795 void *optval; 796 int optlen; 797 }; 798 799 static int 800 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 801 { 802 struct linux_setsockopt_args linux_args; 803 struct setsockopt_args /* { 804 int s; 805 int level; 806 int name; 807 caddr_t val; 808 int valsize; 809 } */ bsd_args; 810 int error, name; 811 812 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 813 return (error); 814 815 bsd_args.s = linux_args.s; 816 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 817 switch (bsd_args.level) { 818 case SOL_SOCKET: 819 name = linux_to_bsd_so_sockopt(linux_args.optname); 820 break; 821 case IPPROTO_IP: 822 name = linux_to_bsd_ip_sockopt(linux_args.optname); 823 break; 824 case IPPROTO_TCP: 825 /* Linux TCP option values match BSD's */ 826 name = linux_args.optname; 827 break; 828 default: 829 name = -1; 830 break; 831 } 832 if (name == -1) 833 return (EINVAL); 834 835 bsd_args.name = name; 836 bsd_args.val = linux_args.optval; 837 bsd_args.valsize = linux_args.optlen; 838 return (setsockopt(td, &bsd_args)); 839 } 840 841 struct linux_getsockopt_args { 842 int s; 843 int level; 844 int optname; 845 void *optval; 846 int *optlen; 847 }; 848 849 static int 850 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 851 { 852 struct linux_getsockopt_args linux_args; 853 struct getsockopt_args /* { 854 int s; 855 int level; 856 int name; 857 caddr_t val; 858 int *avalsize; 859 } */ bsd_args; 860 int error, name; 861 862 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 863 return (error); 864 865 bsd_args.s = linux_args.s; 866 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 867 switch (bsd_args.level) { 868 case SOL_SOCKET: 869 name = linux_to_bsd_so_sockopt(linux_args.optname); 870 break; 871 case IPPROTO_IP: 872 name = linux_to_bsd_ip_sockopt(linux_args.optname); 873 break; 874 case IPPROTO_TCP: 875 /* Linux TCP option values match BSD's */ 876 name = linux_args.optname; 877 break; 878 default: 879 name = -1; 880 break; 881 } 882 if (name == -1) 883 return (EINVAL); 884 885 bsd_args.name = name; 886 bsd_args.val = linux_args.optval; 887 bsd_args.avalsize = linux_args.optlen; 888 return (getsockopt(td, &bsd_args)); 889 } 890 891 int 892 linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 893 { 894 void *arg = (void *)args->args; 895 896 switch (args->what) { 897 case LINUX_SOCKET: 898 return (linux_socket(td, arg)); 899 case LINUX_BIND: 900 return (linux_bind(td, arg)); 901 case LINUX_CONNECT: 902 return (linux_connect(td, arg)); 903 case LINUX_LISTEN: 904 return (linux_listen(td, arg)); 905 case LINUX_ACCEPT: 906 return (linux_accept(td, arg)); 907 case LINUX_GETSOCKNAME: 908 return (linux_getsockname(td, arg)); 909 case LINUX_GETPEERNAME: 910 return (linux_getpeername(td, arg)); 911 case LINUX_SOCKETPAIR: 912 return (linux_socketpair(td, arg)); 913 case LINUX_SEND: 914 return (linux_send(td, arg)); 915 case LINUX_RECV: 916 return (linux_recv(td, arg)); 917 case LINUX_SENDTO: 918 return (linux_sendto(td, arg)); 919 case LINUX_RECVFROM: 920 return (linux_recvfrom(td, arg)); 921 case LINUX_SHUTDOWN: 922 return (linux_shutdown(td, arg)); 923 case LINUX_SETSOCKOPT: 924 return (linux_setsockopt(td, arg)); 925 case LINUX_GETSOCKOPT: 926 return (linux_getsockopt(td, arg)); 927 case LINUX_SENDMSG: 928 do { 929 int error; 930 int level; 931 caddr_t control; 932 struct { 933 int s; 934 const struct msghdr *msg; 935 int flags; 936 } *uap = arg; 937 938 error = copyin(&uap->msg->msg_control, &control, 939 sizeof(caddr_t)); 940 if (error) 941 return (error); 942 943 if (control == NULL) 944 goto done; 945 946 error = copyin(&((struct cmsghdr*)control)->cmsg_level, 947 &level, sizeof(int)); 948 if (error) 949 return (error); 950 951 if (level == 1) { 952 /* 953 * Linux thinks that SOL_SOCKET is 1; we know 954 * that it's really 0xffff, of course. 955 */ 956 level = SOL_SOCKET; 957 error = copyout(&level, 958 &((struct cmsghdr *)control)->cmsg_level, 959 sizeof(int)); 960 if (error) 961 return (error); 962 } 963 done: 964 return (sendmsg(td, arg)); 965 } while (0); 966 case LINUX_RECVMSG: 967 return (linux_recvmsg(td, arg)); 968 } 969 970 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 971 return (ENOSYS); 972 } 973 #endif /*!__alpha__*/ 974