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