linux_socket.c revision 131897
1/*- 2 * Copyright (c) 1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: head/sys/compat/linux/linux_socket.c 131897 2004-07-10 15:42:16Z phk $"); 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 68static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *, 69 struct malloc_type *); 70static 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 */ 76static int 77linux_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 */ 88static int 89do_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 165out: 166 FREE(kosa, mtype); 167 return (error); 168} 169 170static int 171linux_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__ 194static int 195bsd_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 217static int 218linux_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 228static int 229bsd_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 239static int 240linux_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 266static int 267linux_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 297static int 298linux_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 337static int 338linux_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 363static int 364linux_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 397bad: 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. */ 404static int 405linux_check_hdrincl(struct thread *td, caddr_t *sg, int s) 406{ 407 struct getsockopt_args /* { 408 int s; 409 int level; 410 int name; 411 void * __restrict val; 412 socklen_t * __restrict avalsize; 413 } */ bsd_args; 414 void * __restrict val; 415 socklen_t * __restrict valsize; 416 int error, optval, size_val; 417 418 val = stackgap_alloc(sg, sizeof(size_val)); 419 valsize = stackgap_alloc(sg, sizeof(socklen_t)); 420 421 size_val = sizeof(val); 422 if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 423 return (error); 424 425 bsd_args.s = s; 426 bsd_args.level = IPPROTO_IP; 427 bsd_args.name = IP_HDRINCL; 428 bsd_args.val = val; 429 bsd_args.avalsize = valsize; 430 if ((error = getsockopt(td, &bsd_args))) 431 return (error); 432 433 if ((error = copyin(val, &optval, sizeof(optval)))) 434 return (error); 435 436 return (optval == 0); 437} 438 439struct linux_sendto_args { 440 int s; 441 void *msg; 442 int len; 443 int flags; 444 caddr_t to; 445 int tolen; 446}; 447 448/* 449 * Updated sendto() when IP_HDRINCL is set: 450 * tweak endian-dependent fields in the IP packet. 451 */ 452static int 453linux_sendto_hdrincl(struct thread *td, caddr_t *sg, struct linux_sendto_args *linux_args) 454{ 455/* 456 * linux_ip_copysize defines how many bytes we should copy 457 * from the beginning of the IP packet before we customize it for BSD. 458 * It should include all the fields we modify (ip_len and ip_off) 459 * and be as small as possible to minimize copying overhead. 460 */ 461#define linux_ip_copysize 8 462 463 struct ip *packet; 464 struct msghdr msg; 465 struct iovec aiov[2]; 466 int error; 467 468 /* Check the packet isn't too small before we mess with it */ 469 if (linux_args->len < linux_ip_copysize) 470 return (EINVAL); 471 472 /* 473 * Tweaking the user buffer in place would be bad manners. 474 * We create a corrected IP header with just the needed length, 475 * then use an iovec to glue it to the rest of the user packet 476 * when calling sendit(). 477 */ 478 packet = (struct ip *)stackgap_alloc(sg, linux_ip_copysize); 479 480 /* Make a copy of the beginning of the packet to be sent */ 481 if ((error = copyin(linux_args->msg, packet, linux_ip_copysize))) 482 return (error); 483 484 /* Convert fields from Linux to BSD raw IP socket format */ 485 packet->ip_len = linux_args->len; 486 packet->ip_off = ntohs(packet->ip_off); 487 488 /* Prepare the msghdr and iovec structures describing the new packet */ 489 msg.msg_name = linux_args->to; 490 msg.msg_namelen = linux_args->tolen; 491 msg.msg_iov = aiov; 492 msg.msg_iovlen = 2; 493 msg.msg_control = NULL; 494 msg.msg_flags = 0; 495 aiov[0].iov_base = (char *)packet; 496 aiov[0].iov_len = linux_ip_copysize; 497 aiov[1].iov_base = (char *)(linux_args->msg) + linux_ip_copysize; 498 aiov[1].iov_len = linux_args->len - linux_ip_copysize; 499 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags); 500 return (error); 501} 502 503struct linux_socket_args { 504 int domain; 505 int type; 506 int protocol; 507}; 508 509static int 510linux_socket(struct thread *td, struct linux_socket_args *args) 511{ 512 struct linux_socket_args linux_args; 513 struct socket_args /* { 514 int domain; 515 int type; 516 int protocol; 517 } */ bsd_args; 518 struct setsockopt_args /* { 519 int s; 520 int level; 521 int name; 522 caddr_t val; 523 int valsize; 524 } */ bsd_setsockopt_args; 525 int error; 526 int retval_socket; 527 528 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 529 return (error); 530 531 bsd_args.protocol = linux_args.protocol; 532 bsd_args.type = linux_args.type; 533 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 534 if (bsd_args.domain == -1) 535 return (EINVAL); 536 537 retval_socket = socket(td, &bsd_args); 538 if (bsd_args.type == SOCK_RAW 539 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 540 && bsd_args.domain == AF_INET 541 && retval_socket >= 0) { 542 /* It's a raw IP socket: set the IP_HDRINCL option. */ 543 caddr_t sg; 544 int *hdrincl; 545 546 sg = stackgap_init(); 547 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 548 *hdrincl = 1; 549 bsd_setsockopt_args.s = td->td_retval[0]; 550 bsd_setsockopt_args.level = IPPROTO_IP; 551 bsd_setsockopt_args.name = IP_HDRINCL; 552 bsd_setsockopt_args.val = (caddr_t)hdrincl; 553 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 554 /* We ignore any error returned by setsockopt() */ 555 setsockopt(td, &bsd_setsockopt_args); 556 /* Copy back the return value from socket() */ 557 td->td_retval[0] = bsd_setsockopt_args.s; 558 } 559#ifdef INET6 560 /* 561 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 562 * default and some apps depend on this. So, set V6ONLY to 0 563 * for Linux apps if the sysctl value is set to 1. 564 */ 565 if (bsd_args.domain == PF_INET6 && retval_socket >= 0 566#ifndef KLD_MODULE 567 /* 568 * XXX: Avoid undefined symbol error with an IPv4 only 569 * kernel. 570 */ 571 && ip6_v6only 572#endif 573 ) { 574 caddr_t sg; 575 int *v6only; 576 577 sg = stackgap_init(); 578 v6only = (int *)stackgap_alloc(&sg, sizeof(*v6only)); 579 *v6only = 0; 580 bsd_setsockopt_args.s = td->td_retval[0]; 581 bsd_setsockopt_args.level = IPPROTO_IPV6; 582 bsd_setsockopt_args.name = IPV6_V6ONLY; 583 bsd_setsockopt_args.val = (caddr_t)v6only; 584 bsd_setsockopt_args.valsize = sizeof(*v6only); 585 /* We ignore any error returned by setsockopt() */ 586 setsockopt(td, &bsd_setsockopt_args); 587 /* Copy back the return value from socket() */ 588 td->td_retval[0] = bsd_setsockopt_args.s; 589 } 590#endif 591 592 return (retval_socket); 593} 594 595struct linux_bind_args { 596 int s; 597 struct osockaddr *name; 598 int namelen; 599}; 600 601static int 602linux_bind(struct thread *td, struct linux_bind_args *args) 603{ 604 struct linux_bind_args linux_args; 605 struct sockaddr *sa; 606 int error; 607 608 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 609 return (error); 610 611 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen); 612 if (error) 613 return (error); 614 615 return (kern_bind(td, linux_args.s, sa)); 616} 617 618struct linux_connect_args { 619 int s; 620 struct osockaddr * name; 621 int namelen; 622}; 623int linux_connect(struct thread *, struct linux_connect_args *); 624#endif /* !__alpha__*/ 625 626int 627linux_connect(struct thread *td, struct linux_connect_args *args) 628{ 629 struct linux_connect_args linux_args; 630 struct socket *so; 631 struct sockaddr *sa; 632 u_int fflag; 633 int error; 634 635#ifdef __alpha__ 636 bcopy(args, &linux_args, sizeof(linux_args)); 637#else 638 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 639 return (error); 640#endif /* __alpha__ */ 641 642 error = linux_getsockaddr(&sa, (struct osockaddr *)linux_args.name, 643 linux_args.namelen); 644 if (error) 645 return (error); 646 647 error = kern_connect(td, linux_args.s, sa); 648 if (error != EISCONN) 649 return (error); 650 651 /* 652 * Linux doesn't return EISCONN the first time it occurs, 653 * when on a non-blocking socket. Instead it returns the 654 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 655 */ 656 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 657 return(error); 658 error = EISCONN; 659 if (fflag & FNONBLOCK) { 660 if (so->so_emuldata == 0) 661 error = so->so_error; 662 so->so_emuldata = (void *)1; 663 } 664 fputsock(so); 665 return (error); 666} 667 668#ifndef __alpha__ 669 670struct linux_listen_args { 671 int s; 672 int backlog; 673}; 674 675static int 676linux_listen(struct thread *td, struct linux_listen_args *args) 677{ 678 struct linux_listen_args linux_args; 679 struct listen_args /* { 680 int s; 681 int backlog; 682 } */ bsd_args; 683 int error; 684 685 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 686 return (error); 687 688 bsd_args.s = linux_args.s; 689 bsd_args.backlog = linux_args.backlog; 690 return (listen(td, &bsd_args)); 691} 692 693struct linux_accept_args { 694 int s; 695 struct osockaddr *addr; 696 int *namelen; 697}; 698 699static int 700linux_accept(struct thread *td, struct linux_accept_args *args) 701{ 702 struct linux_accept_args linux_args; 703 struct accept_args /* { 704 int s; 705 struct sockaddr * __restrict name; 706 socklen_t * __restrict anamelen; 707 } */ bsd_args; 708 struct close_args /* { 709 int fd; 710 } */ c_args; 711 struct fcntl_args /* { 712 int fd; 713 int cmd; 714 long arg; 715 } */ f_args; 716 int error; 717 718 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 719 return (error); 720 721 bsd_args.s = linux_args.s; 722 /* XXX: */ 723 bsd_args.name = (struct sockaddr * __restrict)linux_args.addr; 724 bsd_args.anamelen = linux_args.namelen; /* XXX */ 725 error = oaccept(td, &bsd_args); 726 if (error) 727 return (error); 728 if (linux_args.addr) { 729 error = linux_sa_put(linux_args.addr); 730 if (error) { 731 c_args.fd = td->td_retval[0]; 732 (void)close(td, &c_args); 733 return (error); 734 } 735 } 736 737 /* 738 * linux appears not to copy flags from the parent socket to the 739 * accepted one, so we must clear the flags in the new descriptor. 740 * Ignore any errors, because we already have an open fd. 741 */ 742 f_args.fd = td->td_retval[0]; 743 f_args.cmd = F_SETFL; 744 f_args.arg = 0; 745 (void)fcntl(td, &f_args); 746 td->td_retval[0] = f_args.fd; 747 return (0); 748} 749 750struct linux_getsockname_args { 751 int s; 752 struct osockaddr *addr; 753 int *namelen; 754}; 755 756static int 757linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 758{ 759 struct linux_getsockname_args linux_args; 760 struct getsockname_args /* { 761 int fdes; 762 struct sockaddr * __restrict asa; 763 socklen_t * __restrict alen; 764 } */ bsd_args; 765 int error; 766 767 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 768 return (error); 769 770 bsd_args.fdes = linux_args.s; 771 /* XXX: */ 772 bsd_args.asa = (struct sockaddr * __restrict)linux_args.addr; 773 bsd_args.alen = linux_args.namelen; /* XXX */ 774 error = ogetsockname(td, &bsd_args); 775 if (error) 776 return (error); 777 error = linux_sa_put(linux_args.addr); 778 if (error) 779 return (error); 780 return (0); 781} 782 783struct linux_getpeername_args { 784 int s; 785 struct osockaddr *addr; 786 int *namelen; 787}; 788 789static int 790linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 791{ 792 struct linux_getpeername_args linux_args; 793 struct ogetpeername_args /* { 794 int fdes; 795 caddr_t asa; 796 int *alen; 797 } */ bsd_args; 798 int error; 799 800 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 801 return (error); 802 803 bsd_args.fdes = linux_args.s; 804 bsd_args.asa = (caddr_t) linux_args.addr; 805 bsd_args.alen = linux_args.namelen; 806 error = ogetpeername(td, &bsd_args); 807 if (error) 808 return (error); 809 error = linux_sa_put(linux_args.addr); 810 if (error) 811 return (error); 812 return (0); 813} 814 815struct linux_socketpair_args { 816 int domain; 817 int type; 818 int protocol; 819 int *rsv; 820}; 821 822static int 823linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 824{ 825 struct linux_socketpair_args linux_args; 826 struct socketpair_args /* { 827 int domain; 828 int type; 829 int protocol; 830 int *rsv; 831 } */ bsd_args; 832 int error; 833 834 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 835 return (error); 836 837 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 838 if (bsd_args.domain == -1) 839 return (EINVAL); 840 841 bsd_args.type = linux_args.type; 842 bsd_args.protocol = linux_args.protocol; 843 bsd_args.rsv = linux_args.rsv; 844 return (socketpair(td, &bsd_args)); 845} 846 847struct linux_send_args { 848 int s; 849 void *msg; 850 int len; 851 int flags; 852}; 853 854static int 855linux_send(struct thread *td, struct linux_send_args *args) 856{ 857 struct linux_send_args linux_args; 858 struct sendto_args /* { 859 int s; 860 caddr_t buf; 861 int len; 862 int flags; 863 caddr_t to; 864 int tolen; 865 } */ bsd_args; 866 int error; 867 868 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 869 return (error); 870 871 bsd_args.s = linux_args.s; 872 bsd_args.buf = linux_args.msg; 873 bsd_args.len = linux_args.len; 874 bsd_args.flags = linux_args.flags; 875 bsd_args.to = NULL; 876 bsd_args.tolen = 0; 877 return (sendto(td, &bsd_args)); 878} 879 880struct linux_recv_args { 881 int s; 882 void *msg; 883 int len; 884 int flags; 885}; 886 887static int 888linux_recv(struct thread *td, struct linux_recv_args *args) 889{ 890 struct linux_recv_args linux_args; 891 struct recvfrom_args /* { 892 int s; 893 caddr_t buf; 894 int len; 895 int flags; 896 struct sockaddr *from; 897 socklen_t fromlenaddr; 898 } */ bsd_args; 899 int error; 900 901 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 902 return (error); 903 904 bsd_args.s = linux_args.s; 905 bsd_args.buf = linux_args.msg; 906 bsd_args.len = linux_args.len; 907 bsd_args.flags = linux_args.flags; 908 bsd_args.from = NULL; 909 bsd_args.fromlenaddr = 0; 910 return (recvfrom(td, &bsd_args)); 911} 912 913static int 914linux_sendto(struct thread *td, struct linux_sendto_args *args) 915{ 916 struct linux_sendto_args linux_args; 917 struct msghdr msg; 918 struct iovec aiov; 919 caddr_t sg = stackgap_init(); 920 int error; 921 922 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 923 return (error); 924 925 if (linux_check_hdrincl(td, &sg, linux_args.s) == 0) 926 /* IP_HDRINCL set, tweak the packet before sending */ 927 return (linux_sendto_hdrincl(td, &sg, &linux_args)); 928 929 msg.msg_name = linux_args.to; 930 msg.msg_namelen = linux_args.tolen; 931 msg.msg_iov = &aiov; 932 msg.msg_iovlen = 1; 933 msg.msg_control = NULL; 934 msg.msg_flags = 0; 935 aiov.iov_base = linux_args.msg; 936 aiov.iov_len = linux_args.len; 937 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags); 938 return (error); 939} 940 941struct linux_recvfrom_args { 942 int s; 943 void *buf; 944 int len; 945 int flags; 946 caddr_t from; 947 int *fromlen; 948}; 949 950static int 951linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 952{ 953 struct linux_recvfrom_args linux_args; 954 struct recvfrom_args /* { 955 int s; 956 caddr_t buf; 957 size_t len; 958 int flags; 959 struct sockaddr * __restrict from; 960 socklen_t * __restrict fromlenaddr; 961 } */ bsd_args; 962 int error; 963 964 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 965 return (error); 966 967 bsd_args.s = linux_args.s; 968 bsd_args.buf = linux_args.buf; 969 bsd_args.len = linux_args.len; 970 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 971 /* XXX: */ 972 bsd_args.from = (struct sockaddr * __restrict)linux_args.from; 973 bsd_args.fromlenaddr = linux_args.fromlen; /* XXX */ 974 error = orecvfrom(td, &bsd_args); 975 if (error) 976 return (error); 977 if (linux_args.from) { 978 error = linux_sa_put((struct osockaddr *) linux_args.from); 979 if (error) 980 return (error); 981 } 982 return (0); 983} 984 985struct linux_sendmsg_args { 986 int s; 987 const struct msghdr *msg; 988 int flags; 989}; 990 991static int 992linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 993{ 994 struct linux_sendmsg_args linux_args; 995 struct msghdr msg; 996 struct iovec *iov; 997 int error; 998 999 error = copyin(args, &linux_args, sizeof(linux_args)); 1000 if (error) 1001 return (error); 1002 error = copyin(linux_args.msg, &msg, sizeof(msg)); 1003 if (error) 1004 return (error); 1005 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1006 if (error) 1007 return (error); 1008 msg.msg_iov = iov; 1009 msg.msg_flags = 0; 1010 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags); 1011 free(iov, M_IOV); 1012 return (error); 1013} 1014 1015struct linux_recvmsg_args { 1016 int s; 1017 struct msghdr *msg; 1018 int flags; 1019}; 1020 1021static int 1022linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1023{ 1024 struct linux_recvmsg_args linux_args; 1025 struct recvmsg_args /* { 1026 int s; 1027 struct msghdr *msg; 1028 int flags; 1029 } */ bsd_args; 1030 struct msghdr msg; 1031 struct cmsghdr *cmsg; 1032 int error; 1033 1034 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1035 return (error); 1036 1037 bsd_args.s = linux_args.s; 1038 bsd_args.msg = linux_args.msg; 1039 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 1040 error = recvmsg(td, &bsd_args); 1041 if (error) 1042 return (error); 1043 1044 if (bsd_args.msg->msg_control != NULL) { 1045 cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; 1046 cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); 1047 } 1048 1049 error = copyin(linux_args.msg, &msg, sizeof(msg)); 1050 if (error) 1051 return (error); 1052 if (msg.msg_name && msg.msg_namelen > 2) 1053 error = linux_sa_put(msg.msg_name); 1054 return (error); 1055} 1056 1057struct linux_shutdown_args { 1058 int s; 1059 int how; 1060}; 1061 1062static int 1063linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1064{ 1065 struct linux_shutdown_args linux_args; 1066 struct shutdown_args /* { 1067 int s; 1068 int how; 1069 } */ bsd_args; 1070 int error; 1071 1072 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1073 return (error); 1074 1075 bsd_args.s = linux_args.s; 1076 bsd_args.how = linux_args.how; 1077 return (shutdown(td, &bsd_args)); 1078} 1079 1080struct linux_setsockopt_args { 1081 int s; 1082 int level; 1083 int optname; 1084 void *optval; 1085 int optlen; 1086}; 1087 1088static int 1089linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1090{ 1091 struct linux_setsockopt_args linux_args; 1092 struct setsockopt_args /* { 1093 int s; 1094 int level; 1095 int name; 1096 caddr_t val; 1097 int valsize; 1098 } */ bsd_args; 1099 int error, name; 1100 1101 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1102 return (error); 1103 1104 bsd_args.s = linux_args.s; 1105 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1106 switch (bsd_args.level) { 1107 case SOL_SOCKET: 1108 name = linux_to_bsd_so_sockopt(linux_args.optname); 1109 break; 1110 case IPPROTO_IP: 1111 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1112 break; 1113 case IPPROTO_TCP: 1114 /* Linux TCP option values match BSD's */ 1115 name = linux_args.optname; 1116 break; 1117 default: 1118 name = -1; 1119 break; 1120 } 1121 if (name == -1) 1122 return (EINVAL); 1123 1124 bsd_args.name = name; 1125 bsd_args.val = linux_args.optval; 1126 bsd_args.valsize = linux_args.optlen; 1127 return (setsockopt(td, &bsd_args)); 1128} 1129 1130struct linux_getsockopt_args { 1131 int s; 1132 int level; 1133 int optname; 1134 void *optval; 1135 int *optlen; 1136}; 1137 1138static int 1139linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1140{ 1141 struct linux_getsockopt_args linux_args; 1142 struct getsockopt_args /* { 1143 int s; 1144 int level; 1145 int name; 1146 caddr_t val; 1147 int *avalsize; 1148 } */ bsd_args; 1149 int error, name; 1150 1151 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1152 return (error); 1153 1154 bsd_args.s = linux_args.s; 1155 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1156 switch (bsd_args.level) { 1157 case SOL_SOCKET: 1158 name = linux_to_bsd_so_sockopt(linux_args.optname); 1159 break; 1160 case IPPROTO_IP: 1161 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1162 break; 1163 case IPPROTO_TCP: 1164 /* Linux TCP option values match BSD's */ 1165 name = linux_args.optname; 1166 break; 1167 default: 1168 name = -1; 1169 break; 1170 } 1171 if (name == -1) 1172 return (EINVAL); 1173 1174 bsd_args.name = name; 1175 bsd_args.val = linux_args.optval; 1176 bsd_args.avalsize = linux_args.optlen; 1177 return (getsockopt(td, &bsd_args)); 1178} 1179 1180int 1181linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1182{ 1183 void *arg = (void *)args->args; 1184 1185 switch (args->what) { 1186 case LINUX_SOCKET: 1187 return (linux_socket(td, arg)); 1188 case LINUX_BIND: 1189 return (linux_bind(td, arg)); 1190 case LINUX_CONNECT: 1191 return (linux_connect(td, arg)); 1192 case LINUX_LISTEN: 1193 return (linux_listen(td, arg)); 1194 case LINUX_ACCEPT: 1195 return (linux_accept(td, arg)); 1196 case LINUX_GETSOCKNAME: 1197 return (linux_getsockname(td, arg)); 1198 case LINUX_GETPEERNAME: 1199 return (linux_getpeername(td, arg)); 1200 case LINUX_SOCKETPAIR: 1201 return (linux_socketpair(td, arg)); 1202 case LINUX_SEND: 1203 return (linux_send(td, arg)); 1204 case LINUX_RECV: 1205 return (linux_recv(td, arg)); 1206 case LINUX_SENDTO: 1207 return (linux_sendto(td, arg)); 1208 case LINUX_RECVFROM: 1209 return (linux_recvfrom(td, arg)); 1210 case LINUX_SHUTDOWN: 1211 return (linux_shutdown(td, arg)); 1212 case LINUX_SETSOCKOPT: 1213 return (linux_setsockopt(td, arg)); 1214 case LINUX_GETSOCKOPT: 1215 return (linux_getsockopt(td, arg)); 1216 case LINUX_SENDMSG: 1217 return (linux_sendmsg(td, arg)); 1218 case LINUX_RECVMSG: 1219 return (linux_recvmsg(td, arg)); 1220 } 1221 1222 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1223 return (ENOSYS); 1224} 1225#endif /*!__alpha__*/ 1226