linux_socket.c revision 143233
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 143233 2005-03-07 07:26:42Z sobomax $"); 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 0 /* not handled */ 326 if (flags & LINUX_MSG_PROXY) 327 ; 328 if (flags & LINUX_MSG_FIN) 329 ; 330 if (flags & LINUX_MSG_SYN) 331 ; 332 if (flags & LINUX_MSG_CONFIRM) 333 ; 334 if (flags & LINUX_MSG_RST) 335 ; 336 if (flags & LINUX_MSG_ERRQUEUE) 337 ; 338 if (flags & LINUX_MSG_NOSIGNAL) 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 the packet isn't too small before we mess with it */ 456 if (linux_args->len < linux_ip_copysize) 457 return (EINVAL); 458 459 packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK); 460 461 /* Make kernel copy of the packet to be sent */ 462 if ((error = copyin(PTRIN(linux_args->msg), packet, 463 linux_args->len))) 464 goto goout; 465 466 /* Convert fields from Linux to BSD raw IP socket format */ 467 packet->ip_len = linux_args->len; 468 packet->ip_off = ntohs(packet->ip_off); 469 470 /* Prepare the msghdr and iovec structures describing the new packet */ 471 msg.msg_name = PTRIN(linux_args->to); 472 msg.msg_namelen = linux_args->tolen; 473 msg.msg_iov = aiov; 474 msg.msg_iovlen = 1; 475 msg.msg_control = NULL; 476 msg.msg_flags = 0; 477 aiov[0].iov_base = (char *)packet; 478 aiov[0].iov_len = linux_args->len; 479 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 480 UIO_SYSSPACE); 481goout: 482 free(packet, M_TEMP); 483 return (error); 484} 485 486struct linux_socket_args { 487 int domain; 488 int type; 489 int protocol; 490}; 491 492static int 493linux_socket(struct thread *td, struct linux_socket_args *args) 494{ 495 struct linux_socket_args linux_args; 496 struct socket_args /* { 497 int domain; 498 int type; 499 int protocol; 500 } */ bsd_args; 501 int error; 502 int retval_socket; 503 504 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 505 return (error); 506 507 bsd_args.protocol = linux_args.protocol; 508 bsd_args.type = linux_args.type; 509 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 510 if (bsd_args.domain == -1) 511 return (EINVAL); 512 513 retval_socket = socket(td, &bsd_args); 514 if (bsd_args.type == SOCK_RAW 515 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 516 && bsd_args.domain == AF_INET 517 && retval_socket >= 0) { 518 /* It's a raw IP socket: set the IP_HDRINCL option. */ 519 int hdrincl; 520 521 hdrincl = 1; 522 /* We ignore any error returned by kern_setsockopt() */ 523 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 524 &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 525 } 526#ifdef INET6 527 /* 528 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 529 * default and some apps depend on this. So, set V6ONLY to 0 530 * for Linux apps if the sysctl value is set to 1. 531 */ 532 if (bsd_args.domain == PF_INET6 && retval_socket >= 0 533#ifndef KLD_MODULE 534 /* 535 * XXX: Avoid undefined symbol error with an IPv4 only 536 * kernel. 537 */ 538 && ip6_v6only 539#endif 540 ) { 541 int v6only; 542 543 v6only = 0; 544 /* We ignore any error returned by setsockopt() */ 545 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 546 &v6only, UIO_SYSSPACE, sizeof(v6only)); 547 } 548#endif 549 550 return (retval_socket); 551} 552 553struct linux_bind_args { 554 int s; 555 l_uintptr_t name; 556 int namelen; 557}; 558 559static int 560linux_bind(struct thread *td, struct linux_bind_args *args) 561{ 562 struct linux_bind_args linux_args; 563 struct sockaddr *sa; 564 int error; 565 566 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 567 return (error); 568 569 error = linux_getsockaddr(&sa, PTRIN(linux_args.name), 570 linux_args.namelen); 571 if (error) 572 return (error); 573 574 return (kern_bind(td, linux_args.s, sa)); 575} 576 577struct linux_connect_args { 578 int s; 579 l_uintptr_t name; 580 int namelen; 581}; 582int linux_connect(struct thread *, struct linux_connect_args *); 583#endif /* !__alpha__*/ 584 585int 586linux_connect(struct thread *td, struct linux_connect_args *args) 587{ 588 struct linux_connect_args linux_args; 589 struct socket *so; 590 struct sockaddr *sa; 591 u_int fflag; 592 int error; 593 594#ifdef __alpha__ 595 bcopy(args, &linux_args, sizeof(linux_args)); 596#else 597 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 598 return (error); 599#endif /* __alpha__ */ 600 601 error = linux_getsockaddr(&sa, 602 (struct osockaddr *)PTRIN(linux_args.name), 603 linux_args.namelen); 604 if (error) 605 return (error); 606 607 error = kern_connect(td, linux_args.s, sa); 608 if (error != EISCONN) 609 return (error); 610 611 /* 612 * Linux doesn't return EISCONN the first time it occurs, 613 * when on a non-blocking socket. Instead it returns the 614 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 615 */ 616 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 617 return(error); 618 error = EISCONN; 619 if (fflag & FNONBLOCK) { 620 if (so->so_emuldata == 0) 621 error = so->so_error; 622 so->so_emuldata = (void *)1; 623 } 624 fputsock(so); 625 return (error); 626} 627 628#ifndef __alpha__ 629 630struct linux_listen_args { 631 int s; 632 int backlog; 633}; 634 635static int 636linux_listen(struct thread *td, struct linux_listen_args *args) 637{ 638 struct linux_listen_args linux_args; 639 struct listen_args /* { 640 int s; 641 int backlog; 642 } */ bsd_args; 643 int error; 644 645 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 646 return (error); 647 648 bsd_args.s = linux_args.s; 649 bsd_args.backlog = linux_args.backlog; 650 return (listen(td, &bsd_args)); 651} 652 653struct linux_accept_args { 654 int s; 655 l_uintptr_t addr; 656 l_uintptr_t namelen; 657}; 658 659static int 660linux_accept(struct thread *td, struct linux_accept_args *args) 661{ 662 struct linux_accept_args linux_args; 663 struct accept_args /* { 664 int s; 665 struct sockaddr * __restrict name; 666 socklen_t * __restrict anamelen; 667 } */ bsd_args; 668 struct close_args /* { 669 int fd; 670 } */ c_args; 671 int error, fd; 672 673 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 674 return (error); 675 676 bsd_args.s = linux_args.s; 677 /* XXX: */ 678 bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr); 679 bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */ 680 error = oaccept(td, &bsd_args); 681 if (error) 682 return (error); 683 if (linux_args.addr) { 684 error = linux_sa_put(PTRIN(linux_args.addr)); 685 if (error) { 686 c_args.fd = td->td_retval[0]; 687 (void)close(td, &c_args); 688 return (error); 689 } 690 } 691 692 /* 693 * linux appears not to copy flags from the parent socket to the 694 * accepted one, so we must clear the flags in the new descriptor. 695 * Ignore any errors, because we already have an open fd. 696 */ 697 fd = td->td_retval[0]; 698 (void)kern_fcntl(td, fd, F_SETFL, 0); 699 td->td_retval[0] = fd; 700 return (0); 701} 702 703struct linux_getsockname_args { 704 int s; 705 l_uintptr_t addr; 706 l_uintptr_t namelen; 707}; 708 709static int 710linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 711{ 712 struct linux_getsockname_args linux_args; 713 struct getsockname_args /* { 714 int fdes; 715 struct sockaddr * __restrict asa; 716 socklen_t * __restrict alen; 717 } */ bsd_args; 718 int error; 719 720 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 721 return (error); 722 723 bsd_args.fdes = linux_args.s; 724 /* XXX: */ 725 bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr); 726 bsd_args.alen = PTRIN(linux_args.namelen); /* XXX */ 727 error = ogetsockname(td, &bsd_args); 728 if (error) 729 return (error); 730 error = linux_sa_put(PTRIN(linux_args.addr)); 731 if (error) 732 return (error); 733 return (0); 734} 735 736struct linux_getpeername_args { 737 int s; 738 l_uintptr_t addr; 739 l_uintptr_t namelen; 740}; 741 742static int 743linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 744{ 745 struct linux_getpeername_args linux_args; 746 struct ogetpeername_args /* { 747 int fdes; 748 caddr_t asa; 749 int *alen; 750 } */ bsd_args; 751 int error; 752 753 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 754 return (error); 755 756 bsd_args.fdes = linux_args.s; 757 bsd_args.asa = (caddr_t)PTRIN(linux_args.addr); 758 bsd_args.alen = (int *)PTRIN(linux_args.namelen); 759 error = ogetpeername(td, &bsd_args); 760 if (error) 761 return (error); 762 error = linux_sa_put(PTRIN(linux_args.addr)); 763 if (error) 764 return (error); 765 return (0); 766} 767 768struct linux_socketpair_args { 769 int domain; 770 int type; 771 int protocol; 772 l_uintptr_t rsv; 773}; 774 775static int 776linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 777{ 778 struct linux_socketpair_args linux_args; 779 struct socketpair_args /* { 780 int domain; 781 int type; 782 int protocol; 783 int *rsv; 784 } */ bsd_args; 785 int error; 786 787 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 788 return (error); 789 790 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 791 if (bsd_args.domain == -1) 792 return (EINVAL); 793 794 bsd_args.type = linux_args.type; 795 bsd_args.protocol = linux_args.protocol; 796 bsd_args.rsv = (int *)PTRIN(linux_args.rsv); 797 return (socketpair(td, &bsd_args)); 798} 799 800struct linux_send_args { 801 int s; 802 l_uintptr_t msg; 803 int len; 804 int flags; 805}; 806 807static int 808linux_send(struct thread *td, struct linux_send_args *args) 809{ 810 struct linux_send_args linux_args; 811 struct sendto_args /* { 812 int s; 813 caddr_t buf; 814 int len; 815 int flags; 816 caddr_t to; 817 int tolen; 818 } */ bsd_args; 819 int error, nosigpipe, onosigpipe; 820 socklen_t valsize; 821 822 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 823 return (error); 824 825 if (linux_args.flags & LINUX_MSG_NOSIGNAL) { 826 valsize = sizeof(onosigpipe); 827 error = kern_getsockopt(td, linux_args.s, SOL_SOCKET, 828 SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE, 829 &valsize); 830 if (error != 0) 831 return error; 832 if (onosigpipe == 0) { 833 nosigpipe = 1; 834 error = kern_setsockopt(td, linux_args.s, SOL_SOCKET, 835 SO_NOSIGPIPE, &nosigpipe, UIO_SYSSPACE, 836 sizeof(nosigpipe)); 837 if (error != 0) 838 return error; 839 } 840 } 841 bsd_args.s = linux_args.s; 842 bsd_args.buf = (caddr_t)PTRIN(linux_args.msg); 843 bsd_args.len = linux_args.len; 844 bsd_args.flags = linux_args.flags; 845 bsd_args.to = NULL; 846 bsd_args.tolen = 0; 847 error = sendto(td, &bsd_args); 848 if ((linux_args.flags & LINUX_MSG_NOSIGNAL) && (onosigpipe == 0)) { 849 kern_setsockopt(td, linux_args.s, SOL_SOCKET, 850 SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE, 851 sizeof(onosigpipe)); 852 } 853 return error; 854} 855 856struct linux_recv_args { 857 int s; 858 l_uintptr_t msg; 859 int len; 860 int flags; 861}; 862 863static int 864linux_recv(struct thread *td, struct linux_recv_args *args) 865{ 866 struct linux_recv_args linux_args; 867 struct recvfrom_args /* { 868 int s; 869 caddr_t buf; 870 int len; 871 int flags; 872 struct sockaddr *from; 873 socklen_t fromlenaddr; 874 } */ bsd_args; 875 int error; 876 877 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 878 return (error); 879 880 bsd_args.s = linux_args.s; 881 bsd_args.buf = (caddr_t)PTRIN(linux_args.msg); 882 bsd_args.len = linux_args.len; 883 bsd_args.flags = linux_args.flags; 884 bsd_args.from = NULL; 885 bsd_args.fromlenaddr = 0; 886 return (recvfrom(td, &bsd_args)); 887} 888 889static int 890linux_sendto(struct thread *td, struct linux_sendto_args *args) 891{ 892 struct linux_sendto_args linux_args; 893 struct msghdr msg; 894 struct iovec aiov; 895 int error; 896 897 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 898 return (error); 899 900 if (linux_check_hdrincl(td, linux_args.s) == 0) 901 /* IP_HDRINCL set, tweak the packet before sending */ 902 return (linux_sendto_hdrincl(td, &linux_args)); 903 904 msg.msg_name = PTRIN(linux_args.to); 905 msg.msg_namelen = linux_args.tolen; 906 msg.msg_iov = &aiov; 907 msg.msg_iovlen = 1; 908 msg.msg_control = NULL; 909 msg.msg_flags = 0; 910 aiov.iov_base = PTRIN(linux_args.msg); 911 aiov.iov_len = linux_args.len; 912 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags, 913 UIO_USERSPACE); 914 return (error); 915} 916 917struct linux_recvfrom_args { 918 int s; 919 l_uintptr_t buf; 920 int len; 921 int flags; 922 l_uintptr_t from; 923 l_uintptr_t fromlen; 924}; 925 926static int 927linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 928{ 929 struct linux_recvfrom_args linux_args; 930 struct recvfrom_args /* { 931 int s; 932 caddr_t buf; 933 size_t len; 934 int flags; 935 struct sockaddr * __restrict from; 936 socklen_t * __restrict fromlenaddr; 937 } */ bsd_args; 938 int error; 939 940 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 941 return (error); 942 943 bsd_args.s = linux_args.s; 944 bsd_args.buf = PTRIN(linux_args.buf); 945 bsd_args.len = linux_args.len; 946 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 947 /* XXX: */ 948 bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from); 949 bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */ 950 error = orecvfrom(td, &bsd_args); 951 if (error) 952 return (error); 953 if (linux_args.from) { 954 error = linux_sa_put((struct osockaddr *) 955 PTRIN(linux_args.from)); 956 if (error) 957 return (error); 958 } 959 return (0); 960} 961 962struct linux_sendmsg_args { 963 int s; 964 l_uintptr_t msg; 965 int flags; 966}; 967 968static int 969linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 970{ 971 struct linux_sendmsg_args linux_args; 972 struct msghdr msg; 973 struct iovec *iov; 974 int error; 975 976 /* XXXTJR sendmsg is broken on amd64 */ 977 978 error = copyin(args, &linux_args, sizeof(linux_args)); 979 if (error) 980 return (error); 981 error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); 982 if (error) 983 return (error); 984 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 985 if (error) 986 return (error); 987 msg.msg_iov = iov; 988 msg.msg_flags = 0; 989 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags, 990 UIO_USERSPACE); 991 free(iov, M_IOV); 992 return (error); 993} 994 995struct linux_recvmsg_args { 996 int s; 997 l_uintptr_t msg; 998 int flags; 999}; 1000 1001static int 1002linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1003{ 1004 struct linux_recvmsg_args linux_args; 1005 struct recvmsg_args /* { 1006 int s; 1007 struct msghdr *msg; 1008 int flags; 1009 } */ bsd_args; 1010 struct msghdr msg; 1011 struct cmsghdr *cmsg; 1012 int error; 1013 1014 /* XXXTJR recvmsg is broken on amd64 */ 1015 1016 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1017 return (error); 1018 1019 bsd_args.s = linux_args.s; 1020 bsd_args.msg = PTRIN(linux_args.msg); 1021 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 1022 error = recvmsg(td, &bsd_args); 1023 if (error) 1024 return (error); 1025 1026 if (bsd_args.msg->msg_control != NULL && 1027 bsd_args.msg->msg_controllen > 0) { 1028 cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; 1029 cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); 1030 } 1031 1032 error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg)); 1033 if (error) 1034 return (error); 1035 if (msg.msg_name && msg.msg_namelen > 2) 1036 error = linux_sa_put(msg.msg_name); 1037 return (error); 1038} 1039 1040struct linux_shutdown_args { 1041 int s; 1042 int how; 1043}; 1044 1045static int 1046linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1047{ 1048 struct linux_shutdown_args linux_args; 1049 struct shutdown_args /* { 1050 int s; 1051 int how; 1052 } */ bsd_args; 1053 int error; 1054 1055 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1056 return (error); 1057 1058 bsd_args.s = linux_args.s; 1059 bsd_args.how = linux_args.how; 1060 return (shutdown(td, &bsd_args)); 1061} 1062 1063struct linux_setsockopt_args { 1064 int s; 1065 int level; 1066 int optname; 1067 l_uintptr_t optval; 1068 int optlen; 1069}; 1070 1071static int 1072linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1073{ 1074 struct linux_setsockopt_args linux_args; 1075 struct setsockopt_args /* { 1076 int s; 1077 int level; 1078 int name; 1079 caddr_t val; 1080 int valsize; 1081 } */ bsd_args; 1082 int error, name; 1083 1084 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1085 return (error); 1086 1087 bsd_args.s = linux_args.s; 1088 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1089 switch (bsd_args.level) { 1090 case SOL_SOCKET: 1091 name = linux_to_bsd_so_sockopt(linux_args.optname); 1092 break; 1093 case IPPROTO_IP: 1094 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1095 break; 1096 case IPPROTO_TCP: 1097 /* Linux TCP option values match BSD's */ 1098 name = linux_args.optname; 1099 break; 1100 default: 1101 name = -1; 1102 break; 1103 } 1104 if (name == -1) 1105 return (EINVAL); 1106 1107 bsd_args.name = name; 1108 bsd_args.val = PTRIN(linux_args.optval); 1109 bsd_args.valsize = linux_args.optlen; 1110 return (setsockopt(td, &bsd_args)); 1111} 1112 1113struct linux_getsockopt_args { 1114 int s; 1115 int level; 1116 int optname; 1117 l_uintptr_t optval; 1118 l_uintptr_t optlen; 1119}; 1120 1121static int 1122linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1123{ 1124 struct linux_getsockopt_args linux_args; 1125 struct getsockopt_args /* { 1126 int s; 1127 int level; 1128 int name; 1129 caddr_t val; 1130 int *avalsize; 1131 } */ bsd_args; 1132 int error, name; 1133 1134 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1135 return (error); 1136 1137 bsd_args.s = linux_args.s; 1138 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1139 switch (bsd_args.level) { 1140 case SOL_SOCKET: 1141 name = linux_to_bsd_so_sockopt(linux_args.optname); 1142 break; 1143 case IPPROTO_IP: 1144 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1145 break; 1146 case IPPROTO_TCP: 1147 /* Linux TCP option values match BSD's */ 1148 name = linux_args.optname; 1149 break; 1150 default: 1151 name = -1; 1152 break; 1153 } 1154 if (name == -1) 1155 return (EINVAL); 1156 1157 bsd_args.name = name; 1158 bsd_args.val = PTRIN(linux_args.optval); 1159 bsd_args.avalsize = PTRIN(linux_args.optlen); 1160 return (getsockopt(td, &bsd_args)); 1161} 1162 1163int 1164linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1165{ 1166 void *arg = (void *)(intptr_t)args->args; 1167 1168 switch (args->what) { 1169 case LINUX_SOCKET: 1170 return (linux_socket(td, arg)); 1171 case LINUX_BIND: 1172 return (linux_bind(td, arg)); 1173 case LINUX_CONNECT: 1174 return (linux_connect(td, arg)); 1175 case LINUX_LISTEN: 1176 return (linux_listen(td, arg)); 1177 case LINUX_ACCEPT: 1178 return (linux_accept(td, arg)); 1179 case LINUX_GETSOCKNAME: 1180 return (linux_getsockname(td, arg)); 1181 case LINUX_GETPEERNAME: 1182 return (linux_getpeername(td, arg)); 1183 case LINUX_SOCKETPAIR: 1184 return (linux_socketpair(td, arg)); 1185 case LINUX_SEND: 1186 return (linux_send(td, arg)); 1187 case LINUX_RECV: 1188 return (linux_recv(td, arg)); 1189 case LINUX_SENDTO: 1190 return (linux_sendto(td, arg)); 1191 case LINUX_RECVFROM: 1192 return (linux_recvfrom(td, arg)); 1193 case LINUX_SHUTDOWN: 1194 return (linux_shutdown(td, arg)); 1195 case LINUX_SETSOCKOPT: 1196 return (linux_setsockopt(td, arg)); 1197 case LINUX_GETSOCKOPT: 1198 return (linux_getsockopt(td, arg)); 1199 case LINUX_SENDMSG: 1200 return (linux_sendmsg(td, arg)); 1201 case LINUX_RECVMSG: 1202 return (linux_recvmsg(td, arg)); 1203 } 1204 1205 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1206 return (ENOSYS); 1207} 1208#endif /*!__alpha__*/ 1209