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