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