linux_socket.c revision 110295
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 * $FreeBSD: head/sys/compat/linux/linux_socket.c 110295 2003-02-03 17:43:20Z ume $ 29 */ 30 31/* XXX we use functions that might not exist. */ 32#include "opt_compat.h" 33#include "opt_inet6.h" 34 35#ifndef COMPAT_43 36#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 37#endif 38 39#include <sys/param.h> 40#include <sys/proc.h> 41#include <sys/systm.h> 42#include <sys/sysproto.h> 43#include <sys/fcntl.h> 44#include <sys/file.h> 45#include <sys/malloc.h> 46#include <sys/socket.h> 47#include <sys/socketvar.h> 48#include <sys/syscallsubr.h> 49#include <sys/uio.h> 50#include <sys/syslog.h> 51 52#include <netinet/in.h> 53#include <netinet/in_systm.h> 54#include <netinet/ip.h> 55#ifdef INET6 56#include <netinet/ip6.h> 57#include <netinet6/ip6_var.h> 58#endif 59 60#include <machine/../linux/linux.h> 61#include <machine/../linux/linux_proto.h> 62#include <compat/linux/linux_socket.h> 63#include <compat/linux/linux_util.h> 64 65#include <machine/limits.h> 66 67static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *, 68 struct malloc_type *); 69static 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 */ 75static int 76linux_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 */ 87static int 88do_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, 0); 118 119 if ((error = copyin(osa, (caddr_t) 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 164out: 165 FREE(kosa, mtype); 166 return (error); 167} 168 169static int 170linux_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__ 193static int 194bsd_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 216static int 217linux_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 227static int 228linux_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 254static int 255linux_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 285static int 286linux_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 */ 329static int 330linux_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 353out: 354 FREE(sa, M_TEMP); 355 return (error); 356} 357 358static int 359linux_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((caddr_t) osa, (caddr_t) &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. */ 385static int 386linux_check_hdrincl(struct thread *td, 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 sg, val, valsize; 397 int size_val = sizeof val; 398 int optval; 399 400 sg = stackgap_init(); 401 val = stackgap_alloc(&sg, sizeof(int)); 402 valsize = stackgap_alloc(&sg, sizeof(int)); 403 404 if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 405 return (error); 406 407 bsd_args.s = s; 408 bsd_args.level = IPPROTO_IP; 409 bsd_args.name = IP_HDRINCL; 410 bsd_args.val = val; 411 bsd_args.avalsize = (int *)valsize; 412 if ((error = getsockopt(td, &bsd_args))) 413 return (error); 414 415 if ((error = copyin(val, &optval, sizeof(optval)))) 416 return (error); 417 418 return (optval == 0); 419} 420 421/* 422 * Updated sendto() when IP_HDRINCL is set: 423 * tweak endian-dependent fields in the IP packet. 424 */ 425static int 426linux_sendto_hdrincl(struct thread *td, struct sendto_args *bsd_args) 427{ 428/* 429 * linux_ip_copysize defines how many bytes we should copy 430 * from the beginning of the IP packet before we customize it for BSD. 431 * It should include all the fields we modify (ip_len and ip_off) 432 * and be as small as possible to minimize copying overhead. 433 */ 434#define linux_ip_copysize 8 435 436 caddr_t sg; 437 struct ip *packet; 438 struct msghdr *msg; 439 struct iovec *iov; 440 441 int error; 442 struct sendmsg_args /* { 443 int s; 444 caddr_t msg; 445 int flags; 446 } */ sendmsg_args; 447 448 /* Check the packet isn't too small before we mess with it */ 449 if (bsd_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 sendmsg(). 457 */ 458 sg = stackgap_init(); 459 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 460 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 461 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 462 463 /* Make a copy of the beginning of the packet to be sent */ 464 if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize))) 465 return (error); 466 467 /* Convert fields from Linux to BSD raw IP socket format */ 468 packet->ip_len = bsd_args->len; 469 packet->ip_off = ntohs(packet->ip_off); 470 471 /* Prepare the msghdr and iovec structures describing the new packet */ 472 msg->msg_name = bsd_args->to; 473 msg->msg_namelen = bsd_args->tolen; 474 msg->msg_iov = iov; 475 msg->msg_iovlen = 2; 476 msg->msg_control = NULL; 477 msg->msg_controllen = 0; 478 msg->msg_flags = 0; 479 iov[0].iov_base = (char *)packet; 480 iov[0].iov_len = linux_ip_copysize; 481 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 482 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 483 484 sendmsg_args.s = bsd_args->s; 485 sendmsg_args.msg = (caddr_t)msg; 486 sendmsg_args.flags = bsd_args->flags; 487 return (sendmsg(td, &sendmsg_args)); 488} 489 490struct linux_socket_args { 491 int domain; 492 int type; 493 int protocol; 494}; 495 496static int 497linux_socket(struct thread *td, struct linux_socket_args *args) 498{ 499 struct linux_socket_args linux_args; 500 struct socket_args /* { 501 int domain; 502 int type; 503 int protocol; 504 } */ bsd_args; 505 struct setsockopt_args /* { 506 int s; 507 int level; 508 int name; 509 caddr_t val; 510 int valsize; 511 } */ bsd_setsockopt_args; 512 int error; 513 int retval_socket; 514 515 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 516 return (error); 517 518 bsd_args.protocol = linux_args.protocol; 519 bsd_args.type = linux_args.type; 520 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 521 if (bsd_args.domain == -1) 522 return (EINVAL); 523 524 retval_socket = socket(td, &bsd_args); 525 if (bsd_args.type == SOCK_RAW 526 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 527 && bsd_args.domain == AF_INET 528 && retval_socket >= 0) { 529 /* It's a raw IP socket: set the IP_HDRINCL option. */ 530 caddr_t sg; 531 int *hdrincl; 532 533 sg = stackgap_init(); 534 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 535 *hdrincl = 1; 536 bsd_setsockopt_args.s = td->td_retval[0]; 537 bsd_setsockopt_args.level = IPPROTO_IP; 538 bsd_setsockopt_args.name = IP_HDRINCL; 539 bsd_setsockopt_args.val = (caddr_t)hdrincl; 540 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 541 /* We ignore any error returned by setsockopt() */ 542 setsockopt(td, &bsd_setsockopt_args); 543 /* Copy back the return value from socket() */ 544 td->td_retval[0] = bsd_setsockopt_args.s; 545 } 546#ifdef INET6 547 /* 548 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 549 * default and some apps depend on this. So, set V6ONLY to 0 550 * for Linux apps if the sysctl value is set to 1. 551 */ 552 if (bsd_args.domain == PF_INET6 && retval_socket >= 0 && ip6_v6only) { 553 caddr_t sg; 554 int *v6only; 555 556 sg = stackgap_init(); 557 v6only = (int *)stackgap_alloc(&sg, sizeof(*v6only)); 558 *v6only = 0; 559 bsd_setsockopt_args.s = td->td_retval[0]; 560 bsd_setsockopt_args.level = IPPROTO_IPV6; 561 bsd_setsockopt_args.name = IPV6_V6ONLY; 562 bsd_setsockopt_args.val = (caddr_t)v6only; 563 bsd_setsockopt_args.valsize = sizeof(*v6only); 564 /* We ignore any error returned by setsockopt() */ 565 setsockopt(td, &bsd_setsockopt_args); 566 /* Copy back the return value from socket() */ 567 td->td_retval[0] = bsd_setsockopt_args.s; 568 } 569#endif 570 571 return (retval_socket); 572} 573 574struct linux_bind_args { 575 int s; 576 struct osockaddr *name; 577 int namelen; 578}; 579 580static int 581linux_bind(struct thread *td, struct linux_bind_args *args) 582{ 583 struct linux_bind_args linux_args; 584 struct sockaddr *sa; 585 int error; 586 587 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 588 return (error); 589 590 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen); 591 if (error) 592 return (error); 593 594 return (kern_bind(td, linux_args.s, sa)); 595} 596 597struct linux_connect_args { 598 int s; 599 struct osockaddr * name; 600 int namelen; 601}; 602int linux_connect(struct thread *, struct linux_connect_args *); 603#endif /* !__alpha__*/ 604 605int 606linux_connect(struct thread *td, struct linux_connect_args *args) 607{ 608 struct linux_connect_args linux_args; 609 struct socket *so; 610 struct sockaddr *sa; 611 u_int fflag; 612 int error; 613 614#ifdef __alpha__ 615 bcopy(args, &linux_args, sizeof(linux_args)); 616#else 617 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 618 return (error); 619#endif /* __alpha__ */ 620 621 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen); 622 if (error) 623 return (error); 624 625 error = kern_connect(td, linux_args.s, sa); 626 if (error != EISCONN) 627 return (error); 628 629 /* 630 * Linux doesn't return EISCONN the first time it occurs, 631 * when on a non-blocking socket. Instead it returns the 632 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 633 */ 634 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 635 return(error); 636 error = EISCONN; 637 if (fflag & FNONBLOCK) { 638 if (so->so_emuldata == 0) 639 error = so->so_error; 640 so->so_emuldata = (void *)1; 641 } 642 fputsock(so); 643 return (error); 644} 645 646#ifndef __alpha__ 647 648struct linux_listen_args { 649 int s; 650 int backlog; 651}; 652 653static int 654linux_listen(struct thread *td, struct linux_listen_args *args) 655{ 656 struct linux_listen_args linux_args; 657 struct listen_args /* { 658 int s; 659 int backlog; 660 } */ bsd_args; 661 int error; 662 663 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 664 return (error); 665 666 bsd_args.s = linux_args.s; 667 bsd_args.backlog = linux_args.backlog; 668 return (listen(td, &bsd_args)); 669} 670 671struct linux_accept_args { 672 int s; 673 struct osockaddr *addr; 674 int *namelen; 675}; 676 677static int 678linux_accept(struct thread *td, struct linux_accept_args *args) 679{ 680 struct linux_accept_args linux_args; 681 struct accept_args /* { 682 int s; 683 caddr_t name; 684 int *anamelen; 685 } */ bsd_args; 686 struct close_args /* { 687 int fd; 688 } */ c_args; 689 struct fcntl_args /* { 690 int fd; 691 int cmd; 692 long arg; 693 } */ f_args; 694 int error; 695 696 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 697 return (error); 698 699 bsd_args.s = linux_args.s; 700 bsd_args.name = (caddr_t)linux_args.addr; 701 bsd_args.anamelen = linux_args.namelen; 702 error = oaccept(td, &bsd_args); 703 if (error) 704 return (error); 705 if (linux_args.addr) { 706 error = linux_sa_put(linux_args.addr); 707 if (error) { 708 c_args.fd = td->td_retval[0]; 709 (void)close(td, &c_args); 710 return (error); 711 } 712 } 713 714 /* 715 * linux appears not to copy flags from the parent socket to the 716 * accepted one, so we must clear the flags in the new descriptor. 717 * Ignore any errors, because we already have an open fd. 718 */ 719 f_args.fd = td->td_retval[0]; 720 f_args.cmd = F_SETFL; 721 f_args.arg = 0; 722 (void)fcntl(td, &f_args); 723 td->td_retval[0] = f_args.fd; 724 return (0); 725} 726 727struct linux_getsockname_args { 728 int s; 729 struct osockaddr *addr; 730 int *namelen; 731}; 732 733static int 734linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 735{ 736 struct linux_getsockname_args linux_args; 737 struct getsockname_args /* { 738 int fdes; 739 caddr_t asa; 740 int *alen; 741 } */ bsd_args; 742 int error; 743 744 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 745 return (error); 746 747 bsd_args.fdes = linux_args.s; 748 bsd_args.asa = (caddr_t) linux_args.addr; 749 bsd_args.alen = linux_args.namelen; 750 error = ogetsockname(td, &bsd_args); 751 if (error) 752 return (error); 753 error = linux_sa_put(linux_args.addr); 754 if (error) 755 return (error); 756 return (0); 757} 758 759struct linux_getpeername_args { 760 int s; 761 struct osockaddr *addr; 762 int *namelen; 763}; 764 765static int 766linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 767{ 768 struct linux_getpeername_args linux_args; 769 struct ogetpeername_args /* { 770 int fdes; 771 caddr_t asa; 772 int *alen; 773 } */ bsd_args; 774 int error; 775 776 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 777 return (error); 778 779 bsd_args.fdes = linux_args.s; 780 bsd_args.asa = (caddr_t) linux_args.addr; 781 bsd_args.alen = linux_args.namelen; 782 error = ogetpeername(td, &bsd_args); 783 if (error) 784 return (error); 785 error = linux_sa_put(linux_args.addr); 786 if (error) 787 return (error); 788 return (0); 789} 790 791struct linux_socketpair_args { 792 int domain; 793 int type; 794 int protocol; 795 int *rsv; 796}; 797 798static int 799linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 800{ 801 struct linux_socketpair_args linux_args; 802 struct socketpair_args /* { 803 int domain; 804 int type; 805 int protocol; 806 int *rsv; 807 } */ bsd_args; 808 int error; 809 810 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 811 return (error); 812 813 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 814 if (bsd_args.domain == -1) 815 return (EINVAL); 816 817 bsd_args.type = linux_args.type; 818 bsd_args.protocol = linux_args.protocol; 819 bsd_args.rsv = linux_args.rsv; 820 return (socketpair(td, &bsd_args)); 821} 822 823struct linux_send_args { 824 int s; 825 void *msg; 826 int len; 827 int flags; 828}; 829 830static int 831linux_send(struct thread *td, struct linux_send_args *args) 832{ 833 struct linux_send_args linux_args; 834 struct osend_args /* { 835 int s; 836 caddr_t buf; 837 int len; 838 int flags; 839 } */ bsd_args; 840 int error; 841 842 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 843 return (error); 844 845 bsd_args.s = linux_args.s; 846 bsd_args.buf = linux_args.msg; 847 bsd_args.len = linux_args.len; 848 bsd_args.flags = linux_args.flags; 849 return (osend(td, &bsd_args)); 850} 851 852struct linux_recv_args { 853 int s; 854 void *msg; 855 int len; 856 int flags; 857}; 858 859static int 860linux_recv(struct thread *td, struct linux_recv_args *args) 861{ 862 struct linux_recv_args linux_args; 863 struct orecv_args /* { 864 int s; 865 caddr_t buf; 866 int len; 867 int flags; 868 } */ bsd_args; 869 int error; 870 871 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 872 return (error); 873 874 bsd_args.s = linux_args.s; 875 bsd_args.buf = linux_args.msg; 876 bsd_args.len = linux_args.len; 877 bsd_args.flags = linux_args.flags; 878 return (orecv(td, &bsd_args)); 879} 880 881struct linux_sendto_args { 882 int s; 883 void *msg; 884 int len; 885 int flags; 886 caddr_t to; 887 int tolen; 888}; 889 890static int 891linux_sendto(struct thread *td, struct linux_sendto_args *args) 892{ 893 struct linux_sendto_args linux_args; 894 struct sendto_args /* { 895 int s; 896 caddr_t buf; 897 size_t len; 898 int flags; 899 caddr_t to; 900 int tolen; 901 } */ bsd_args; 902 caddr_t sg = stackgap_init(); 903 struct sockaddr *to; 904 int tolen, error; 905 906 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 907 return (error); 908 909 tolen = linux_args.tolen; 910 if (linux_args.to) { 911 error = linux_sa_get(&sg, &to, 912 (struct osockaddr *) linux_args.to, &tolen); 913 if (error) 914 return (error); 915 } else 916 to = NULL; 917 918 bsd_args.s = linux_args.s; 919 bsd_args.buf = linux_args.msg; 920 bsd_args.len = linux_args.len; 921 bsd_args.flags = linux_args.flags; 922 bsd_args.to = (caddr_t) to; 923 bsd_args.tolen = (unsigned int) tolen; 924 925 if (linux_check_hdrincl(td, linux_args.s) == 0) 926 /* IP_HDRINCL set, tweak the packet before sending */ 927 return (linux_sendto_hdrincl(td, &bsd_args)); 928 929 return (sendto(td, &bsd_args)); 930} 931 932struct linux_recvfrom_args { 933 int s; 934 void *buf; 935 int len; 936 int flags; 937 caddr_t from; 938 int *fromlen; 939}; 940 941static int 942linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 943{ 944 struct linux_recvfrom_args linux_args; 945 struct recvfrom_args /* { 946 int s; 947 caddr_t buf; 948 size_t len; 949 int flags; 950 caddr_t from; 951 int *fromlenaddr; 952 } */ bsd_args; 953 int error; 954 955 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 956 return (error); 957 958 bsd_args.s = linux_args.s; 959 bsd_args.buf = linux_args.buf; 960 bsd_args.len = linux_args.len; 961 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 962 bsd_args.from = linux_args.from; 963 bsd_args.fromlenaddr = linux_args.fromlen; 964 error = orecvfrom(td, &bsd_args); 965 if (error) 966 return (error); 967 if (linux_args.from) { 968 error = linux_sa_put((struct osockaddr *) linux_args.from); 969 if (error) 970 return (error); 971 } 972 return (0); 973} 974 975struct linux_sendmsg_args { 976 int s; 977 const struct msghdr *msg; 978 int flags; 979}; 980 981static int 982linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 983{ 984 struct linux_sendmsg_args linux_args; 985 struct sendmsg_args /* { 986 int s; 987 const struct msghdr *msg; 988 int flags; 989 } */ bsd_args; 990 struct msghdr msg; 991 struct msghdr *nmsg = NULL; 992 int error; 993 int level; 994 caddr_t control; 995 996 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 997 return (error); 998 999 error = copyin(linux_args.msg, (caddr_t) &msg, sizeof(msg)); 1000 if (error) 1001 return (error); 1002 1003 if (msg.msg_name) { 1004 struct sockaddr *sa; 1005 caddr_t sg = stackgap_init(); 1006 1007 nmsg = (struct msghdr *) stackgap_alloc(&sg, 1008 sizeof(struct msghdr)); 1009 if (!nmsg) 1010 return (ENOMEM); 1011 1012 error = linux_sa_get(&sg, &sa, 1013 (struct osockaddr *) msg.msg_name, &msg.msg_namelen); 1014 if (error) 1015 return (error); 1016 1017 msg.msg_name = (struct sockaddr *) sa; 1018 error = copyout(&msg, nmsg, sizeof(struct msghdr)); 1019 if (error) 1020 return (error); 1021 } 1022 1023 error = copyin(&linux_args.msg->msg_control, &control, 1024 sizeof(caddr_t)); 1025 if (error) 1026 return (error); 1027 1028 if (control == NULL) 1029 goto done; 1030 1031 error = copyin(&((struct cmsghdr*)control)->cmsg_level, &level, 1032 sizeof(int)); 1033 if (error) 1034 return (error); 1035 1036 if (level == 1) { 1037 /* 1038 * Linux thinks that SOL_SOCKET is 1; we know 1039 * that it's really 0xffff, of course. 1040 */ 1041 level = SOL_SOCKET; 1042 error = copyout(&level, 1043 &((struct cmsghdr *)control)->cmsg_level, sizeof(int)); 1044 if (error) 1045 return (error); 1046 } 1047done: 1048 return (sendmsg(td, &bsd_args)); 1049} 1050 1051struct linux_recvmsg_args { 1052 int s; 1053 struct msghdr *msg; 1054 int flags; 1055}; 1056 1057static int 1058linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1059{ 1060 struct linux_recvmsg_args linux_args; 1061 struct recvmsg_args /* { 1062 int s; 1063 struct msghdr *msg; 1064 int flags; 1065 } */ bsd_args; 1066 struct msghdr msg; 1067 int error; 1068 1069 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1070 return (error); 1071 1072 bsd_args.s = linux_args.s; 1073 bsd_args.msg = linux_args.msg; 1074 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 1075 error = recvmsg(td, &bsd_args); 1076 if (error) 1077 return (error); 1078 1079 error = copyin((caddr_t)linux_args.msg, (caddr_t)&msg, sizeof(msg)); 1080 if (error) 1081 return (error); 1082 if (msg.msg_name && msg.msg_namelen > 2) 1083 error = linux_sa_put(msg.msg_name); 1084 return (error); 1085} 1086 1087struct linux_shutdown_args { 1088 int s; 1089 int how; 1090}; 1091 1092static int 1093linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1094{ 1095 struct linux_shutdown_args linux_args; 1096 struct shutdown_args /* { 1097 int s; 1098 int how; 1099 } */ bsd_args; 1100 int error; 1101 1102 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1103 return (error); 1104 1105 bsd_args.s = linux_args.s; 1106 bsd_args.how = linux_args.how; 1107 return (shutdown(td, &bsd_args)); 1108} 1109 1110struct linux_setsockopt_args { 1111 int s; 1112 int level; 1113 int optname; 1114 void *optval; 1115 int optlen; 1116}; 1117 1118static int 1119linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1120{ 1121 struct linux_setsockopt_args linux_args; 1122 struct setsockopt_args /* { 1123 int s; 1124 int level; 1125 int name; 1126 caddr_t val; 1127 int valsize; 1128 } */ bsd_args; 1129 int error, name; 1130 1131 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1132 return (error); 1133 1134 bsd_args.s = linux_args.s; 1135 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1136 switch (bsd_args.level) { 1137 case SOL_SOCKET: 1138 name = linux_to_bsd_so_sockopt(linux_args.optname); 1139 break; 1140 case IPPROTO_IP: 1141 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1142 break; 1143 case IPPROTO_TCP: 1144 /* Linux TCP option values match BSD's */ 1145 name = linux_args.optname; 1146 break; 1147 default: 1148 name = -1; 1149 break; 1150 } 1151 if (name == -1) 1152 return (EINVAL); 1153 1154 bsd_args.name = name; 1155 bsd_args.val = linux_args.optval; 1156 bsd_args.valsize = linux_args.optlen; 1157 return (setsockopt(td, &bsd_args)); 1158} 1159 1160struct linux_getsockopt_args { 1161 int s; 1162 int level; 1163 int optname; 1164 void *optval; 1165 int *optlen; 1166}; 1167 1168static int 1169linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1170{ 1171 struct linux_getsockopt_args linux_args; 1172 struct getsockopt_args /* { 1173 int s; 1174 int level; 1175 int name; 1176 caddr_t val; 1177 int *avalsize; 1178 } */ bsd_args; 1179 int error, name; 1180 1181 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1182 return (error); 1183 1184 bsd_args.s = linux_args.s; 1185 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1186 switch (bsd_args.level) { 1187 case SOL_SOCKET: 1188 name = linux_to_bsd_so_sockopt(linux_args.optname); 1189 break; 1190 case IPPROTO_IP: 1191 name = linux_to_bsd_ip_sockopt(linux_args.optname); 1192 break; 1193 case IPPROTO_TCP: 1194 /* Linux TCP option values match BSD's */ 1195 name = linux_args.optname; 1196 break; 1197 default: 1198 name = -1; 1199 break; 1200 } 1201 if (name == -1) 1202 return (EINVAL); 1203 1204 bsd_args.name = name; 1205 bsd_args.val = linux_args.optval; 1206 bsd_args.avalsize = linux_args.optlen; 1207 return (getsockopt(td, &bsd_args)); 1208} 1209 1210int 1211linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1212{ 1213 void *arg = (void *)args->args; 1214 1215 switch (args->what) { 1216 case LINUX_SOCKET: 1217 return (linux_socket(td, arg)); 1218 case LINUX_BIND: 1219 return (linux_bind(td, arg)); 1220 case LINUX_CONNECT: 1221 return (linux_connect(td, arg)); 1222 case LINUX_LISTEN: 1223 return (linux_listen(td, arg)); 1224 case LINUX_ACCEPT: 1225 return (linux_accept(td, arg)); 1226 case LINUX_GETSOCKNAME: 1227 return (linux_getsockname(td, arg)); 1228 case LINUX_GETPEERNAME: 1229 return (linux_getpeername(td, arg)); 1230 case LINUX_SOCKETPAIR: 1231 return (linux_socketpair(td, arg)); 1232 case LINUX_SEND: 1233 return (linux_send(td, arg)); 1234 case LINUX_RECV: 1235 return (linux_recv(td, arg)); 1236 case LINUX_SENDTO: 1237 return (linux_sendto(td, arg)); 1238 case LINUX_RECVFROM: 1239 return (linux_recvfrom(td, arg)); 1240 case LINUX_SHUTDOWN: 1241 return (linux_shutdown(td, arg)); 1242 case LINUX_SETSOCKOPT: 1243 return (linux_setsockopt(td, arg)); 1244 case LINUX_GETSOCKOPT: 1245 return (linux_getsockopt(td, arg)); 1246 case LINUX_SENDMSG: 1247 return (linux_sendmsg(td, arg)); 1248 case LINUX_RECVMSG: 1249 return (linux_recvmsg(td, arg)); 1250 } 1251 1252 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1253 return (ENOSYS); 1254} 1255#endif /*!__alpha__*/ 1256