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