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