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