linux_socket.c revision 144012
1/*- 2 * Copyright (c) 1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sys/compat/linux/linux_socket.c 144012 2005-03-23 08:28:00Z das $"); 31 32/* XXX we use functions that might not exist. */ 33#include "opt_compat.h" 34#include "opt_inet6.h" 35 36#ifndef COMPAT_43 37#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 38#endif 39 40#include <sys/param.h> 41#include <sys/proc.h> 42#include <sys/systm.h> 43#include <sys/sysproto.h> 44#include <sys/fcntl.h> 45#include <sys/file.h> 46#include <sys/limits.h> 47#include <sys/malloc.h> 48#include <sys/mbuf.h> 49#include <sys/socket.h> 50#include <sys/socketvar.h> 51#include <sys/syscallsubr.h> 52#include <sys/uio.h> 53#include <sys/syslog.h> 54 55#include <netinet/in.h> 56#include <netinet/in_systm.h> 57#include <netinet/ip.h> 58#ifdef INET6 59#include <netinet/ip6.h> 60#include <netinet6/ip6_var.h> 61#endif 62 63#include "opt_compat.h" 64 65#ifdef COMPAT_LINUX32 66#include <machine/../linux32/linux.h> 67#include <machine/../linux32/linux32_proto.h> 68#else 69#include <machine/../linux/linux.h> 70#include <machine/../linux/linux_proto.h> 71#endif 72#include <compat/linux/linux_socket.h> 73#include <compat/linux/linux_util.h> 74 75static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *, 76 struct malloc_type *); 77static int linux_to_bsd_domain(int); 78 79/* 80 * Reads a linux sockaddr and does any necessary translation. 81 * Linux sockaddrs don't have a length field, only a family. 82 */ 83static int 84linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len) 85{ 86 int osalen = len; 87 88 return (do_sa_get(sap, osa, &osalen, M_SONAME)); 89} 90 91/* 92 * Copy the osockaddr structure pointed to by osa to kernel, adjust 93 * family and convert to sockaddr. 94 */ 95static int 96do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen, 97 struct malloc_type *mtype) 98{ 99 int error=0, bdom; 100 struct sockaddr *sa; 101 struct osockaddr *kosa; 102 int alloclen; 103#ifdef INET6 104 int oldv6size; 105 struct sockaddr_in6 *sin6; 106#endif 107 108 if (*osalen < 2 || *osalen > UCHAR_MAX || !osa) 109 return (EINVAL); 110 111 alloclen = *osalen; 112#ifdef INET6 113 oldv6size = 0; 114 /* 115 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 116 * if it's a v4-mapped address, so reserve the proper space 117 * for it. 118 */ 119 if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) { 120 alloclen = sizeof (struct sockaddr_in6); 121 oldv6size = 1; 122 } 123#endif 124 125 MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK); 126 127 if ((error = copyin(osa, kosa, *osalen))) 128 goto out; 129 130 bdom = linux_to_bsd_domain(kosa->sa_family); 131 if (bdom == -1) { 132 error = EINVAL; 133 goto out; 134 } 135 136#ifdef INET6 137 /* 138 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 139 * which lacks the scope id compared with RFC2553 one. If we detect 140 * the situation, reject the address and write a message to system log. 141 * 142 * Still accept addresses for which the scope id is not used. 143 */ 144 if (oldv6size && bdom == AF_INET6) { 145 sin6 = (struct sockaddr_in6 *)kosa; 146 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 147 (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 148 !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 149 !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 150 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 151 !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 152 sin6->sin6_scope_id = 0; 153 } else { 154 log(LOG_DEBUG, 155 "obsolete pre-RFC2553 sockaddr_in6 rejected"); 156 error = EINVAL; 157 goto out; 158 } 159 } else 160#endif 161 if (bdom == AF_INET) 162 alloclen = sizeof(struct sockaddr_in); 163 164 sa = (struct sockaddr *) kosa; 165 sa->sa_family = bdom; 166 sa->sa_len = alloclen; 167 168 *sap = sa; 169 *osalen = alloclen; 170 return (0); 171 172out: 173 FREE(kosa, mtype); 174 return (error); 175} 176 177static int 178linux_to_bsd_domain(int domain) 179{ 180 181 switch (domain) { 182 case LINUX_AF_UNSPEC: 183 return (AF_UNSPEC); 184 case LINUX_AF_UNIX: 185 return (AF_LOCAL); 186 case LINUX_AF_INET: 187 return (AF_INET); 188 case LINUX_AF_INET6: 189 return (AF_INET6); 190 case LINUX_AF_AX25: 191 return (AF_CCITT); 192 case LINUX_AF_IPX: 193 return (AF_IPX); 194 case LINUX_AF_APPLETALK: 195 return (AF_APPLETALK); 196 } 197 return (-1); 198} 199 200#ifndef __alpha__ 201static int 202bsd_to_linux_domain(int domain) 203{ 204 205 switch (domain) { 206 case AF_UNSPEC: 207 return (LINUX_AF_UNSPEC); 208 case AF_LOCAL: 209 return (LINUX_AF_UNIX); 210 case AF_INET: 211 return (LINUX_AF_INET); 212 case AF_INET6: 213 return (LINUX_AF_INET6); 214 case AF_CCITT: 215 return (LINUX_AF_AX25); 216 case AF_IPX: 217 return (LINUX_AF_IPX); 218 case AF_APPLETALK: 219 return (LINUX_AF_APPLETALK); 220 } 221 return (-1); 222} 223 224static int 225linux_to_bsd_sockopt_level(int level) 226{ 227 228 switch (level) { 229 case LINUX_SOL_SOCKET: 230 return (SOL_SOCKET); 231 } 232 return (level); 233} 234 235static int 236bsd_to_linux_sockopt_level(int level) 237{ 238 239 switch (level) { 240 case SOL_SOCKET: 241 return (LINUX_SOL_SOCKET); 242 } 243 return (level); 244} 245 246static int 247linux_to_bsd_ip_sockopt(int opt) 248{ 249 250 switch (opt) { 251 case LINUX_IP_TOS: 252 return (IP_TOS); 253 case LINUX_IP_TTL: 254 return (IP_TTL); 255 case LINUX_IP_OPTIONS: 256 return (IP_OPTIONS); 257 case LINUX_IP_MULTICAST_IF: 258 return (IP_MULTICAST_IF); 259 case LINUX_IP_MULTICAST_TTL: 260 return (IP_MULTICAST_TTL); 261 case LINUX_IP_MULTICAST_LOOP: 262 return (IP_MULTICAST_LOOP); 263 case LINUX_IP_ADD_MEMBERSHIP: 264 return (IP_ADD_MEMBERSHIP); 265 case LINUX_IP_DROP_MEMBERSHIP: 266 return (IP_DROP_MEMBERSHIP); 267 case LINUX_IP_HDRINCL: 268 return (IP_HDRINCL); 269 } 270 return (-1); 271} 272 273static int 274linux_to_bsd_so_sockopt(int opt) 275{ 276 277 switch (opt) { 278 case LINUX_SO_DEBUG: 279 return (SO_DEBUG); 280 case LINUX_SO_REUSEADDR: 281 return (SO_REUSEADDR); 282 case LINUX_SO_TYPE: 283 return (SO_TYPE); 284 case LINUX_SO_ERROR: 285 return (SO_ERROR); 286 case LINUX_SO_DONTROUTE: 287 return (SO_DONTROUTE); 288 case LINUX_SO_BROADCAST: 289 return (SO_BROADCAST); 290 case LINUX_SO_SNDBUF: 291 return (SO_SNDBUF); 292 case LINUX_SO_RCVBUF: 293 return (SO_RCVBUF); 294 case LINUX_SO_KEEPALIVE: 295 return (SO_KEEPALIVE); 296 case LINUX_SO_OOBINLINE: 297 return (SO_OOBINLINE); 298 case LINUX_SO_LINGER: 299 return (SO_LINGER); 300 } 301 return (-1); 302} 303 304static int 305linux_to_bsd_msg_flags(int flags) 306{ 307 int ret_flags = 0; 308 309 if (flags & LINUX_MSG_OOB) 310 ret_flags |= MSG_OOB; 311 if (flags & LINUX_MSG_PEEK) 312 ret_flags |= MSG_PEEK; 313 if (flags & LINUX_MSG_DONTROUTE) 314 ret_flags |= MSG_DONTROUTE; 315 if (flags & LINUX_MSG_CTRUNC) 316 ret_flags |= MSG_CTRUNC; 317 if (flags & LINUX_MSG_TRUNC) 318 ret_flags |= MSG_TRUNC; 319 if (flags & LINUX_MSG_DONTWAIT) 320 ret_flags |= MSG_DONTWAIT; 321 if (flags & LINUX_MSG_EOR) 322 ret_flags |= MSG_EOR; 323 if (flags & LINUX_MSG_WAITALL) 324 ret_flags |= MSG_WAITALL; 325 if (flags & LINUX_MSG_NOSIGNAL) 326 ret_flags |= MSG_NOSIGNAL; 327#if 0 /* not handled */ 328 if (flags & LINUX_MSG_PROXY) 329 ; 330 if (flags & LINUX_MSG_FIN) 331 ; 332 if (flags & LINUX_MSG_SYN) 333 ; 334 if (flags & LINUX_MSG_CONFIRM) 335 ; 336 if (flags & LINUX_MSG_RST) 337 ; 338 if (flags & LINUX_MSG_ERRQUEUE) 339 ; 340#endif 341 return ret_flags; 342} 343 344static int 345linux_sa_put(struct osockaddr *osa) 346{ 347 struct osockaddr sa; 348 int error, bdom; 349 350 /* 351 * Only read/write the osockaddr family part, the rest is 352 * not changed. 353 */ 354 error = copyin(osa, &sa, sizeof(sa.sa_family)); 355 if (error) 356 return (error); 357 358 bdom = bsd_to_linux_domain(sa.sa_family); 359 if (bdom == -1) 360 return (EINVAL); 361 362 sa.sa_family = bdom; 363 error = copyout(&sa, osa, sizeof(sa.sa_family)); 364 if (error) 365 return (error); 366 367 return (0); 368} 369 370static int 371linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 372 enum uio_seg segflg) 373{ 374 struct mbuf *control; 375 struct sockaddr *to; 376 int error; 377 378 if (mp->msg_name != NULL) { 379 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 380 if (error) 381 return (error); 382 mp->msg_name = to; 383 } else 384 to = NULL; 385 386 if (mp->msg_control != NULL) { 387 struct cmsghdr *cmsg; 388 389 if (mp->msg_controllen < sizeof(struct cmsghdr)) { 390 error = EINVAL; 391 goto bad; 392 } 393 error = sockargs(&control, mp->msg_control, 394 mp->msg_controllen, MT_CONTROL); 395 if (error) 396 goto bad; 397 398 cmsg = mtod(control, struct cmsghdr *); 399 cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); 400 } else 401 control = NULL; 402 403 error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 404 segflg); 405 406bad: 407 if (to) 408 FREE(to, M_SONAME); 409 return (error); 410} 411 412/* Return 0 if IP_HDRINCL is set for the given socket. */ 413static int 414linux_check_hdrincl(struct thread *td, int s) 415{ 416 int error, optval, size_val; 417 418 size_val = sizeof(optval); 419 error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 420 &optval, UIO_SYSSPACE, &size_val); 421 if (error) 422 return (error); 423 424 return (optval == 0); 425} 426 427struct linux_sendto_args { 428 int s; 429 l_uintptr_t msg; 430 int len; 431 int flags; 432 l_uintptr_t to; 433 int tolen; 434}; 435 436/* 437 * Updated sendto() when IP_HDRINCL is set: 438 * tweak endian-dependent fields in the IP packet. 439 */ 440static int 441linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 442{ 443/* 444 * linux_ip_copysize defines how many bytes we should copy 445 * from the beginning of the IP packet before we customize it for BSD. 446 * It should include all the fields we modify (ip_len and ip_off). 447 */ 448#define linux_ip_copysize 8 449 450 struct ip *packet; 451 struct msghdr msg; 452 struct iovec aiov[1]; 453 int error; 454 455 /* Check that the packet isn't too big or too small. */ 456 if (linux_args->len < linux_ip_copysize || 457 linux_args->len > IP_MAXPACKET) 458 return (EINVAL); 459 460 packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK); 461 462 /* Make kernel copy of the packet to be sent */ 463 if ((error = copyin(PTRIN(linux_args->msg), packet, 464 linux_args->len))) 465 goto goout; 466 467 /* Convert fields from Linux to BSD raw IP socket format */ 468 packet->ip_len = linux_args->len; 469 packet->ip_off = ntohs(packet->ip_off); 470 471 /* Prepare the msghdr and iovec structures describing the new packet */ 472 msg.msg_name = PTRIN(linux_args->to); 473 msg.msg_namelen = linux_args->tolen; 474 msg.msg_iov = aiov; 475 msg.msg_iovlen = 1; 476 msg.msg_control = NULL; 477 msg.msg_flags = 0; 478 aiov[0].iov_base = (char *)packet; 479 aiov[0].iov_len = linux_args->len; 480 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 481 UIO_SYSSPACE); 482goout: 483 free(packet, M_TEMP); 484 return (error); 485} 486 487struct linux_socket_args { 488 int domain; 489 int type; 490 int protocol; 491}; 492 493static int 494linux_socket(struct thread *td, struct linux_socket_args *args) 495{ 496 struct linux_socket_args linux_args; 497 struct socket_args /* { 498 int domain; 499 int type; 500 int protocol; 501 } */ bsd_args; 502 int error; 503 int retval_socket; 504 505 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 506 return (error); 507 508 bsd_args.protocol = linux_args.protocol; 509 bsd_args.type = linux_args.type; 510 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 511 if (bsd_args.domain == -1) 512 return (EINVAL); 513 514 retval_socket = socket(td, &bsd_args); 515 if (bsd_args.type == SOCK_RAW 516 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 517 && bsd_args.domain == AF_INET 518 && retval_socket >= 0) { 519 /* It's a raw IP socket: set the IP_HDRINCL option. */ 520 int hdrincl; 521 522 hdrincl = 1; 523 /* We ignore any error returned by kern_setsockopt() */ 524 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 525 &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 526 } 527#ifdef INET6 528 /* 529 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 530 * default and some apps depend on this. So, set V6ONLY to 0 531 * for Linux apps if the sysctl value is set to 1. 532 */ 533 if (bsd_args.domain == PF_INET6 && retval_socket >= 0 534#ifndef KLD_MODULE 535 /* 536 * XXX: Avoid undefined symbol error with an IPv4 only 537 * kernel. 538 */ 539 && ip6_v6only 540#endif 541 ) { 542 int v6only; 543 544 v6only = 0; 545 /* We ignore any error returned by setsockopt() */ 546 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 547 &v6only, UIO_SYSSPACE, sizeof(v6only)); 548 } 549#endif 550 551 return (retval_socket); 552} 553 554struct linux_bind_args { 555 int s; 556 l_uintptr_t name; 557 int namelen; 558}; 559 560static int 561linux_bind(struct thread *td, struct linux_bind_args *args) 562{ 563 struct linux_bind_args linux_args; 564 struct sockaddr *sa; 565 int error; 566 567 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 568 return (error); 569 570 error = linux_getsockaddr(&sa, PTRIN(linux_args.name), 571 linux_args.namelen); 572 if (error) 573 return (error); 574 575 return (kern_bind(td, linux_args.s, sa)); 576} 577 578struct linux_connect_args { 579 int s; 580 l_uintptr_t name; 581 int namelen; 582}; 583int linux_connect(struct thread *, struct linux_connect_args *); 584#endif /* !__alpha__*/ 585 586int 587linux_connect(struct thread *td, struct linux_connect_args *args) 588{ 589 struct linux_connect_args linux_args; 590 struct socket *so; 591 struct sockaddr *sa; 592 u_int fflag; 593 int error; 594 595#ifdef __alpha__ 596 bcopy(args, &linux_args, sizeof(linux_args)); 597#else 598 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 599 return (error); 600#endif /* __alpha__ */ 601 602 error = linux_getsockaddr(&sa, 603 (struct osockaddr *)PTRIN(linux_args.name), 604 linux_args.namelen); 605 if (error) 606 return (error); 607 608 error = kern_connect(td, linux_args.s, sa); 609 if (error != EISCONN) 610 return (error); 611 612 /* 613 * Linux doesn't return EISCONN the first time it occurs, 614 * when on a non-blocking socket. Instead it returns the 615 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 616 */ 617 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 618 return(error); 619 error = EISCONN; 620 if (fflag & FNONBLOCK) { 621 if (so->so_emuldata == 0) 622 error = so->so_error; 623 so->so_emuldata = (void *)1; 624 } 625 fputsock(so); 626 return (error); 627} 628 629#ifndef __alpha__ 630 631struct linux_listen_args { 632 int s; 633 int backlog; 634}; 635 636static int 637linux_listen(struct thread *td, struct linux_listen_args *args) 638{ 639 struct linux_listen_args linux_args; 640 struct listen_args /* { 641 int s; 642 int backlog; 643 } */ bsd_args; 644 int error; 645 646 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 647 return (error); 648 649 bsd_args.s = linux_args.s; 650 bsd_args.backlog = linux_args.backlog; 651 return (listen(td, &bsd_args)); 652} 653 654struct linux_accept_args { 655 int s; 656 l_uintptr_t addr; 657 l_uintptr_t namelen; 658}; 659 660static int 661linux_accept(struct thread *td, struct linux_accept_args *args) 662{ 663 struct linux_accept_args linux_args; 664 struct accept_args /* { 665 int s; 666 struct sockaddr * __restrict name; 667 socklen_t * __restrict anamelen; 668 } */ bsd_args; 669 struct close_args /* { 670 int fd; 671 } */ c_args; 672 int error, fd; 673 674 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 675 return (error); 676 677 bsd_args.s = linux_args.s; 678 /* XXX: */ 679 bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr); 680 bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */ 681 error = oaccept(td, &bsd_args); 682 if (error) 683 return (error); 684 if (linux_args.addr) { 685 error = linux_sa_put(PTRIN(linux_args.addr)); 686 if (error) { 687 c_args.fd = td->td_retval[0]; 688 (void)close(td, &c_args); 689 return (error); 690 } 691 } 692 693 /* 694 * linux appears not to copy flags from the parent socket to the 695 * accepted one, so we must clear the flags in the new descriptor. 696 * Ignore any errors, because we already have an open fd. 697 */ 698 fd = td->td_retval[0]; 699 (void)kern_fcntl(td, fd, F_SETFL, 0); 700 td->td_retval[0] = fd; 701 return (0); 702} 703 704struct linux_getsockname_args { 705 int s; 706 l_uintptr_t addr; 707 l_uintptr_t namelen; 708}; 709 710static int 711linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 712{ 713 struct linux_getsockname_args linux_args; 714 struct getsockname_args /* { 715 int fdes; 716 struct sockaddr * __restrict asa; 717 socklen_t * __restrict alen; 718 } */ bsd_args; 719 int error; 720 721 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 722 return (error); 723 724 bsd_args.fdes = linux_args.s; 725 /* XXX: */ 726 bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr); 727 bsd_args.alen = PTRIN(linux_args.namelen); /* XXX */ 728 error = ogetsockname(td, &bsd_args); 729 if (error) 730 return (error); 731 error = linux_sa_put(PTRIN(linux_args.addr)); 732 if (error) 733 return (error); 734 return (0); 735} 736 737struct linux_getpeername_args { 738 int s; 739 l_uintptr_t addr; 740 l_uintptr_t namelen; 741}; 742 743static int 744linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 745{ 746 struct linux_getpeername_args linux_args; 747 struct ogetpeername_args /* { 748 int fdes; 749 caddr_t asa; 750 int *alen; 751 } */ bsd_args; 752 int error; 753 754 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 755 return (error); 756 757 bsd_args.fdes = linux_args.s; 758 bsd_args.asa = (caddr_t)PTRIN(linux_args.addr); 759 bsd_args.alen = (int *)PTRIN(linux_args.namelen); 760 error = ogetpeername(td, &bsd_args); 761 if (error) 762 return (error); 763 error = linux_sa_put(PTRIN(linux_args.addr)); 764 if (error) 765 return (error); 766 return (0); 767} 768 769struct linux_socketpair_args { 770 int domain; 771 int type; 772 int protocol; 773 l_uintptr_t rsv; 774}; 775 776static int 777linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 778{ 779 struct linux_socketpair_args linux_args; 780 struct socketpair_args /* { 781 int domain; 782 int type; 783 int protocol; 784 int *rsv; 785 } */ bsd_args; 786 int error; 787 788 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 789 return (error); 790 791 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 792 if (bsd_args.domain == -1) 793 return (EINVAL); 794 795 bsd_args.type = linux_args.type; 796 bsd_args.protocol = linux_args.protocol; 797 bsd_args.rsv = (int *)PTRIN(linux_args.rsv); 798 return (socketpair(td, &bsd_args)); 799} 800 801struct linux_send_args { 802 int s; 803 l_uintptr_t msg; 804 int len; 805 int flags; 806}; 807 808static int 809linux_send(struct thread *td, struct linux_send_args *args) 810{ 811 struct linux_send_args linux_args; 812 struct sendto_args /* { 813 int s; 814 caddr_t buf; 815 int len; 816 int flags; 817 caddr_t to; 818 int tolen; 819 } */ bsd_args; 820 int error; 821 822 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 823 return (error); 824 825 bsd_args.s = linux_args.s; 826 bsd_args.buf = (caddr_t)PTRIN(linux_args.msg); 827 bsd_args.len = linux_args.len; 828 bsd_args.flags = linux_args.flags; 829 bsd_args.to = NULL; 830 bsd_args.tolen = 0; 831 return sendto(td, &bsd_args); 832} 833 834struct linux_recv_args { 835 int s; 836 l_uintptr_t msg; 837 int len; 838 int flags; 839}; 840 841static int 842linux_recv(struct thread *td, struct linux_recv_args *args) 843{ 844 struct linux_recv_args linux_args; 845 struct recvfrom_args /* { 846 int s; 847 caddr_t buf; 848 int len; 849 int flags; 850 struct sockaddr *from; 851 socklen_t fromlenaddr; 852 } */ bsd_args; 853 int error; 854 855 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 856 return (error); 857 858 bsd_args.s = linux_args.s; 859 bsd_args.buf = (caddr_t)PTRIN(linux_args.msg); 860 bsd_args.len = linux_args.len; 861 bsd_args.flags = linux_args.flags; 862 bsd_args.from = NULL; 863 bsd_args.fromlenaddr = 0; 864 return (recvfrom(td, &bsd_args)); 865} 866 867static int 868linux_sendto(struct thread *td, struct linux_sendto_args *args) 869{ 870 struct linux_sendto_args linux_args; 871 struct msghdr msg; 872 struct iovec aiov; 873 int error; 874 875 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 876 return (error); 877 878 if (linux_check_hdrincl(td, linux_args.s) == 0) 879 /* IP_HDRINCL set, tweak the packet before sending */ 880 return (linux_sendto_hdrincl(td, &linux_args)); 881 882 msg.msg_name = PTRIN(linux_args.to); 883 msg.msg_namelen = linux_args.tolen; 884 msg.msg_iov = &aiov; 885 msg.msg_iovlen = 1; 886 msg.msg_control = NULL; 887 msg.msg_flags = 0; 888 aiov.iov_base = PTRIN(linux_args.msg); 889 aiov.iov_len = linux_args.len; 890 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags, 891 UIO_USERSPACE); 892 return (error); 893} 894 895struct linux_recvfrom_args { 896 int s; 897 l_uintptr_t buf; 898 int len; 899 int flags; 900 l_uintptr_t from; 901 l_uintptr_t fromlen; 902}; 903 904static int 905linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 906{ 907 struct linux_recvfrom_args linux_args; 908 struct recvfrom_args /* { 909 int s; 910 caddr_t buf; 911 size_t len; 912 int flags; 913 struct sockaddr * __restrict from; 914 socklen_t * __restrict fromlenaddr; 915 } */ bsd_args; 916 int error; 917 918 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 919 return (error); 920 921 bsd_args.s = linux_args.s; 922 bsd_args.buf = PTRIN(linux_args.buf); 923 bsd_args.len = linux_args.len; 924 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 925 /* XXX: */ 926 bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from); 927 bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */ 928 error = orecvfrom(td, &bsd_args); 929 if (error) 930 return (error); 931 if (linux_args.from) { 932 error = linux_sa_put((struct osockaddr *) 933 PTRIN(linux_args.from)); 934 if (error) 935 return (error); 936 } 937 return (0); 938} 939 940struct linux_sendmsg_args { 941 int s; 942 l_uintptr_t msg; 943 int flags; 944}; 945 946static int 947linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 948{ 949 struct linux_sendmsg_args linux_args; 950 struct msghdr msg; 951 struct iovec *iov; 952 int error; 953 954 /* XXXTJR sendmsg is broken on amd64 */ 955 956 error = copyin(args, &linux_args, sizeof(linux_args)); 957 if (error) 958 return (error); 959 error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); 960 if (error) 961 return (error); 962 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 963 if (error) 964 return (error); 965 msg.msg_iov = iov; 966 msg.msg_flags = 0; 967 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags, 968 UIO_USERSPACE); 969 free(iov, M_IOV); 970 return (error); 971} 972 973struct linux_recvmsg_args { 974 int s; 975 l_uintptr_t msg; 976 int flags; 977}; 978 979static int 980linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 981{ 982 struct linux_recvmsg_args linux_args; 983 struct recvmsg_args /* { 984 int s; 985 struct msghdr *msg; 986 int flags; 987 } */ bsd_args; 988 struct msghdr msg; 989 struct cmsghdr *cmsg; 990 int error; 991 992 /* XXXTJR recvmsg is broken on amd64 */ 993 994 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 995 return (error); 996 997 bsd_args.s = linux_args.s; 998 bsd_args.msg = PTRIN(linux_args.msg); 999 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 1000 error = recvmsg(td, &bsd_args); 1001 if (error) 1002 return (error); 1003 1004 if (bsd_args.msg->msg_control != NULL && 1005 bsd_args.msg->msg_controllen > 0) { 1006 cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; 1007 cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); 1008 } 1009 1010 error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); 1011 if (error) 1012 return (error); 1013 if (msg.msg_name && msg.msg_namelen > 2) 1014 error = linux_sa_put(msg.msg_name); 1015 return (error); 1016} 1017 1018struct linux_shutdown_args { 1019 int s; 1020 int how; 1021}; 1022 1023static int 1024linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1025{ 1026 struct linux_shutdown_args linux_args; 1027 struct shutdown_args /* { 1028 int s; 1029 int how; 1030 } */ bsd_args; 1031 int error; 1032 1033 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1034 return (error); 1035 1036 bsd_args.s = linux_args.s; 1037 bsd_args.how = linux_args.how; 1038 return (shutdown(td, &bsd_args)); 1039} 1040 1041struct linux_setsockopt_args { 1042 int s; 1043 int level; 1044 int optname; 1045 l_uintptr_t optval; 1046 int optlen; 1047}; 1048 1049static int 1050linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1051{ 1052 struct linux_setsockopt_args linux_args; 1053 struct setsockopt_args /* { 1054 int s; 1055 int level; 1056 int name; 1057 caddr_t val; 1058 int valsize; 1059 } */ bsd_args; 1060 int error, name; 1061 1062 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1063 return (error); 1064 1065 bsd_args.s = linux_args.s; 1066 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1067 switch (bsd_args.level) { 1068 case SOL_SOCKET: 1069 name = linux_to_bsd_so_sockopt(linux_args.optname); 1070 break; 1071 case IPPROTO_IP: 1072 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1073 break; 1074 case IPPROTO_TCP: 1075 /* Linux TCP option values match BSD's */ 1076 name = linux_args.optname; 1077 break; 1078 default: 1079 name = -1; 1080 break; 1081 } 1082 if (name == -1) 1083 return (EINVAL); 1084 1085 bsd_args.name = name; 1086 bsd_args.val = PTRIN(linux_args.optval); 1087 bsd_args.valsize = linux_args.optlen; 1088 return (setsockopt(td, &bsd_args)); 1089} 1090 1091struct linux_getsockopt_args { 1092 int s; 1093 int level; 1094 int optname; 1095 l_uintptr_t optval; 1096 l_uintptr_t optlen; 1097}; 1098 1099static int 1100linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1101{ 1102 struct linux_getsockopt_args linux_args; 1103 struct getsockopt_args /* { 1104 int s; 1105 int level; 1106 int name; 1107 caddr_t val; 1108 int *avalsize; 1109 } */ bsd_args; 1110 int error, name; 1111 1112 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1113 return (error); 1114 1115 bsd_args.s = linux_args.s; 1116 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1117 switch (bsd_args.level) { 1118 case SOL_SOCKET: 1119 name = linux_to_bsd_so_sockopt(linux_args.optname); 1120 break; 1121 case IPPROTO_IP: 1122 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1123 break; 1124 case IPPROTO_TCP: 1125 /* Linux TCP option values match BSD's */ 1126 name = linux_args.optname; 1127 break; 1128 default: 1129 name = -1; 1130 break; 1131 } 1132 if (name == -1) 1133 return (EINVAL); 1134 1135 bsd_args.name = name; 1136 bsd_args.val = PTRIN(linux_args.optval); 1137 bsd_args.avalsize = PTRIN(linux_args.optlen); 1138 return (getsockopt(td, &bsd_args)); 1139} 1140 1141int 1142linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1143{ 1144 void *arg = (void *)(intptr_t)args->args; 1145 1146 switch (args->what) { 1147 case LINUX_SOCKET: 1148 return (linux_socket(td, arg)); 1149 case LINUX_BIND: 1150 return (linux_bind(td, arg)); 1151 case LINUX_CONNECT: 1152 return (linux_connect(td, arg)); 1153 case LINUX_LISTEN: 1154 return (linux_listen(td, arg)); 1155 case LINUX_ACCEPT: 1156 return (linux_accept(td, arg)); 1157 case LINUX_GETSOCKNAME: 1158 return (linux_getsockname(td, arg)); 1159 case LINUX_GETPEERNAME: 1160 return (linux_getpeername(td, arg)); 1161 case LINUX_SOCKETPAIR: 1162 return (linux_socketpair(td, arg)); 1163 case LINUX_SEND: 1164 return (linux_send(td, arg)); 1165 case LINUX_RECV: 1166 return (linux_recv(td, arg)); 1167 case LINUX_SENDTO: 1168 return (linux_sendto(td, arg)); 1169 case LINUX_RECVFROM: 1170 return (linux_recvfrom(td, arg)); 1171 case LINUX_SHUTDOWN: 1172 return (linux_shutdown(td, arg)); 1173 case LINUX_SETSOCKOPT: 1174 return (linux_setsockopt(td, arg)); 1175 case LINUX_GETSOCKOPT: 1176 return (linux_getsockopt(td, arg)); 1177 case LINUX_SENDMSG: 1178 return (linux_sendmsg(td, arg)); 1179 case LINUX_RECVMSG: 1180 return (linux_recvmsg(td, arg)); 1181 } 1182 1183 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1184 return (ENOSYS); 1185} 1186#endif /*!__alpha__*/ 1187