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