linux_socket.c revision 103839
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 without 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: head/sys/compat/linux/linux_socket.c 103839 2002-09-23 06:17:54Z mini $ 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 */ 61static int 62linux_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__ 79static int 80linux_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 100static int 101linux_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 111static int 112linux_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 138static int 139linux_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 169static int 170linux_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. */ 210static int 211linux_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 */ 250static int 251linux_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 315struct linux_socket_args { 316 int domain; 317 int type; 318 int protocol; 319}; 320 321static int 322linux_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 375struct linux_bind_args { 376 int s; 377 struct sockaddr *name; 378 int namelen; 379}; 380 381static int 382linux_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 401struct linux_connect_args { 402 int s; 403 struct sockaddr * name; 404 int namelen; 405}; 406int linux_connect(struct thread *, struct linux_connect_args *); 407#endif /* !__alpha__*/ 408 409int 410linux_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 u_int fflag; 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 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 442 return(error); 443 error = EISCONN; 444 if (fflag & FNONBLOCK) { 445 if (so->so_emuldata == 0) 446 error = so->so_error; 447 so->so_emuldata = (void *)1; 448 } 449 fputsock(so); 450 return (error); 451} 452 453#ifndef __alpha__ 454 455struct linux_listen_args { 456 int s; 457 int backlog; 458}; 459 460static int 461linux_listen(struct thread *td, struct linux_listen_args *args) 462{ 463 struct linux_listen_args linux_args; 464 struct listen_args /* { 465 int s; 466 int backlog; 467 } */ bsd_args; 468 int error; 469 470 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 471 return (error); 472 473 bsd_args.s = linux_args.s; 474 bsd_args.backlog = linux_args.backlog; 475 return (listen(td, &bsd_args)); 476} 477 478struct linux_accept_args { 479 int s; 480 struct sockaddr *addr; 481 int *namelen; 482}; 483 484static int 485linux_accept(struct thread *td, struct linux_accept_args *args) 486{ 487 struct linux_accept_args linux_args; 488 struct accept_args /* { 489 int s; 490 caddr_t name; 491 int *anamelen; 492 } */ bsd_args; 493 struct fcntl_args /* { 494 int fd; 495 int cmd; 496 long arg; 497 } */ f_args; 498 int error; 499 500 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 501 return (error); 502 503 bsd_args.s = linux_args.s; 504 bsd_args.name = (caddr_t)linux_args.addr; 505 bsd_args.anamelen = linux_args.namelen; 506 error = accept(td, &bsd_args); 507 if (error) 508 return (error); 509 510 /* 511 * linux appears not to copy flags from the parent socket to the 512 * accepted one, so we must clear the flags in the new descriptor. 513 * Ignore any errors, because we already have an open fd. 514 */ 515 f_args.fd = td->td_retval[0]; 516 f_args.cmd = F_SETFL; 517 f_args.arg = 0; 518 (void)fcntl(td, &f_args); 519 td->td_retval[0] = f_args.fd; 520 return (0); 521} 522 523struct linux_getsockname_args { 524 int s; 525 struct sockaddr *addr; 526 int *namelen; 527}; 528 529static int 530linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 531{ 532 struct linux_getsockname_args linux_args; 533 struct getsockname_args /* { 534 int fdes; 535 caddr_t asa; 536 int *alen; 537 } */ bsd_args; 538 int error; 539 540 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 541 return (error); 542 543 bsd_args.fdes = linux_args.s; 544 bsd_args.asa = (caddr_t) linux_args.addr; 545 bsd_args.alen = linux_args.namelen; 546 return (getsockname(td, &bsd_args)); 547} 548 549struct linux_getpeername_args { 550 int s; 551 struct sockaddr *addr; 552 int *namelen; 553}; 554 555static int 556linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 557{ 558 struct linux_getpeername_args linux_args; 559 struct getpeername_args /* { 560 int fdes; 561 caddr_t asa; 562 int *alen; 563 } */ bsd_args; 564 int error; 565 566 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 567 return (error); 568 569 bsd_args.fdes = linux_args.s; 570 bsd_args.asa = (caddr_t) linux_args.addr; 571 bsd_args.alen = linux_args.namelen; 572 return (getpeername(td, &bsd_args)); 573} 574 575struct linux_socketpair_args { 576 int domain; 577 int type; 578 int protocol; 579 int *rsv; 580}; 581 582static int 583linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 584{ 585 struct linux_socketpair_args linux_args; 586 struct socketpair_args /* { 587 int domain; 588 int type; 589 int protocol; 590 int *rsv; 591 } */ bsd_args; 592 int error; 593 594 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 595 return (error); 596 597 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 598 if (bsd_args.domain == -1) 599 return (EINVAL); 600 601 bsd_args.type = linux_args.type; 602 bsd_args.protocol = linux_args.protocol; 603 bsd_args.rsv = linux_args.rsv; 604 return (socketpair(td, &bsd_args)); 605} 606 607struct linux_send_args { 608 int s; 609 void *msg; 610 int len; 611 int flags; 612}; 613 614static int 615linux_send(struct thread *td, struct linux_send_args *args) 616{ 617 struct linux_send_args linux_args; 618 struct sendto_args /* { 619 int s; 620 caddr_t buf; 621 size_t len; 622 int flags; 623 caddr_t to; 624 int tolen; 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 bsd_args.to = NULL; 636 bsd_args.tolen = 0; 637 return (sendto(td, &bsd_args)); 638} 639 640struct linux_recv_args { 641 int s; 642 void *msg; 643 int len; 644 int flags; 645}; 646 647static int 648linux_recv(struct thread *td, struct linux_recv_args *args) 649{ 650 struct linux_recv_args linux_args; 651 struct recvfrom_args /* { 652 int s; 653 caddr_t buf; 654 int len; 655 int flags; 656 caddr_t from; 657 int fromlen; 658 } */ bsd_args; 659 int error; 660 661 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 662 return (error); 663 664 bsd_args.s = linux_args.s; 665 bsd_args.buf = linux_args.msg; 666 bsd_args.len = linux_args.len; 667 bsd_args.flags = linux_args.flags; 668 bsd_args.from = NULL; 669 bsd_args.fromlenaddr = NULL; 670 return (recvfrom(td, &bsd_args)); 671} 672 673struct linux_sendto_args { 674 int s; 675 void *msg; 676 int len; 677 int flags; 678 caddr_t to; 679 int tolen; 680}; 681 682static int 683linux_sendto(struct thread *td, struct linux_sendto_args *args) 684{ 685 struct linux_sendto_args linux_args; 686 struct sendto_args /* { 687 int s; 688 caddr_t buf; 689 size_t len; 690 int flags; 691 caddr_t to; 692 int tolen; 693 } */ bsd_args; 694 int error; 695 696 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 697 return (error); 698 699 bsd_args.s = linux_args.s; 700 bsd_args.buf = linux_args.msg; 701 bsd_args.len = linux_args.len; 702 bsd_args.flags = linux_args.flags; 703 bsd_args.to = linux_args.to; 704 bsd_args.tolen = linux_args.tolen; 705 706 if (linux_check_hdrincl(td, linux_args.s) == 0) 707 /* IP_HDRINCL set, tweak the packet before sending */ 708 return (linux_sendto_hdrincl(td, &bsd_args)); 709 710 return (sendto(td, &bsd_args)); 711} 712 713struct linux_recvfrom_args { 714 int s; 715 void *buf; 716 int len; 717 int flags; 718 caddr_t from; 719 int *fromlen; 720}; 721 722static int 723linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 724{ 725 struct linux_recvfrom_args linux_args; 726 struct recvfrom_args /* { 727 int s; 728 caddr_t buf; 729 size_t len; 730 int flags; 731 caddr_t from; 732 int *fromlenaddr; 733 } */ bsd_args; 734 int error; 735 736 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 737 return (error); 738 739 bsd_args.s = linux_args.s; 740 bsd_args.buf = linux_args.buf; 741 bsd_args.len = linux_args.len; 742 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 743 bsd_args.from = linux_args.from; 744 bsd_args.fromlenaddr = linux_args.fromlen; 745 return (recvfrom(td, &bsd_args)); 746} 747 748struct linux_recvmsg_args { 749 int s; 750 struct msghdr *msg; 751 int flags; 752}; 753 754static int 755linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 756{ 757 struct linux_recvmsg_args linux_args; 758 struct recvmsg_args /* { 759 int s; 760 struct msghdr *msg; 761 int flags; 762 } */ bsd_args; 763 int error; 764 765 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 766 return (error); 767 768 bsd_args.s = linux_args.s; 769 bsd_args.msg = linux_args.msg; 770 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 771 return (recvmsg(td, &bsd_args)); 772} 773 774struct linux_shutdown_args { 775 int s; 776 int how; 777}; 778 779static int 780linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 781{ 782 struct linux_shutdown_args linux_args; 783 struct shutdown_args /* { 784 int s; 785 int how; 786 } */ bsd_args; 787 int error; 788 789 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 790 return (error); 791 792 bsd_args.s = linux_args.s; 793 bsd_args.how = linux_args.how; 794 return (shutdown(td, &bsd_args)); 795} 796 797struct linux_setsockopt_args { 798 int s; 799 int level; 800 int optname; 801 void *optval; 802 int optlen; 803}; 804 805static int 806linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 807{ 808 struct linux_setsockopt_args linux_args; 809 struct setsockopt_args /* { 810 int s; 811 int level; 812 int name; 813 caddr_t val; 814 int valsize; 815 } */ bsd_args; 816 int error, name; 817 818 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 819 return (error); 820 821 bsd_args.s = linux_args.s; 822 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 823 switch (bsd_args.level) { 824 case SOL_SOCKET: 825 name = linux_to_bsd_so_sockopt(linux_args.optname); 826 break; 827 case IPPROTO_IP: 828 name = linux_to_bsd_ip_sockopt(linux_args.optname); 829 break; 830 case IPPROTO_TCP: 831 /* Linux TCP option values match BSD's */ 832 name = linux_args.optname; 833 break; 834 default: 835 name = -1; 836 break; 837 } 838 if (name == -1) 839 return (EINVAL); 840 841 bsd_args.name = name; 842 bsd_args.val = linux_args.optval; 843 bsd_args.valsize = linux_args.optlen; 844 return (setsockopt(td, &bsd_args)); 845} 846 847struct linux_getsockopt_args { 848 int s; 849 int level; 850 int optname; 851 void *optval; 852 int *optlen; 853}; 854 855static int 856linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 857{ 858 struct linux_getsockopt_args linux_args; 859 struct getsockopt_args /* { 860 int s; 861 int level; 862 int name; 863 caddr_t val; 864 int *avalsize; 865 } */ bsd_args; 866 int error, name; 867 868 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 869 return (error); 870 871 bsd_args.s = linux_args.s; 872 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 873 switch (bsd_args.level) { 874 case SOL_SOCKET: 875 name = linux_to_bsd_so_sockopt(linux_args.optname); 876 break; 877 case IPPROTO_IP: 878 name = linux_to_bsd_ip_sockopt(linux_args.optname); 879 break; 880 case IPPROTO_TCP: 881 /* Linux TCP option values match BSD's */ 882 name = linux_args.optname; 883 break; 884 default: 885 name = -1; 886 break; 887 } 888 if (name == -1) 889 return (EINVAL); 890 891 bsd_args.name = name; 892 bsd_args.val = linux_args.optval; 893 bsd_args.avalsize = linux_args.optlen; 894 return (getsockopt(td, &bsd_args)); 895} 896 897int 898linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 899{ 900 void *arg = (void *)args->args; 901 902 switch (args->what) { 903 case LINUX_SOCKET: 904 return (linux_socket(td, arg)); 905 case LINUX_BIND: 906 return (linux_bind(td, arg)); 907 case LINUX_CONNECT: 908 return (linux_connect(td, arg)); 909 case LINUX_LISTEN: 910 return (linux_listen(td, arg)); 911 case LINUX_ACCEPT: 912 return (linux_accept(td, arg)); 913 case LINUX_GETSOCKNAME: 914 return (linux_getsockname(td, arg)); 915 case LINUX_GETPEERNAME: 916 return (linux_getpeername(td, arg)); 917 case LINUX_SOCKETPAIR: 918 return (linux_socketpair(td, arg)); 919 case LINUX_SEND: 920 return (linux_send(td, arg)); 921 case LINUX_RECV: 922 return (linux_recv(td, arg)); 923 case LINUX_SENDTO: 924 return (linux_sendto(td, arg)); 925 case LINUX_RECVFROM: 926 return (linux_recvfrom(td, arg)); 927 case LINUX_SHUTDOWN: 928 return (linux_shutdown(td, arg)); 929 case LINUX_SETSOCKOPT: 930 return (linux_setsockopt(td, arg)); 931 case LINUX_GETSOCKOPT: 932 return (linux_getsockopt(td, arg)); 933 case LINUX_SENDMSG: 934 do { 935 int error; 936 int level; 937 caddr_t control; 938 struct { 939 int s; 940 const struct msghdr *msg; 941 int flags; 942 } *uap = arg; 943 944 error = copyin(&uap->msg->msg_control, &control, 945 sizeof(caddr_t)); 946 if (error) 947 return (error); 948 949 if (control == NULL) 950 goto done; 951 952 error = copyin(&((struct cmsghdr*)control)->cmsg_level, 953 &level, sizeof(int)); 954 if (error) 955 return (error); 956 957 if (level == 1) { 958 /* 959 * Linux thinks that SOL_SOCKET is 1; we know 960 * that it's really 0xffff, of course. 961 */ 962 level = SOL_SOCKET; 963 error = copyout(&level, 964 &((struct cmsghdr *)control)->cmsg_level, 965 sizeof(int)); 966 if (error) 967 return (error); 968 } 969 done: 970 return (sendmsg(td, arg)); 971 } while (0); 972 case LINUX_RECVMSG: 973 return (linux_recvmsg(td, arg)); 974 } 975 976 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 977 return (ENOSYS); 978} 979#endif /*!__alpha__*/ 980