linux_socket.c revision 195699
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 195699 2009-07-14 22:48:30Z rwatson $"); 31 32/* XXX we use functions that might not exist. */ 33#include "opt_compat.h" 34#include "opt_inet6.h" 35 36#include <sys/param.h> 37#include <sys/proc.h> 38#include <sys/systm.h> 39#include <sys/sysproto.h> 40#include <sys/fcntl.h> 41#include <sys/file.h> 42#include <sys/limits.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/mutex.h> 46#include <sys/mbuf.h> 47#include <sys/socket.h> 48#include <sys/socketvar.h> 49#include <sys/syscallsubr.h> 50#include <sys/uio.h> 51#include <sys/syslog.h> 52#include <sys/un.h> 53#include <sys/vimage.h> 54 55#include <net/if.h> 56#include <netinet/in.h> 57#include <netinet/in_systm.h> 58#include <netinet/ip.h> 59#ifdef INET6 60#include <netinet/ip6.h> 61#include <netinet6/ip6_var.h> 62#include <netinet6/in6_var.h> 63#endif 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 kosa = malloc(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\n"); 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 200static int 201bsd_to_linux_domain(int domain) 202{ 203 204 switch (domain) { 205 case AF_UNSPEC: 206 return (LINUX_AF_UNSPEC); 207 case AF_LOCAL: 208 return (LINUX_AF_UNIX); 209 case AF_INET: 210 return (LINUX_AF_INET); 211 case AF_INET6: 212 return (LINUX_AF_INET6); 213 case AF_CCITT: 214 return (LINUX_AF_AX25); 215 case AF_IPX: 216 return (LINUX_AF_IPX); 217 case AF_APPLETALK: 218 return (LINUX_AF_APPLETALK); 219 } 220 return (-1); 221} 222 223static int 224linux_to_bsd_sockopt_level(int level) 225{ 226 227 switch (level) { 228 case LINUX_SOL_SOCKET: 229 return (SOL_SOCKET); 230 } 231 return (level); 232} 233 234static int 235bsd_to_linux_sockopt_level(int level) 236{ 237 238 switch (level) { 239 case SOL_SOCKET: 240 return (LINUX_SOL_SOCKET); 241 } 242 return (level); 243} 244 245static int 246linux_to_bsd_ip_sockopt(int opt) 247{ 248 249 switch (opt) { 250 case LINUX_IP_TOS: 251 return (IP_TOS); 252 case LINUX_IP_TTL: 253 return (IP_TTL); 254 case LINUX_IP_OPTIONS: 255 return (IP_OPTIONS); 256 case LINUX_IP_MULTICAST_IF: 257 return (IP_MULTICAST_IF); 258 case LINUX_IP_MULTICAST_TTL: 259 return (IP_MULTICAST_TTL); 260 case LINUX_IP_MULTICAST_LOOP: 261 return (IP_MULTICAST_LOOP); 262 case LINUX_IP_ADD_MEMBERSHIP: 263 return (IP_ADD_MEMBERSHIP); 264 case LINUX_IP_DROP_MEMBERSHIP: 265 return (IP_DROP_MEMBERSHIP); 266 case LINUX_IP_HDRINCL: 267 return (IP_HDRINCL); 268 } 269 return (-1); 270} 271 272static int 273linux_to_bsd_so_sockopt(int opt) 274{ 275 276 switch (opt) { 277 case LINUX_SO_DEBUG: 278 return (SO_DEBUG); 279 case LINUX_SO_REUSEADDR: 280 return (SO_REUSEADDR); 281 case LINUX_SO_TYPE: 282 return (SO_TYPE); 283 case LINUX_SO_ERROR: 284 return (SO_ERROR); 285 case LINUX_SO_DONTROUTE: 286 return (SO_DONTROUTE); 287 case LINUX_SO_BROADCAST: 288 return (SO_BROADCAST); 289 case LINUX_SO_SNDBUF: 290 return (SO_SNDBUF); 291 case LINUX_SO_RCVBUF: 292 return (SO_RCVBUF); 293 case LINUX_SO_KEEPALIVE: 294 return (SO_KEEPALIVE); 295 case LINUX_SO_OOBINLINE: 296 return (SO_OOBINLINE); 297 case LINUX_SO_LINGER: 298 return (SO_LINGER); 299 case LINUX_SO_PEERCRED: 300 return (LOCAL_PEERCRED); 301 case LINUX_SO_RCVLOWAT: 302 return (SO_RCVLOWAT); 303 case LINUX_SO_SNDLOWAT: 304 return (SO_SNDLOWAT); 305 case LINUX_SO_RCVTIMEO: 306 return (SO_RCVTIMEO); 307 case LINUX_SO_SNDTIMEO: 308 return (SO_SNDTIMEO); 309 case LINUX_SO_TIMESTAMP: 310 return (SO_TIMESTAMP); 311 case LINUX_SO_ACCEPTCONN: 312 return (SO_ACCEPTCONN); 313 } 314 return (-1); 315} 316 317static int 318linux_to_bsd_msg_flags(int flags) 319{ 320 int ret_flags = 0; 321 322 if (flags & LINUX_MSG_OOB) 323 ret_flags |= MSG_OOB; 324 if (flags & LINUX_MSG_PEEK) 325 ret_flags |= MSG_PEEK; 326 if (flags & LINUX_MSG_DONTROUTE) 327 ret_flags |= MSG_DONTROUTE; 328 if (flags & LINUX_MSG_CTRUNC) 329 ret_flags |= MSG_CTRUNC; 330 if (flags & LINUX_MSG_TRUNC) 331 ret_flags |= MSG_TRUNC; 332 if (flags & LINUX_MSG_DONTWAIT) 333 ret_flags |= MSG_DONTWAIT; 334 if (flags & LINUX_MSG_EOR) 335 ret_flags |= MSG_EOR; 336 if (flags & LINUX_MSG_WAITALL) 337 ret_flags |= MSG_WAITALL; 338 if (flags & LINUX_MSG_NOSIGNAL) 339 ret_flags |= MSG_NOSIGNAL; 340#if 0 /* not handled */ 341 if (flags & LINUX_MSG_PROXY) 342 ; 343 if (flags & LINUX_MSG_FIN) 344 ; 345 if (flags & LINUX_MSG_SYN) 346 ; 347 if (flags & LINUX_MSG_CONFIRM) 348 ; 349 if (flags & LINUX_MSG_RST) 350 ; 351 if (flags & LINUX_MSG_ERRQUEUE) 352 ; 353#endif 354 return ret_flags; 355} 356 357/* 358* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the 359* native syscall will fault. Thus, we don't really need to check the 360* return values for these functions. 361*/ 362 363static int 364bsd_to_linux_sockaddr(struct sockaddr *arg) 365{ 366 struct sockaddr sa; 367 size_t sa_len = sizeof(struct sockaddr); 368 int error; 369 370 if ((error = copyin(arg, &sa, sa_len))) 371 return (error); 372 373 *(u_short *)&sa = sa.sa_family; 374 375 error = copyout(&sa, arg, sa_len); 376 377 return (error); 378} 379 380static int 381linux_to_bsd_sockaddr(struct sockaddr *arg, int len) 382{ 383 struct sockaddr sa; 384 size_t sa_len = sizeof(struct sockaddr); 385 int error; 386 387 if ((error = copyin(arg, &sa, sa_len))) 388 return (error); 389 390 sa.sa_family = *(sa_family_t *)&sa; 391 sa.sa_len = len; 392 393 error = copyout(&sa, arg, sa_len); 394 395 return (error); 396} 397 398 399static int 400linux_sa_put(struct osockaddr *osa) 401{ 402 struct osockaddr sa; 403 int error, bdom; 404 405 /* 406 * Only read/write the osockaddr family part, the rest is 407 * not changed. 408 */ 409 error = copyin(osa, &sa, sizeof(sa.sa_family)); 410 if (error) 411 return (error); 412 413 bdom = bsd_to_linux_domain(sa.sa_family); 414 if (bdom == -1) 415 return (EINVAL); 416 417 sa.sa_family = bdom; 418 error = copyout(&sa, osa, sizeof(sa.sa_family)); 419 if (error) 420 return (error); 421 422 return (0); 423} 424 425static int 426linux_to_bsd_cmsg_type(int cmsg_type) 427{ 428 429 switch (cmsg_type) { 430 case LINUX_SCM_RIGHTS: 431 return (SCM_RIGHTS); 432 } 433 return (-1); 434} 435 436static int 437bsd_to_linux_cmsg_type(int cmsg_type) 438{ 439 440 switch (cmsg_type) { 441 case SCM_RIGHTS: 442 return (LINUX_SCM_RIGHTS); 443 } 444 return (-1); 445} 446 447static int 448linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 449{ 450 if (lhdr->msg_controllen > INT_MAX) 451 return (ENOBUFS); 452 453 bhdr->msg_name = PTRIN(lhdr->msg_name); 454 bhdr->msg_namelen = lhdr->msg_namelen; 455 bhdr->msg_iov = PTRIN(lhdr->msg_iov); 456 bhdr->msg_iovlen = lhdr->msg_iovlen; 457 bhdr->msg_control = PTRIN(lhdr->msg_control); 458 bhdr->msg_controllen = lhdr->msg_controllen; 459 bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 460 return (0); 461} 462 463static int 464bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 465{ 466 lhdr->msg_name = PTROUT(bhdr->msg_name); 467 lhdr->msg_namelen = bhdr->msg_namelen; 468 lhdr->msg_iov = PTROUT(bhdr->msg_iov); 469 lhdr->msg_iovlen = bhdr->msg_iovlen; 470 lhdr->msg_control = PTROUT(bhdr->msg_control); 471 lhdr->msg_controllen = bhdr->msg_controllen; 472 /* msg_flags skipped */ 473 return (0); 474} 475 476static int 477linux_set_socket_flags(struct thread *td, int s, int flags) 478{ 479 int error; 480 481 if (flags & LINUX_SOCK_NONBLOCK) { 482 error = kern_fcntl(td, s, F_SETFL, O_NONBLOCK); 483 if (error) 484 return (error); 485 } 486 if (flags & LINUX_SOCK_CLOEXEC) { 487 error = kern_fcntl(td, s, F_SETFD, FD_CLOEXEC); 488 if (error) 489 return (error); 490 } 491 return (0); 492} 493 494static int 495linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 496 struct mbuf *control, enum uio_seg segflg) 497{ 498 struct sockaddr *to; 499 int error; 500 501 if (mp->msg_name != NULL) { 502 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 503 if (error) 504 return (error); 505 mp->msg_name = to; 506 } else 507 to = NULL; 508 509 error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 510 segflg); 511 512 if (to) 513 free(to, M_SONAME); 514 return (error); 515} 516 517/* Return 0 if IP_HDRINCL is set for the given socket. */ 518static int 519linux_check_hdrincl(struct thread *td, int s) 520{ 521 int error, optval, size_val; 522 523 size_val = sizeof(optval); 524 error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 525 &optval, UIO_SYSSPACE, &size_val); 526 if (error) 527 return (error); 528 529 return (optval == 0); 530} 531 532struct linux_sendto_args { 533 int s; 534 l_uintptr_t msg; 535 int len; 536 int flags; 537 l_uintptr_t to; 538 int tolen; 539}; 540 541/* 542 * Updated sendto() when IP_HDRINCL is set: 543 * tweak endian-dependent fields in the IP packet. 544 */ 545static int 546linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 547{ 548/* 549 * linux_ip_copysize defines how many bytes we should copy 550 * from the beginning of the IP packet before we customize it for BSD. 551 * It should include all the fields we modify (ip_len and ip_off). 552 */ 553#define linux_ip_copysize 8 554 555 struct ip *packet; 556 struct msghdr msg; 557 struct iovec aiov[1]; 558 int error; 559 560 /* Check that the packet isn't too big or too small. */ 561 if (linux_args->len < linux_ip_copysize || 562 linux_args->len > IP_MAXPACKET) 563 return (EINVAL); 564 565 packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK); 566 567 /* Make kernel copy of the packet to be sent */ 568 if ((error = copyin(PTRIN(linux_args->msg), packet, 569 linux_args->len))) 570 goto goout; 571 572 /* Convert fields from Linux to BSD raw IP socket format */ 573 packet->ip_len = linux_args->len; 574 packet->ip_off = ntohs(packet->ip_off); 575 576 /* Prepare the msghdr and iovec structures describing the new packet */ 577 msg.msg_name = PTRIN(linux_args->to); 578 msg.msg_namelen = linux_args->tolen; 579 msg.msg_iov = aiov; 580 msg.msg_iovlen = 1; 581 msg.msg_control = NULL; 582 msg.msg_flags = 0; 583 aiov[0].iov_base = (char *)packet; 584 aiov[0].iov_len = linux_args->len; 585 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 586 NULL, UIO_SYSSPACE); 587goout: 588 free(packet, M_TEMP); 589 return (error); 590} 591 592struct linux_socket_args { 593 int domain; 594 int type; 595 int protocol; 596}; 597 598static int 599linux_socket(struct thread *td, struct linux_socket_args *args) 600{ 601 struct socket_args /* { 602 int domain; 603 int type; 604 int protocol; 605 } */ bsd_args; 606 int retval_socket, socket_flags; 607 608 bsd_args.protocol = args->protocol; 609 socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; 610 if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 611 return (EINVAL); 612 bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 613 if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 614 return (EINVAL); 615 bsd_args.domain = linux_to_bsd_domain(args->domain); 616 if (bsd_args.domain == -1) 617 return (EAFNOSUPPORT); 618 619 retval_socket = socket(td, &bsd_args); 620 if (retval_socket) 621 return (retval_socket); 622 623 retval_socket = linux_set_socket_flags(td, td->td_retval[0], 624 socket_flags); 625 if (retval_socket) { 626 (void)kern_close(td, td->td_retval[0]); 627 goto out; 628 } 629 630 if (bsd_args.type == SOCK_RAW 631 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 632 && bsd_args.domain == PF_INET) { 633 /* It's a raw IP socket: set the IP_HDRINCL option. */ 634 int hdrincl; 635 636 hdrincl = 1; 637 /* We ignore any error returned by kern_setsockopt() */ 638 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 639 &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 640 } 641#ifdef INET6 642 /* 643 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 644 * default and some apps depend on this. So, set V6ONLY to 0 645 * for Linux apps if the sysctl value is set to 1. 646 */ 647 if (bsd_args.domain == PF_INET6 648#ifndef KLD_MODULE 649 /* 650 * XXX: Avoid undefined symbol error with an IPv4 only 651 * kernel. 652 */ 653 && V_ip6_v6only 654#endif 655 ) { 656 int v6only; 657 658 v6only = 0; 659 /* We ignore any error returned by setsockopt() */ 660 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 661 &v6only, UIO_SYSSPACE, sizeof(v6only)); 662 } 663#endif 664 665out: 666 return (retval_socket); 667} 668 669struct linux_bind_args { 670 int s; 671 l_uintptr_t name; 672 int namelen; 673}; 674 675static int 676linux_bind(struct thread *td, struct linux_bind_args *args) 677{ 678 struct sockaddr *sa; 679 int error; 680 681 error = linux_getsockaddr(&sa, PTRIN(args->name), 682 args->namelen); 683 if (error) 684 return (error); 685 686 error = kern_bind(td, args->s, sa); 687 free(sa, M_SONAME); 688 if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 689 return (EINVAL); 690 return (error); 691} 692 693struct linux_connect_args { 694 int s; 695 l_uintptr_t name; 696 int namelen; 697}; 698int linux_connect(struct thread *, struct linux_connect_args *); 699 700int 701linux_connect(struct thread *td, struct linux_connect_args *args) 702{ 703 struct socket *so; 704 struct sockaddr *sa; 705 u_int fflag; 706 int error; 707 708 error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), 709 args->namelen); 710 if (error) 711 return (error); 712 713 error = kern_connect(td, args->s, sa); 714 free(sa, M_SONAME); 715 if (error != EISCONN) 716 return (error); 717 718 /* 719 * Linux doesn't return EISCONN the first time it occurs, 720 * when on a non-blocking socket. Instead it returns the 721 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 722 * 723 * XXXRW: Instead of using fgetsock(), check that it is a 724 * socket and use the file descriptor reference instead of 725 * creating a new one. 726 */ 727 error = fgetsock(td, args->s, &so, &fflag); 728 if (error == 0) { 729 error = EISCONN; 730 if (fflag & FNONBLOCK) { 731 SOCK_LOCK(so); 732 if (so->so_emuldata == 0) 733 error = so->so_error; 734 so->so_emuldata = (void *)1; 735 SOCK_UNLOCK(so); 736 } 737 fputsock(so); 738 } 739 return (error); 740} 741 742struct linux_listen_args { 743 int s; 744 int backlog; 745}; 746 747static int 748linux_listen(struct thread *td, struct linux_listen_args *args) 749{ 750 struct listen_args /* { 751 int s; 752 int backlog; 753 } */ bsd_args; 754 755 bsd_args.s = args->s; 756 bsd_args.backlog = args->backlog; 757 return (listen(td, &bsd_args)); 758} 759 760static int 761linux_accept_common(struct thread *td, int s, l_uintptr_t addr, 762 l_uintptr_t namelen, int flags) 763{ 764 struct accept_args /* { 765 int s; 766 struct sockaddr * __restrict name; 767 socklen_t * __restrict anamelen; 768 } */ bsd_args; 769 int error; 770 771 if (flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 772 return (EINVAL); 773 774 bsd_args.s = s; 775 /* XXX: */ 776 bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr); 777 bsd_args.anamelen = PTRIN(namelen);/* XXX */ 778 error = accept(td, &bsd_args); 779 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); 780 if (error) { 781 if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 782 return (EINVAL); 783 return (error); 784 } 785 786 /* 787 * linux appears not to copy flags from the parent socket to the 788 * accepted one, so we must clear the flags in the new descriptor 789 * and apply the requested flags. 790 */ 791 error = kern_fcntl(td, td->td_retval[0], F_SETFL, 0); 792 if (error) 793 goto out; 794 error = linux_set_socket_flags(td, td->td_retval[0], flags); 795 if (error) 796 goto out; 797 if (addr) 798 error = linux_sa_put(PTRIN(addr)); 799 800out: 801 if (error) { 802 (void)kern_close(td, td->td_retval[0]); 803 td->td_retval[0] = 0; 804 } 805 return (error); 806} 807 808struct linux_accept_args { 809 int s; 810 l_uintptr_t addr; 811 l_uintptr_t namelen; 812}; 813 814static int 815linux_accept(struct thread *td, struct linux_accept_args *args) 816{ 817 818 return (linux_accept_common(td, args->s, args->addr, 819 args->namelen, 0)); 820} 821 822struct linux_accept4_args { 823 int s; 824 l_uintptr_t addr; 825 l_uintptr_t namelen; 826 int flags; 827}; 828 829static int 830linux_accept4(struct thread *td, struct linux_accept4_args *args) 831{ 832 833 return (linux_accept_common(td, args->s, args->addr, 834 args->namelen, args->flags)); 835} 836 837struct linux_getsockname_args { 838 int s; 839 l_uintptr_t addr; 840 l_uintptr_t namelen; 841}; 842 843static int 844linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 845{ 846 struct getsockname_args /* { 847 int fdes; 848 struct sockaddr * __restrict asa; 849 socklen_t * __restrict alen; 850 } */ bsd_args; 851 int error; 852 853 bsd_args.fdes = args->s; 854 /* XXX: */ 855 bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); 856 bsd_args.alen = PTRIN(args->namelen); /* XXX */ 857 error = getsockname(td, &bsd_args); 858 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 859 if (error) 860 return (error); 861 error = linux_sa_put(PTRIN(args->addr)); 862 if (error) 863 return (error); 864 return (0); 865} 866 867struct linux_getpeername_args { 868 int s; 869 l_uintptr_t addr; 870 l_uintptr_t namelen; 871}; 872 873static int 874linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 875{ 876 struct getpeername_args /* { 877 int fdes; 878 caddr_t asa; 879 int *alen; 880 } */ bsd_args; 881 int error; 882 883 bsd_args.fdes = args->s; 884 bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); 885 bsd_args.alen = (int *)PTRIN(args->namelen); 886 error = getpeername(td, &bsd_args); 887 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 888 if (error) 889 return (error); 890 error = linux_sa_put(PTRIN(args->addr)); 891 if (error) 892 return (error); 893 return (0); 894} 895 896struct linux_socketpair_args { 897 int domain; 898 int type; 899 int protocol; 900 l_uintptr_t rsv; 901}; 902 903static int 904linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 905{ 906 struct socketpair_args /* { 907 int domain; 908 int type; 909 int protocol; 910 int *rsv; 911 } */ bsd_args; 912 int error, socket_flags; 913 int sv[2]; 914 915 bsd_args.domain = linux_to_bsd_domain(args->domain); 916 if (bsd_args.domain != PF_LOCAL) 917 return (EAFNOSUPPORT); 918 919 socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; 920 if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 921 return (EINVAL); 922 bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 923 if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 924 return (EINVAL); 925 926 if (args->protocol != 0 && args->protocol != PF_UNIX) 927 928 /* 929 * Use of PF_UNIX as protocol argument is not right, 930 * but Linux does it. 931 * Do not map PF_UNIX as its Linux value is identical 932 * to FreeBSD one. 933 */ 934 return (EPROTONOSUPPORT); 935 else 936 bsd_args.protocol = 0; 937 bsd_args.rsv = (int *)PTRIN(args->rsv); 938 error = kern_socketpair(td, bsd_args.domain, bsd_args.type, 939 bsd_args.protocol, sv); 940 if (error) 941 return (error); 942 error = linux_set_socket_flags(td, sv[0], socket_flags); 943 if (error) 944 goto out; 945 error = linux_set_socket_flags(td, sv[1], socket_flags); 946 if (error) 947 goto out; 948 949 error = copyout(sv, bsd_args.rsv, 2 * sizeof(int)); 950 951out: 952 if (error) { 953 (void)kern_close(td, sv[0]); 954 (void)kern_close(td, sv[1]); 955 } 956 return (error); 957} 958 959struct linux_send_args { 960 int s; 961 l_uintptr_t msg; 962 int len; 963 int flags; 964}; 965 966static int 967linux_send(struct thread *td, struct linux_send_args *args) 968{ 969 struct sendto_args /* { 970 int s; 971 caddr_t buf; 972 int len; 973 int flags; 974 caddr_t to; 975 int tolen; 976 } */ bsd_args; 977 978 bsd_args.s = args->s; 979 bsd_args.buf = (caddr_t)PTRIN(args->msg); 980 bsd_args.len = args->len; 981 bsd_args.flags = args->flags; 982 bsd_args.to = NULL; 983 bsd_args.tolen = 0; 984 return sendto(td, &bsd_args); 985} 986 987struct linux_recv_args { 988 int s; 989 l_uintptr_t msg; 990 int len; 991 int flags; 992}; 993 994static int 995linux_recv(struct thread *td, struct linux_recv_args *args) 996{ 997 struct recvfrom_args /* { 998 int s; 999 caddr_t buf; 1000 int len; 1001 int flags; 1002 struct sockaddr *from; 1003 socklen_t fromlenaddr; 1004 } */ bsd_args; 1005 1006 bsd_args.s = args->s; 1007 bsd_args.buf = (caddr_t)PTRIN(args->msg); 1008 bsd_args.len = args->len; 1009 bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 1010 bsd_args.from = NULL; 1011 bsd_args.fromlenaddr = 0; 1012 return (recvfrom(td, &bsd_args)); 1013} 1014 1015static int 1016linux_sendto(struct thread *td, struct linux_sendto_args *args) 1017{ 1018 struct msghdr msg; 1019 struct iovec aiov; 1020 int error; 1021 1022 if (linux_check_hdrincl(td, args->s) == 0) 1023 /* IP_HDRINCL set, tweak the packet before sending */ 1024 return (linux_sendto_hdrincl(td, args)); 1025 1026 msg.msg_name = PTRIN(args->to); 1027 msg.msg_namelen = args->tolen; 1028 msg.msg_iov = &aiov; 1029 msg.msg_iovlen = 1; 1030 msg.msg_control = NULL; 1031 msg.msg_flags = 0; 1032 aiov.iov_base = PTRIN(args->msg); 1033 aiov.iov_len = args->len; 1034 error = linux_sendit(td, args->s, &msg, args->flags, NULL, 1035 UIO_USERSPACE); 1036 return (error); 1037} 1038 1039struct linux_recvfrom_args { 1040 int s; 1041 l_uintptr_t buf; 1042 int len; 1043 int flags; 1044 l_uintptr_t from; 1045 l_uintptr_t fromlen; 1046}; 1047 1048static int 1049linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 1050{ 1051 struct recvfrom_args /* { 1052 int s; 1053 caddr_t buf; 1054 size_t len; 1055 int flags; 1056 struct sockaddr * __restrict from; 1057 socklen_t * __restrict fromlenaddr; 1058 } */ bsd_args; 1059 size_t len; 1060 int error; 1061 1062 if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t)))) 1063 return (error); 1064 1065 bsd_args.s = args->s; 1066 bsd_args.buf = PTRIN(args->buf); 1067 bsd_args.len = args->len; 1068 bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 1069 /* XXX: */ 1070 bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from); 1071 bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */ 1072 1073 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len); 1074 error = recvfrom(td, &bsd_args); 1075 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from); 1076 1077 if (error) 1078 return (error); 1079 if (args->from) { 1080 error = linux_sa_put((struct osockaddr *) 1081 PTRIN(args->from)); 1082 if (error) 1083 return (error); 1084 } 1085 return (0); 1086} 1087 1088struct linux_sendmsg_args { 1089 int s; 1090 l_uintptr_t msg; 1091 int flags; 1092}; 1093 1094static int 1095linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1096{ 1097 struct cmsghdr *cmsg; 1098 struct mbuf *control; 1099 struct msghdr msg; 1100 struct l_cmsghdr linux_cmsg; 1101 struct l_cmsghdr *ptr_cmsg; 1102 struct l_msghdr linux_msg; 1103 struct iovec *iov; 1104 socklen_t datalen; 1105 void *data; 1106 int error; 1107 1108 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1109 if (error) 1110 return (error); 1111 error = linux_to_bsd_msghdr(&msg, &linux_msg); 1112 if (error) 1113 return (error); 1114 1115 /* 1116 * Some Linux applications (ping) define a non-NULL control data 1117 * pointer, but a msg_controllen of 0, which is not allowed in the 1118 * FreeBSD system call interface. NULL the msg_control pointer in 1119 * order to handle this case. This should be checked, but allows the 1120 * Linux ping to work. 1121 */ 1122 if (msg.msg_control != NULL && msg.msg_controllen == 0) 1123 msg.msg_control = NULL; 1124 1125#ifdef COMPAT_LINUX32 1126 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1127 &iov, EMSGSIZE); 1128#else 1129 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1130#endif 1131 if (error) 1132 return (error); 1133 1134 if (msg.msg_control != NULL) { 1135 error = ENOBUFS; 1136 cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1137 control = m_get(M_WAIT, MT_CONTROL); 1138 if (control == NULL) 1139 goto bad; 1140 ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg); 1141 1142 do { 1143 error = copyin(ptr_cmsg, &linux_cmsg, 1144 sizeof(struct l_cmsghdr)); 1145 if (error) 1146 goto bad; 1147 1148 error = EINVAL; 1149 if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) 1150 goto bad; 1151 1152 /* 1153 * Now we support only SCM_RIGHTS, so return EINVAL 1154 * in any other cmsg_type 1155 */ 1156 if ((cmsg->cmsg_type = 1157 linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1) 1158 goto bad; 1159 cmsg->cmsg_level = 1160 linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1161 1162 datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1163 cmsg->cmsg_len = CMSG_LEN(datalen); 1164 data = LINUX_CMSG_DATA(ptr_cmsg); 1165 1166 error = ENOBUFS; 1167 if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg)) 1168 goto bad; 1169 if (!m_append(control, datalen, (c_caddr_t) data)) 1170 goto bad; 1171 } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg))); 1172 } else { 1173 control = NULL; 1174 cmsg = NULL; 1175 } 1176 1177 msg.msg_iov = iov; 1178 msg.msg_flags = 0; 1179 error = linux_sendit(td, args->s, &msg, args->flags, control, 1180 UIO_USERSPACE); 1181 1182bad: 1183 free(iov, M_IOV); 1184 if (cmsg) 1185 free(cmsg, M_TEMP); 1186 return (error); 1187} 1188 1189struct linux_recvmsg_args { 1190 int s; 1191 l_uintptr_t msg; 1192 int flags; 1193}; 1194 1195static int 1196linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1197{ 1198 struct cmsghdr *cm; 1199 struct msghdr msg; 1200 struct l_cmsghdr *linux_cmsg = NULL; 1201 socklen_t datalen, outlen, clen; 1202 struct l_msghdr linux_msg; 1203 struct iovec *iov, *uiov; 1204 struct mbuf *control = NULL; 1205 struct mbuf **controlp; 1206 caddr_t outbuf; 1207 void *data; 1208 int error, i, fd, fds, *fdp; 1209 1210 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1211 if (error) 1212 return (error); 1213 1214 error = linux_to_bsd_msghdr(&msg, &linux_msg); 1215 if (error) 1216 return (error); 1217 1218#ifdef COMPAT_LINUX32 1219 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1220 &iov, EMSGSIZE); 1221#else 1222 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1223#endif 1224 if (error) 1225 return (error); 1226 1227 if (msg.msg_name) { 1228 error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, 1229 msg.msg_namelen); 1230 if (error) 1231 goto bad; 1232 } 1233 1234 uiov = msg.msg_iov; 1235 msg.msg_iov = iov; 1236 controlp = (msg.msg_control != NULL) ? &control : NULL; 1237 error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); 1238 msg.msg_iov = uiov; 1239 if (error) 1240 goto bad; 1241 1242 error = bsd_to_linux_msghdr(&msg, &linux_msg); 1243 if (error) 1244 goto bad; 1245 1246 if (linux_msg.msg_name) { 1247 error = bsd_to_linux_sockaddr((struct sockaddr *) 1248 PTRIN(linux_msg.msg_name)); 1249 if (error) 1250 goto bad; 1251 } 1252 if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { 1253 error = linux_sa_put(PTRIN(linux_msg.msg_name)); 1254 if (error) 1255 goto bad; 1256 } 1257 1258 if (control) { 1259 1260 linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1261 outbuf = PTRIN(linux_msg.msg_control); 1262 cm = mtod(control, struct cmsghdr *); 1263 outlen = 0; 1264 clen = control->m_len; 1265 1266 while (cm != NULL) { 1267 1268 if ((linux_cmsg->cmsg_type = 1269 bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1) 1270 { 1271 error = EINVAL; 1272 goto bad; 1273 } 1274 data = CMSG_DATA(cm); 1275 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1276 1277 switch (linux_cmsg->cmsg_type) 1278 { 1279 case LINUX_SCM_RIGHTS: 1280 if (outlen + LINUX_CMSG_LEN(datalen) > 1281 linux_msg.msg_controllen) { 1282 if (outlen == 0) { 1283 error = EMSGSIZE; 1284 goto bad; 1285 } else { 1286 linux_msg.msg_flags |= 1287 LINUX_MSG_CTRUNC; 1288 goto out; 1289 } 1290 } 1291 if (args->flags & LINUX_MSG_CMSG_CLOEXEC) { 1292 fds = datalen / sizeof(int); 1293 fdp = data; 1294 for (i = 0; i < fds; i++) { 1295 fd = *fdp++; 1296 (void)kern_fcntl(td, fd, 1297 F_SETFD, FD_CLOEXEC); 1298 } 1299 } 1300 break; 1301 } 1302 1303 linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 1304 linux_cmsg->cmsg_level = 1305 bsd_to_linux_sockopt_level(cm->cmsg_level); 1306 1307 error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1308 if (error) 1309 goto bad; 1310 outbuf += L_CMSG_HDRSZ; 1311 1312 error = copyout(data, outbuf, datalen); 1313 if (error) 1314 goto bad; 1315 1316 outbuf += LINUX_CMSG_ALIGN(datalen); 1317 outlen += LINUX_CMSG_LEN(datalen); 1318 linux_msg.msg_controllen = outlen; 1319 1320 if (CMSG_SPACE(datalen) < clen) { 1321 clen -= CMSG_SPACE(datalen); 1322 cm = (struct cmsghdr *) 1323 ((caddr_t)cm + CMSG_SPACE(datalen)); 1324 } else 1325 cm = NULL; 1326 } 1327 } 1328 1329out: 1330 error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); 1331 1332bad: 1333 free(iov, M_IOV); 1334 if (control != NULL) 1335 m_freem(control); 1336 if (linux_cmsg != NULL) 1337 free(linux_cmsg, M_TEMP); 1338 1339 return (error); 1340} 1341 1342struct linux_shutdown_args { 1343 int s; 1344 int how; 1345}; 1346 1347static int 1348linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1349{ 1350 struct shutdown_args /* { 1351 int s; 1352 int how; 1353 } */ bsd_args; 1354 1355 bsd_args.s = args->s; 1356 bsd_args.how = args->how; 1357 return (shutdown(td, &bsd_args)); 1358} 1359 1360struct linux_setsockopt_args { 1361 int s; 1362 int level; 1363 int optname; 1364 l_uintptr_t optval; 1365 int optlen; 1366}; 1367 1368static int 1369linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1370{ 1371 struct setsockopt_args /* { 1372 int s; 1373 int level; 1374 int name; 1375 caddr_t val; 1376 int valsize; 1377 } */ bsd_args; 1378 l_timeval linux_tv; 1379 struct timeval tv; 1380 int error, name; 1381 1382 bsd_args.s = args->s; 1383 bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1384 switch (bsd_args.level) { 1385 case SOL_SOCKET: 1386 name = linux_to_bsd_so_sockopt(args->optname); 1387 switch (name) { 1388 case SO_RCVTIMEO: 1389 /* FALLTHROUGH */ 1390 case SO_SNDTIMEO: 1391 error = copyin(PTRIN(args->optval), &linux_tv, 1392 sizeof(linux_tv)); 1393 if (error) 1394 return (error); 1395 tv.tv_sec = linux_tv.tv_sec; 1396 tv.tv_usec = linux_tv.tv_usec; 1397 return (kern_setsockopt(td, args->s, bsd_args.level, 1398 name, &tv, UIO_SYSSPACE, sizeof(tv))); 1399 /* NOTREACHED */ 1400 break; 1401 default: 1402 break; 1403 } 1404 break; 1405 case IPPROTO_IP: 1406 name = linux_to_bsd_ip_sockopt(args->optname); 1407 break; 1408 case IPPROTO_TCP: 1409 /* Linux TCP option values match BSD's */ 1410 name = args->optname; 1411 break; 1412 default: 1413 name = -1; 1414 break; 1415 } 1416 if (name == -1) 1417 return (ENOPROTOOPT); 1418 1419 bsd_args.name = name; 1420 bsd_args.val = PTRIN(args->optval); 1421 bsd_args.valsize = args->optlen; 1422 1423 if (name == IPV6_NEXTHOP) { 1424 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, 1425 bsd_args.valsize); 1426 error = setsockopt(td, &bsd_args); 1427 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1428 } else 1429 error = setsockopt(td, &bsd_args); 1430 1431 return (error); 1432} 1433 1434struct linux_getsockopt_args { 1435 int s; 1436 int level; 1437 int optname; 1438 l_uintptr_t optval; 1439 l_uintptr_t optlen; 1440}; 1441 1442static int 1443linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1444{ 1445 struct getsockopt_args /* { 1446 int s; 1447 int level; 1448 int name; 1449 caddr_t val; 1450 int *avalsize; 1451 } */ bsd_args; 1452 l_timeval linux_tv; 1453 struct timeval tv; 1454 socklen_t tv_len, xulen; 1455 struct xucred xu; 1456 struct l_ucred lxu; 1457 int error, name; 1458 1459 bsd_args.s = args->s; 1460 bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1461 switch (bsd_args.level) { 1462 case SOL_SOCKET: 1463 name = linux_to_bsd_so_sockopt(args->optname); 1464 switch (name) { 1465 case SO_RCVTIMEO: 1466 /* FALLTHROUGH */ 1467 case SO_SNDTIMEO: 1468 tv_len = sizeof(tv); 1469 error = kern_getsockopt(td, args->s, bsd_args.level, 1470 name, &tv, UIO_SYSSPACE, &tv_len); 1471 if (error) 1472 return (error); 1473 linux_tv.tv_sec = tv.tv_sec; 1474 linux_tv.tv_usec = tv.tv_usec; 1475 return (copyout(&linux_tv, PTRIN(args->optval), 1476 sizeof(linux_tv))); 1477 /* NOTREACHED */ 1478 break; 1479 case LOCAL_PEERCRED: 1480 if (args->optlen != sizeof(lxu)) 1481 return (EINVAL); 1482 xulen = sizeof(xu); 1483 error = kern_getsockopt(td, args->s, bsd_args.level, 1484 name, &xu, UIO_SYSSPACE, &xulen); 1485 if (error) 1486 return (error); 1487 /* 1488 * XXX Use 0 for pid as the FreeBSD does not cache peer pid. 1489 */ 1490 lxu.pid = 0; 1491 lxu.uid = xu.cr_uid; 1492 lxu.gid = xu.cr_gid; 1493 return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1494 /* NOTREACHED */ 1495 break; 1496 default: 1497 break; 1498 } 1499 break; 1500 case IPPROTO_IP: 1501 name = linux_to_bsd_ip_sockopt(args->optname); 1502 break; 1503 case IPPROTO_TCP: 1504 /* Linux TCP option values match BSD's */ 1505 name = args->optname; 1506 break; 1507 default: 1508 name = -1; 1509 break; 1510 } 1511 if (name == -1) 1512 return (EINVAL); 1513 1514 bsd_args.name = name; 1515 bsd_args.val = PTRIN(args->optval); 1516 bsd_args.avalsize = PTRIN(args->optlen); 1517 1518 if (name == IPV6_NEXTHOP) { 1519 error = getsockopt(td, &bsd_args); 1520 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1521 } else 1522 error = getsockopt(td, &bsd_args); 1523 1524 return (error); 1525} 1526 1527/* Argument list sizes for linux_socketcall */ 1528 1529#define LINUX_AL(x) ((x) * sizeof(l_ulong)) 1530 1531static const unsigned char lxs_args[] = { 1532 LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, 1533 LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, 1534 LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, 1535 LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, 1536 LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, 1537 LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, 1538 LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, 1539 LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, 1540 LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */, 1541 LINUX_AL(4) /* accept4 */ 1542}; 1543 1544#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 1545 1546int 1547linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1548{ 1549 l_ulong a[6]; 1550 void *arg; 1551 int error; 1552 1553 if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) 1554 return (EINVAL); 1555 error = copyin(PTRIN(args->args), a, lxs_args[args->what]); 1556 if (error) 1557 return (error); 1558 1559 arg = a; 1560 switch (args->what) { 1561 case LINUX_SOCKET: 1562 return (linux_socket(td, arg)); 1563 case LINUX_BIND: 1564 return (linux_bind(td, arg)); 1565 case LINUX_CONNECT: 1566 return (linux_connect(td, arg)); 1567 case LINUX_LISTEN: 1568 return (linux_listen(td, arg)); 1569 case LINUX_ACCEPT: 1570 return (linux_accept(td, arg)); 1571 case LINUX_GETSOCKNAME: 1572 return (linux_getsockname(td, arg)); 1573 case LINUX_GETPEERNAME: 1574 return (linux_getpeername(td, arg)); 1575 case LINUX_SOCKETPAIR: 1576 return (linux_socketpair(td, arg)); 1577 case LINUX_SEND: 1578 return (linux_send(td, arg)); 1579 case LINUX_RECV: 1580 return (linux_recv(td, arg)); 1581 case LINUX_SENDTO: 1582 return (linux_sendto(td, arg)); 1583 case LINUX_RECVFROM: 1584 return (linux_recvfrom(td, arg)); 1585 case LINUX_SHUTDOWN: 1586 return (linux_shutdown(td, arg)); 1587 case LINUX_SETSOCKOPT: 1588 return (linux_setsockopt(td, arg)); 1589 case LINUX_GETSOCKOPT: 1590 return (linux_getsockopt(td, arg)); 1591 case LINUX_SENDMSG: 1592 return (linux_sendmsg(td, arg)); 1593 case LINUX_RECVMSG: 1594 return (linux_recvmsg(td, arg)); 1595 case LINUX_ACCEPT4: 1596 return (linux_accept4(td, arg)); 1597 } 1598 1599 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1600 return (ENOSYS); 1601} 1602