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