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 103839 2002-09-23 06:17:54Z mini $
|
28 * $FreeBSD: head/sys/compat/linux/linux_socket.c 103886 2002-09-24 07:03:01Z mini $ |
29 */ 30 31/* XXX we use functions that might not exist. */ 32#include "opt_compat.h" 33 34#ifndef COMPAT_43 35#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 36#endif 37 38#include <sys/param.h> 39#include <sys/proc.h> 40#include <sys/systm.h> 41#include <sys/sysproto.h> 42#include <sys/fcntl.h> 43#include <sys/file.h> 44#include <sys/socket.h> 45#include <sys/socketvar.h> 46#include <sys/uio.h> 47 48#include <netinet/in.h> 49#include <netinet/in_systm.h> 50#include <netinet/ip.h> 51 52#include <machine/../linux/linux.h> 53#include <machine/../linux/linux_proto.h> 54#include <compat/linux/linux_socket.h> 55#include <compat/linux/linux_util.h> 56 57/* 58 * FreeBSD's socket calls require the sockaddr struct length to agree 59 * with the address family. Linux does not, so we must force it. 60 */ 61static int 62linux_to_bsd_namelen(caddr_t name, int namelen) 63{ 64 uint16_t family; /* XXX must match Linux sockaddr */ 65 66 if (copyin(name, &family, sizeof(family))) 67 return namelen; 68 69 switch (family) { 70 case AF_INET: 71 return sizeof(struct sockaddr_in); 72 case AF_INET6: 73 return sizeof(struct sockaddr_in6); 74 } 75 return namelen; 76} 77 78#ifndef __alpha__ 79static int 80linux_to_bsd_domain(int domain) 81{ 82 83 switch (domain) { 84 case LINUX_AF_UNSPEC: 85 return (AF_UNSPEC); 86 case LINUX_AF_UNIX: 87 return (AF_LOCAL); 88 case LINUX_AF_INET: 89 return (AF_INET); 90 case LINUX_AF_AX25: 91 return (AF_CCITT); 92 case LINUX_AF_IPX: 93 return (AF_IPX); 94 case LINUX_AF_APPLETALK: 95 return (AF_APPLETALK); 96 } 97 return (-1); 98} 99 100static int 101linux_to_bsd_sockopt_level(int level) 102{ 103 104 switch (level) { 105 case LINUX_SOL_SOCKET: 106 return (SOL_SOCKET); 107 } 108 return (level); 109} 110 111static int 112linux_to_bsd_ip_sockopt(int opt) 113{ 114 115 switch (opt) { 116 case LINUX_IP_TOS: 117 return (IP_TOS); 118 case LINUX_IP_TTL: 119 return (IP_TTL); 120 case LINUX_IP_OPTIONS: 121 return (IP_OPTIONS); 122 case LINUX_IP_MULTICAST_IF: 123 return (IP_MULTICAST_IF); 124 case LINUX_IP_MULTICAST_TTL: 125 return (IP_MULTICAST_TTL); 126 case LINUX_IP_MULTICAST_LOOP: 127 return (IP_MULTICAST_LOOP); 128 case LINUX_IP_ADD_MEMBERSHIP: 129 return (IP_ADD_MEMBERSHIP); 130 case LINUX_IP_DROP_MEMBERSHIP: 131 return (IP_DROP_MEMBERSHIP); 132 case LINUX_IP_HDRINCL: 133 return (IP_HDRINCL); 134 } 135 return (-1); 136} 137 138static int 139linux_to_bsd_so_sockopt(int opt) 140{ 141 142 switch (opt) { 143 case LINUX_SO_DEBUG: 144 return (SO_DEBUG); 145 case LINUX_SO_REUSEADDR: 146 return (SO_REUSEADDR); 147 case LINUX_SO_TYPE: 148 return (SO_TYPE); 149 case LINUX_SO_ERROR: 150 return (SO_ERROR); 151 case LINUX_SO_DONTROUTE: 152 return (SO_DONTROUTE); 153 case LINUX_SO_BROADCAST: 154 return (SO_BROADCAST); 155 case LINUX_SO_SNDBUF: 156 return (SO_SNDBUF); 157 case LINUX_SO_RCVBUF: 158 return (SO_RCVBUF); 159 case LINUX_SO_KEEPALIVE: 160 return (SO_KEEPALIVE); 161 case LINUX_SO_OOBINLINE: 162 return (SO_OOBINLINE); 163 case LINUX_SO_LINGER: 164 return (SO_LINGER); 165 } 166 return (-1); 167} 168 169static int 170linux_to_bsd_msg_flags(int flags) 171{ 172 int ret_flags = 0; 173 174 if (flags & LINUX_MSG_OOB) 175 ret_flags |= MSG_OOB; 176 if (flags & LINUX_MSG_PEEK) 177 ret_flags |= MSG_PEEK; 178 if (flags & LINUX_MSG_DONTROUTE) 179 ret_flags |= MSG_DONTROUTE; 180 if (flags & LINUX_MSG_CTRUNC) 181 ret_flags |= MSG_CTRUNC; 182 if (flags & LINUX_MSG_TRUNC) 183 ret_flags |= MSG_TRUNC; 184 if (flags & LINUX_MSG_DONTWAIT) 185 ret_flags |= MSG_DONTWAIT; 186 if (flags & LINUX_MSG_EOR) 187 ret_flags |= MSG_EOR; 188 if (flags & LINUX_MSG_WAITALL) 189 ret_flags |= MSG_WAITALL; 190#if 0 /* not handled */ 191 if (flags & LINUX_MSG_PROXY) 192 ; 193 if (flags & LINUX_MSG_FIN) 194 ; 195 if (flags & LINUX_MSG_SYN) 196 ; 197 if (flags & LINUX_MSG_CONFIRM) 198 ; 199 if (flags & LINUX_MSG_RST) 200 ; 201 if (flags & LINUX_MSG_ERRQUEUE) 202 ; 203 if (flags & LINUX_MSG_NOSIGNAL) 204 ; 205#endif 206 return ret_flags; 207} 208 209/* Return 0 if IP_HDRINCL is set for the given socket. */ 210static int 211linux_check_hdrincl(struct thread *td, int s) 212{ 213 struct getsockopt_args /* { 214 int s; 215 int level; 216 int name; 217 caddr_t val; 218 int *avalsize; 219 } */ bsd_args; 220 int error; 221 caddr_t sg, val, valsize; 222 int size_val = sizeof val; 223 int optval; 224 225 sg = stackgap_init(); 226 val = stackgap_alloc(&sg, sizeof(int)); 227 valsize = stackgap_alloc(&sg, sizeof(int)); 228 229 if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 230 return (error); 231 232 bsd_args.s = s; 233 bsd_args.level = IPPROTO_IP; 234 bsd_args.name = IP_HDRINCL; 235 bsd_args.val = val; 236 bsd_args.avalsize = (int *)valsize; 237 if ((error = getsockopt(td, &bsd_args))) 238 return (error); 239 240 if ((error = copyin(val, &optval, sizeof(optval)))) 241 return (error); 242 243 return (optval == 0); 244} 245 246/* 247 * Updated sendto() when IP_HDRINCL is set: 248 * tweak endian-dependent fields in the IP packet. 249 */ 250static int 251linux_sendto_hdrincl(struct thread *td, struct sendto_args *bsd_args) 252{ 253/* 254 * linux_ip_copysize defines how many bytes we should copy 255 * from the beginning of the IP packet before we customize it for BSD. 256 * It should include all the fields we modify (ip_len and ip_off) 257 * and be as small as possible to minimize copying overhead. 258 */ 259#define linux_ip_copysize 8 260 261 caddr_t sg; 262 struct ip *packet; 263 struct msghdr *msg; 264 struct iovec *iov; 265 266 int error; 267 struct sendmsg_args /* { 268 int s; 269 caddr_t msg; 270 int flags; 271 } */ sendmsg_args; 272 273 /* Check the packet isn't too small before we mess with it */ 274 if (bsd_args->len < linux_ip_copysize) 275 return (EINVAL); 276 277 /* 278 * Tweaking the user buffer in place would be bad manners. 279 * We create a corrected IP header with just the needed length, 280 * then use an iovec to glue it to the rest of the user packet 281 * when calling sendmsg(). 282 */ 283 sg = stackgap_init(); 284 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 285 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 286 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 287 288 /* Make a copy of the beginning of the packet to be sent */ 289 if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize))) 290 return (error); 291 292 /* Convert fields from Linux to BSD raw IP socket format */ 293 packet->ip_len = bsd_args->len; 294 packet->ip_off = ntohs(packet->ip_off); 295 296 /* Prepare the msghdr and iovec structures describing the new packet */ 297 msg->msg_name = bsd_args->to; 298 msg->msg_namelen = bsd_args->tolen; 299 msg->msg_iov = iov; 300 msg->msg_iovlen = 2; 301 msg->msg_control = NULL; 302 msg->msg_controllen = 0; 303 msg->msg_flags = 0; 304 iov[0].iov_base = (char *)packet; 305 iov[0].iov_len = linux_ip_copysize; 306 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 307 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 308 309 sendmsg_args.s = bsd_args->s; 310 sendmsg_args.msg = (caddr_t)msg; 311 sendmsg_args.flags = bsd_args->flags; 312 return (sendmsg(td, &sendmsg_args)); 313} 314 315struct linux_socket_args { 316 int domain; 317 int type; 318 int protocol; 319}; 320 321static int 322linux_socket(struct thread *td, struct linux_socket_args *args) 323{ 324 struct linux_socket_args linux_args; 325 struct socket_args /* { 326 int domain; 327 int type; 328 int protocol; 329 } */ bsd_args; 330 int error; 331 int retval_socket; 332 333 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 334 return (error); 335 336 bsd_args.protocol = linux_args.protocol; 337 bsd_args.type = linux_args.type; 338 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 339 if (bsd_args.domain == -1) 340 return (EINVAL); 341 342 retval_socket = socket(td, &bsd_args); 343 if (bsd_args.type == SOCK_RAW 344 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 345 && bsd_args.domain == AF_INET 346 && retval_socket >= 0) { 347 /* It's a raw IP socket: set the IP_HDRINCL option. */ 348 struct setsockopt_args /* { 349 int s; 350 int level; 351 int name; 352 caddr_t val; 353 int valsize; 354 } */ bsd_setsockopt_args; 355 caddr_t sg; 356 int *hdrincl; 357 358 sg = stackgap_init(); 359 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 360 *hdrincl = 1; 361 bsd_setsockopt_args.s = td->td_retval[0]; 362 bsd_setsockopt_args.level = IPPROTO_IP; 363 bsd_setsockopt_args.name = IP_HDRINCL; 364 bsd_setsockopt_args.val = (caddr_t)hdrincl; 365 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 366 /* We ignore any error returned by setsockopt() */ 367 setsockopt(td, &bsd_setsockopt_args); 368 /* Copy back the return value from socket() */ 369 td->td_retval[0] = bsd_setsockopt_args.s; 370 } 371 372 return (retval_socket); 373} 374 375struct linux_bind_args { 376 int s; 377 struct sockaddr *name; 378 int namelen; 379}; 380 381static int 382linux_bind(struct thread *td, struct linux_bind_args *args) 383{ 384 struct linux_bind_args linux_args; 385 struct bind_args /* { 386 int s; 387 caddr_t name; 388 int namelen; 389 } */ bsd_args; 390 int error; 391 392 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 393 return (error); 394 395 bsd_args.s = linux_args.s; 396 bsd_args.name = (caddr_t)linux_args.name; 397 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 398 return (bind(td, &bsd_args)); 399} 400 401struct linux_connect_args { 402 int s; 403 struct sockaddr * name; 404 int namelen; 405}; 406int linux_connect(struct thread *, struct linux_connect_args *); 407#endif /* !__alpha__*/ 408 409int 410linux_connect(struct thread *td, struct linux_connect_args *args) 411{ 412 struct linux_connect_args linux_args; 413 struct connect_args /* { 414 int s; 415 caddr_t name; 416 int namelen; 417 } */ bsd_args; 418 struct socket *so; 419 u_int fflag; 420 int error; 421 422#ifdef __alpha__ 423 bcopy(args, &linux_args, sizeof(linux_args)); 424#else 425 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 426 return (error); 427#endif /* __alpha__ */ 428 429 bsd_args.s = linux_args.s; 430 bsd_args.name = (caddr_t)linux_args.name; 431 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 432 error = connect(td, &bsd_args); 433 if (error != EISCONN) 434 return (error); 435 436 /* 437 * Linux doesn't return EISCONN the first time it occurs, 438 * when on a non-blocking socket. Instead it returns the 439 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 440 */ 441 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 442 return(error); 443 error = EISCONN; 444 if (fflag & FNONBLOCK) { 445 if (so->so_emuldata == 0) 446 error = so->so_error; 447 so->so_emuldata = (void *)1; 448 } 449 fputsock(so); 450 return (error); 451} 452 453#ifndef __alpha__ 454 455struct linux_listen_args { 456 int s; 457 int backlog; 458}; 459 460static int 461linux_listen(struct thread *td, struct linux_listen_args *args) 462{ 463 struct linux_listen_args linux_args; 464 struct listen_args /* { 465 int s; 466 int backlog; 467 } */ bsd_args; 468 int error; 469 470 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 471 return (error); 472 473 bsd_args.s = linux_args.s; 474 bsd_args.backlog = linux_args.backlog; 475 return (listen(td, &bsd_args)); 476} 477 478struct linux_accept_args { 479 int s; 480 struct sockaddr *addr; 481 int *namelen; 482}; 483 484static int 485linux_accept(struct thread *td, struct linux_accept_args *args) 486{ 487 struct linux_accept_args linux_args; 488 struct accept_args /* { 489 int s; 490 caddr_t name; 491 int *anamelen; 492 } */ bsd_args; 493 struct fcntl_args /* { 494 int fd; 495 int cmd; 496 long arg; 497 } */ f_args; 498 int error; 499 500 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 501 return (error); 502 503 bsd_args.s = linux_args.s; 504 bsd_args.name = (caddr_t)linux_args.addr; 505 bsd_args.anamelen = linux_args.namelen;
|
506 error = accept(td, &bsd_args);
|
506 error = oaccept(td, &bsd_args); |
507 if (error) 508 return (error); 509 510 /* 511 * linux appears not to copy flags from the parent socket to the 512 * accepted one, so we must clear the flags in the new descriptor. 513 * Ignore any errors, because we already have an open fd. 514 */ 515 f_args.fd = td->td_retval[0]; 516 f_args.cmd = F_SETFL; 517 f_args.arg = 0; 518 (void)fcntl(td, &f_args); 519 td->td_retval[0] = f_args.fd; 520 return (0); 521} 522 523struct linux_getsockname_args { 524 int s; 525 struct sockaddr *addr; 526 int *namelen; 527}; 528 529static int 530linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 531{ 532 struct linux_getsockname_args linux_args; 533 struct getsockname_args /* { 534 int fdes; 535 caddr_t asa; 536 int *alen; 537 } */ bsd_args; 538 int error; 539 540 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 541 return (error); 542 543 bsd_args.fdes = linux_args.s; 544 bsd_args.asa = (caddr_t) linux_args.addr; 545 bsd_args.alen = linux_args.namelen;
|
546 return (getsockname(td, &bsd_args));
|
546 return (ogetsockname(td, &bsd_args)); |
547} 548 549struct linux_getpeername_args { 550 int s; 551 struct sockaddr *addr; 552 int *namelen; 553}; 554 555static int 556linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 557{ 558 struct linux_getpeername_args linux_args;
|
559 struct getpeername_args /* {
|
559 struct ogetpeername_args /* { |
560 int fdes; 561 caddr_t asa; 562 int *alen; 563 } */ bsd_args; 564 int error; 565 566 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 567 return (error); 568 569 bsd_args.fdes = linux_args.s; 570 bsd_args.asa = (caddr_t) linux_args.addr; 571 bsd_args.alen = linux_args.namelen;
|
572 return (getpeername(td, &bsd_args));
|
572 return (ogetpeername(td, &bsd_args)); |
573} 574 575struct linux_socketpair_args { 576 int domain; 577 int type; 578 int protocol; 579 int *rsv; 580}; 581 582static int 583linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 584{ 585 struct linux_socketpair_args linux_args; 586 struct socketpair_args /* { 587 int domain; 588 int type; 589 int protocol; 590 int *rsv; 591 } */ bsd_args; 592 int error; 593 594 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 595 return (error); 596 597 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 598 if (bsd_args.domain == -1) 599 return (EINVAL); 600 601 bsd_args.type = linux_args.type; 602 bsd_args.protocol = linux_args.protocol; 603 bsd_args.rsv = linux_args.rsv; 604 return (socketpair(td, &bsd_args)); 605} 606 607struct linux_send_args { 608 int s; 609 void *msg; 610 int len; 611 int flags; 612}; 613 614static int 615linux_send(struct thread *td, struct linux_send_args *args) 616{ 617 struct linux_send_args linux_args;
|
618 struct sendto_args /* {
619 int s;
|
618 struct osend_args /* { 619 int s; |
620 caddr_t buf;
|
621 size_t len;
|
621 int len; |
622 int flags;
|
623 caddr_t to;
624 int tolen;
|
623 } */ bsd_args; 624 int error; 625 626 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 627 return (error); 628 629 bsd_args.s = linux_args.s; 630 bsd_args.buf = linux_args.msg; 631 bsd_args.len = linux_args.len; 632 bsd_args.flags = linux_args.flags;
|
635 bsd_args.to = NULL;
636 bsd_args.tolen = 0;
637 return (sendto(td, &bsd_args));
|
633 return (osend(td, &bsd_args)); |
634} 635 636struct linux_recv_args { 637 int s; 638 void *msg; 639 int len; 640 int flags; 641}; 642 643static int 644linux_recv(struct thread *td, struct linux_recv_args *args) 645{ 646 struct linux_recv_args linux_args;
|
651 struct recvfrom_args /* {
|
647 struct orecv_args /* { |
648 int s; 649 caddr_t buf; 650 int len; 651 int flags;
|
656 caddr_t from;
657 int fromlen;
|
652 } */ bsd_args; 653 int error; 654 655 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 656 return (error); 657 658 bsd_args.s = linux_args.s; 659 bsd_args.buf = linux_args.msg; 660 bsd_args.len = linux_args.len; 661 bsd_args.flags = linux_args.flags;
|
668 bsd_args.from = NULL;
669 bsd_args.fromlenaddr = NULL;
670 return (recvfrom(td, &bsd_args));
|
662 return (orecv(td, &bsd_args)); |
663} 664 665struct linux_sendto_args { 666 int s; 667 void *msg; 668 int len; 669 int flags; 670 caddr_t to; 671 int tolen; 672}; 673 674static int 675linux_sendto(struct thread *td, struct linux_sendto_args *args) 676{ 677 struct linux_sendto_args linux_args; 678 struct sendto_args /* { 679 int s; 680 caddr_t buf; 681 size_t len; 682 int flags; 683 caddr_t to; 684 int tolen; 685 } */ bsd_args; 686 int error; 687 688 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 689 return (error); 690 691 bsd_args.s = linux_args.s; 692 bsd_args.buf = linux_args.msg; 693 bsd_args.len = linux_args.len; 694 bsd_args.flags = linux_args.flags; 695 bsd_args.to = linux_args.to; 696 bsd_args.tolen = linux_args.tolen; 697 698 if (linux_check_hdrincl(td, linux_args.s) == 0) 699 /* IP_HDRINCL set, tweak the packet before sending */ 700 return (linux_sendto_hdrincl(td, &bsd_args)); 701 702 return (sendto(td, &bsd_args)); 703} 704 705struct linux_recvfrom_args { 706 int s; 707 void *buf; 708 int len; 709 int flags; 710 caddr_t from; 711 int *fromlen; 712}; 713 714static int 715linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 716{ 717 struct linux_recvfrom_args linux_args; 718 struct recvfrom_args /* { 719 int s; 720 caddr_t buf; 721 size_t len; 722 int flags; 723 caddr_t from; 724 int *fromlenaddr; 725 } */ bsd_args; 726 int error; 727 728 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 729 return (error); 730 731 bsd_args.s = linux_args.s; 732 bsd_args.buf = linux_args.buf; 733 bsd_args.len = linux_args.len; 734 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 735 bsd_args.from = linux_args.from; 736 bsd_args.fromlenaddr = linux_args.fromlen;
|
745 return (recvfrom(td, &bsd_args));
|
737 return (orecvfrom(td, &bsd_args)); |
738} 739 740struct linux_recvmsg_args { 741 int s; 742 struct msghdr *msg; 743 int flags; 744}; 745 746static int 747linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 748{ 749 struct linux_recvmsg_args linux_args; 750 struct recvmsg_args /* { 751 int s; 752 struct msghdr *msg; 753 int flags; 754 } */ bsd_args; 755 int error; 756 757 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 758 return (error); 759 760 bsd_args.s = linux_args.s; 761 bsd_args.msg = linux_args.msg; 762 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 763 return (recvmsg(td, &bsd_args)); 764} 765 766struct linux_shutdown_args { 767 int s; 768 int how; 769}; 770 771static int 772linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 773{ 774 struct linux_shutdown_args linux_args; 775 struct shutdown_args /* { 776 int s; 777 int how; 778 } */ bsd_args; 779 int error; 780 781 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 782 return (error); 783 784 bsd_args.s = linux_args.s; 785 bsd_args.how = linux_args.how; 786 return (shutdown(td, &bsd_args)); 787} 788 789struct linux_setsockopt_args { 790 int s; 791 int level; 792 int optname; 793 void *optval; 794 int optlen; 795}; 796 797static int 798linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 799{ 800 struct linux_setsockopt_args linux_args; 801 struct setsockopt_args /* { 802 int s; 803 int level; 804 int name; 805 caddr_t val; 806 int valsize; 807 } */ bsd_args; 808 int error, name; 809 810 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 811 return (error); 812 813 bsd_args.s = linux_args.s; 814 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 815 switch (bsd_args.level) { 816 case SOL_SOCKET: 817 name = linux_to_bsd_so_sockopt(linux_args.optname); 818 break; 819 case IPPROTO_IP: 820 name = linux_to_bsd_ip_sockopt(linux_args.optname); 821 break; 822 case IPPROTO_TCP: 823 /* Linux TCP option values match BSD's */ 824 name = linux_args.optname; 825 break; 826 default: 827 name = -1; 828 break; 829 } 830 if (name == -1) 831 return (EINVAL); 832 833 bsd_args.name = name; 834 bsd_args.val = linux_args.optval; 835 bsd_args.valsize = linux_args.optlen; 836 return (setsockopt(td, &bsd_args)); 837} 838 839struct linux_getsockopt_args { 840 int s; 841 int level; 842 int optname; 843 void *optval; 844 int *optlen; 845}; 846 847static int 848linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 849{ 850 struct linux_getsockopt_args linux_args; 851 struct getsockopt_args /* { 852 int s; 853 int level; 854 int name; 855 caddr_t val; 856 int *avalsize; 857 } */ bsd_args; 858 int error, name; 859 860 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 861 return (error); 862 863 bsd_args.s = linux_args.s; 864 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 865 switch (bsd_args.level) { 866 case SOL_SOCKET: 867 name = linux_to_bsd_so_sockopt(linux_args.optname); 868 break; 869 case IPPROTO_IP: 870 name = linux_to_bsd_ip_sockopt(linux_args.optname); 871 break; 872 case IPPROTO_TCP: 873 /* Linux TCP option values match BSD's */ 874 name = linux_args.optname; 875 break; 876 default: 877 name = -1; 878 break; 879 } 880 if (name == -1) 881 return (EINVAL); 882 883 bsd_args.name = name; 884 bsd_args.val = linux_args.optval; 885 bsd_args.avalsize = linux_args.optlen; 886 return (getsockopt(td, &bsd_args)); 887} 888 889int 890linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 891{ 892 void *arg = (void *)args->args; 893 894 switch (args->what) { 895 case LINUX_SOCKET: 896 return (linux_socket(td, arg)); 897 case LINUX_BIND: 898 return (linux_bind(td, arg)); 899 case LINUX_CONNECT: 900 return (linux_connect(td, arg)); 901 case LINUX_LISTEN: 902 return (linux_listen(td, arg)); 903 case LINUX_ACCEPT: 904 return (linux_accept(td, arg)); 905 case LINUX_GETSOCKNAME: 906 return (linux_getsockname(td, arg)); 907 case LINUX_GETPEERNAME: 908 return (linux_getpeername(td, arg)); 909 case LINUX_SOCKETPAIR: 910 return (linux_socketpair(td, arg)); 911 case LINUX_SEND: 912 return (linux_send(td, arg)); 913 case LINUX_RECV: 914 return (linux_recv(td, arg)); 915 case LINUX_SENDTO: 916 return (linux_sendto(td, arg)); 917 case LINUX_RECVFROM: 918 return (linux_recvfrom(td, arg)); 919 case LINUX_SHUTDOWN: 920 return (linux_shutdown(td, arg)); 921 case LINUX_SETSOCKOPT: 922 return (linux_setsockopt(td, arg)); 923 case LINUX_GETSOCKOPT: 924 return (linux_getsockopt(td, arg)); 925 case LINUX_SENDMSG: 926 do { 927 int error; 928 int level; 929 caddr_t control; 930 struct { 931 int s; 932 const struct msghdr *msg; 933 int flags; 934 } *uap = arg; 935 936 error = copyin(&uap->msg->msg_control, &control, 937 sizeof(caddr_t)); 938 if (error) 939 return (error); 940 941 if (control == NULL) 942 goto done; 943 944 error = copyin(&((struct cmsghdr*)control)->cmsg_level, 945 &level, sizeof(int)); 946 if (error) 947 return (error); 948 949 if (level == 1) { 950 /* 951 * Linux thinks that SOL_SOCKET is 1; we know 952 * that it's really 0xffff, of course. 953 */ 954 level = SOL_SOCKET; 955 error = copyout(&level, 956 &((struct cmsghdr *)control)->cmsg_level, 957 sizeof(int)); 958 if (error) 959 return (error); 960 } 961 done: 962 return (sendmsg(td, arg)); 963 } while (0); 964 case LINUX_RECVMSG: 965 return (linux_recvmsg(td, arg)); 966 } 967 968 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 969 return (ENOSYS); 970} 971#endif /*!__alpha__*/
|