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