linux_socket.c revision 33148
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 withough 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 * $Id: linux_socket.c,v 1.11 1997/12/16 17:40:11 eivind Exp $ 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/socket.h> 44 45#include <netinet/in.h> 46#include <netinet/in_systm.h> 47#include <netinet/ip.h> 48 49#include <i386/linux/linux.h> 50#include <i386/linux/linux_proto.h> 51#include <i386/linux/linux_util.h> 52 53static int 54linux_to_bsd_domain(int domain) 55{ 56 switch (domain) { 57 case LINUX_AF_UNSPEC: 58 return AF_UNSPEC; 59 case LINUX_AF_UNIX: 60 return AF_LOCAL; 61 case LINUX_AF_INET: 62 return AF_INET; 63 case LINUX_AF_AX25: 64 return AF_CCITT; 65 case LINUX_AF_IPX: 66 return AF_IPX; 67 case LINUX_AF_APPLETALK: 68 return AF_APPLETALK; 69 default: 70 return -1; 71 } 72} 73 74static int 75linux_to_bsd_sockopt_level(int level) 76{ 77 switch (level) { 78 case LINUX_SOL_SOCKET: 79 return SOL_SOCKET; 80 default: 81 return level; 82 } 83} 84 85static int linux_to_bsd_ip_sockopt(int opt) 86{ 87 switch (opt) { 88 case LINUX_IP_TOS: 89 return IP_TOS; 90 case LINUX_IP_TTL: 91 return IP_TTL; 92 case LINUX_IP_OPTIONS: 93 return IP_OPTIONS; 94 case LINUX_IP_MULTICAST_IF: 95 return IP_MULTICAST_IF; 96 case LINUX_IP_MULTICAST_TTL: 97 return IP_MULTICAST_TTL; 98 case LINUX_IP_MULTICAST_LOOP: 99 return IP_MULTICAST_LOOP; 100 case LINUX_IP_ADD_MEMBERSHIP: 101 return IP_ADD_MEMBERSHIP; 102 case LINUX_IP_DROP_MEMBERSHIP: 103 return IP_DROP_MEMBERSHIP; 104 case LINUX_IP_HDRINCL: 105 return IP_HDRINCL; 106 default: 107 return -1; 108 } 109} 110 111static int 112linux_to_bsd_so_sockopt(int opt) 113{ 114 switch (opt) { 115 case LINUX_SO_DEBUG: 116 return SO_DEBUG; 117 case LINUX_SO_REUSEADDR: 118 return SO_REUSEADDR; 119 case LINUX_SO_TYPE: 120 return SO_TYPE; 121 case LINUX_SO_ERROR: 122 return SO_ERROR; 123 case LINUX_SO_DONTROUTE: 124 return SO_DONTROUTE; 125 case LINUX_SO_BROADCAST: 126 return SO_BROADCAST; 127 case LINUX_SO_SNDBUF: 128 return SO_SNDBUF; 129 case LINUX_SO_RCVBUF: 130 return SO_RCVBUF; 131 case LINUX_SO_KEEPALIVE: 132 return SO_KEEPALIVE; 133 case LINUX_SO_OOBINLINE: 134 return SO_OOBINLINE; 135 case LINUX_SO_LINGER: 136 return SO_LINGER; 137 case LINUX_SO_PRIORITY: 138 case LINUX_SO_NO_CHECK: 139 default: 140 return -1; 141 } 142} 143 144/* Return 0 if IP_HDRINCL is set of the given socket, not 0 otherwise */ 145static int 146linux_check_hdrincl(struct proc *p, int s) 147{ 148 struct getsockopt_args /* { 149 int s; 150 int level; 151 int name; 152 caddr_t val; 153 int *avalsize; 154 } */ bsd_args; 155 int error; 156 caddr_t sg, val, valsize; 157 int size_val = sizeof val; 158 int optval; 159 160 sg = stackgap_init(); 161 val = stackgap_alloc(&sg, sizeof(int)); 162 valsize = stackgap_alloc(&sg, sizeof(int)); 163 164 if ((error=copyout(&size_val, valsize, sizeof(size_val)))) 165 return error; 166 bsd_args.s = s; 167 bsd_args.level = IPPROTO_IP; 168 bsd_args.name = IP_HDRINCL; 169 bsd_args.val = val; 170 bsd_args.avalsize = (int *)valsize; 171 if ((error=getsockopt(p, &bsd_args))) 172 return error; 173 if ((error=copyin(val, &optval, sizeof(optval)))) 174 return error; 175 return optval == 0; 176} 177 178/* 179 * Updated sendto() when IP_HDRINCL is set: 180 * tweak endian-dependent fields in the IP packet. 181 */ 182static int 183linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args) 184{ 185/* 186 * linux_ip_copysize defines how many bytes we should copy 187 * from the beginning of the IP packet before we customize it for BSD. 188 * It should include all the fields we modify (ip_len and ip_off) 189 * and be as small as possible to minimize copying overhead. 190 */ 191#define linux_ip_copysize 8 192 193 caddr_t sg; 194 struct ip *packet; 195 struct msghdr *msg; 196 struct iovec *iov; 197 198 int error; 199 struct sendmsg_args /* { 200 int s; 201 caddr_t msg; 202 int flags; 203 } */ sendmsg_args; 204 205 /* Check the packet isn't too small before we mess with it */ 206 if (bsd_args->len < linux_ip_copysize) 207 return EINVAL; 208 209 /* 210 * Tweaking the user buffer in place would be bad manners. 211 * We create a corrected IP header with just the needed length, 212 * then use an iovec to glue it to the rest of the user packet 213 * when calling sendmsg(). 214 */ 215 sg = stackgap_init(); 216 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 217 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 218 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 219 220 /* Make a copy of the beginning of the packet to be sent */ 221 if ((error = copyin(bsd_args->buf, (caddr_t)packet, linux_ip_copysize))) 222 return error; 223 224 /* Convert fields from Linux to BSD raw IP socket format */ 225 packet->ip_len = bsd_args->len; 226 packet->ip_off = ntohs(packet->ip_off); 227 228 /* Prepare the msghdr and iovec structures describing the new packet */ 229 msg->msg_name = bsd_args->to; 230 msg->msg_namelen = bsd_args->tolen; 231 msg->msg_iov = iov; 232 msg->msg_iovlen = 2; 233 msg->msg_control = NULL; 234 msg->msg_controllen = 0; 235 msg->msg_flags = 0; 236 iov[0].iov_base = (char *)packet; 237 iov[0].iov_len = linux_ip_copysize; 238 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 239 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 240 241 sendmsg_args.s = bsd_args->s; 242 sendmsg_args.msg = (caddr_t)msg; 243 sendmsg_args.flags = bsd_args->flags; 244 return sendmsg(p, &sendmsg_args); 245} 246 247struct linux_socket_args { 248 int domain; 249 int type; 250 int protocol; 251}; 252 253static int 254linux_socket(struct proc *p, struct linux_socket_args *args) 255{ 256 struct linux_socket_args linux_args; 257 struct socket_args /* { 258 int domain; 259 int type; 260 int protocol; 261 } */ bsd_args; 262 int error; 263 int retval_socket; 264 265 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 266 return error; 267 bsd_args.protocol = linux_args.protocol; 268 bsd_args.type = linux_args.type; 269 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 270 if (bsd_args.domain == -1) 271 return EINVAL; 272 273 retval_socket = socket(p, &bsd_args); 274 if (bsd_args.type == SOCK_RAW 275 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 276 && bsd_args.domain == AF_INET 277 && retval_socket >= 0) { 278 /* It's a raw IP socket: set the IP_HDRINCL option. */ 279 struct setsockopt_args /* { 280 int s; 281 int level; 282 int name; 283 caddr_t val; 284 int valsize; 285 } */ bsd_setsockopt_args; 286 caddr_t sg; 287 int *hdrincl; 288 289 sg = stackgap_init(); 290 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 291 *hdrincl = 1; 292 bsd_setsockopt_args.s = p->p_retval[0]; 293 bsd_setsockopt_args.level = IPPROTO_IP; 294 bsd_setsockopt_args.name = IP_HDRINCL; 295 bsd_setsockopt_args.val = (caddr_t)hdrincl; 296 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 297 /* We ignore any error returned by setsockopt() */ 298 setsockopt(p, &bsd_setsockopt_args); 299 /* Copy back the return value from socket() */ 300 p->p_retval[0] = bsd_setsockopt_args.s; 301 } 302 return retval_socket; 303} 304 305struct linux_bind_args { 306 int s; 307 struct sockaddr *name; 308 int namelen; 309}; 310 311static int 312linux_bind(struct proc *p, struct linux_bind_args *args) 313{ 314 struct linux_bind_args linux_args; 315 struct bind_args /* { 316 int s; 317 caddr_t name; 318 int namelen; 319 } */ bsd_args; 320 int error; 321 322 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 323 return error; 324 bsd_args.s = linux_args.s; 325 bsd_args.name = (caddr_t)linux_args.name; 326 bsd_args.namelen = linux_args.namelen; 327 return bind(p, &bsd_args); 328} 329 330struct linux_connect_args { 331 int s; 332 struct sockaddr * name; 333 int namelen; 334}; 335 336static int 337linux_connect(struct proc *p, struct linux_connect_args *args) 338{ 339 struct linux_connect_args linux_args; 340 struct connect_args /* { 341 int s; 342 caddr_t name; 343 int namelen; 344 } */ bsd_args; 345 int error; 346 347 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 348 return error; 349 bsd_args.s = linux_args.s; 350 bsd_args.name = (caddr_t)linux_args.name; 351 bsd_args.namelen = linux_args.namelen; 352 error = connect(p, &bsd_args); 353 if (error == EISCONN) { 354 /* 355 * Linux doesn't return EISCONN the first time it occurs, 356 * when on a non-blocking socket. Instead it returns the 357 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 358 */ 359 struct fcntl_args /* { 360 int fd; 361 int cmd; 362 int arg; 363 } */ bsd_fcntl_args; 364 struct getsockopt_args /* { 365 int s; 366 int level; 367 int name; 368 caddr_t val; 369 int *avalsize; 370 } */ bsd_getsockopt_args; 371 void *status, *statusl; 372 int stat, statl = sizeof stat; 373 caddr_t sg; 374 375 /* Check for non-blocking */ 376 bsd_fcntl_args.fd = linux_args.s; 377 bsd_fcntl_args.cmd = F_GETFL; 378 bsd_fcntl_args.arg = 0; 379 error = fcntl(p, &bsd_fcntl_args); 380 if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) { 381 sg = stackgap_init(); 382 status = stackgap_alloc(&sg, sizeof stat); 383 statusl = stackgap_alloc(&sg, sizeof statusl); 384 385 if ((error = copyout(&statl, statusl, sizeof statl))) 386 return error; 387 388 bsd_getsockopt_args.s = linux_args.s; 389 bsd_getsockopt_args.level = SOL_SOCKET; 390 bsd_getsockopt_args.name = SO_ERROR; 391 bsd_getsockopt_args.val = status; 392 bsd_getsockopt_args.avalsize = statusl; 393 394 error = getsockopt(p, &bsd_getsockopt_args); 395 if (error) 396 return error; 397 if ((error = copyin(status, &stat, sizeof stat))) 398 return error; 399 p->p_retval[0] = stat; 400 return 0; 401 } 402 } 403 return error; 404} 405 406struct linux_listen_args { 407 int s; 408 int backlog; 409}; 410 411static int 412linux_listen(struct proc *p, struct linux_listen_args *args) 413{ 414 struct linux_listen_args linux_args; 415 struct listen_args /* { 416 int s; 417 int backlog; 418 } */ bsd_args; 419 int error; 420 421 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 422 return error; 423 bsd_args.s = linux_args.s; 424 bsd_args.backlog = linux_args.backlog; 425 return listen(p, &bsd_args); 426} 427 428struct linux_accept_args { 429 int s; 430 struct sockaddr *addr; 431 int *namelen; 432}; 433 434static int 435linux_accept(struct proc *p, struct linux_accept_args *args) 436{ 437 struct linux_accept_args linux_args; 438 struct accept_args /* { 439 int s; 440 caddr_t name; 441 int *anamelen; 442 } */ bsd_args; 443 int error; 444 445 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 446 return error; 447 bsd_args.s = linux_args.s; 448 bsd_args.name = (caddr_t)linux_args.addr; 449 bsd_args.anamelen = linux_args.namelen; 450 return oaccept(p, &bsd_args); 451} 452 453struct linux_getsockname_args { 454 int s; 455 struct sockaddr *addr; 456 int *namelen; 457}; 458 459static int 460linux_getsockname(struct proc *p, struct linux_getsockname_args *args) 461{ 462 struct linux_getsockname_args linux_args; 463 struct getsockname_args /* { 464 int fdes; 465 caddr_t asa; 466 int *alen; 467 } */ bsd_args; 468 int error; 469 470 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 471 return error; 472 bsd_args.fdes = linux_args.s; 473 bsd_args.asa = (caddr_t) linux_args.addr; 474 bsd_args.alen = linux_args.namelen; 475 return ogetsockname(p, &bsd_args); 476} 477 478struct linux_getpeername_args { 479 int s; 480 struct sockaddr *addr; 481 int *namelen; 482}; 483 484static int 485linux_getpeername(struct proc *p, struct linux_getpeername_args *args) 486{ 487 struct linux_getpeername_args linux_args; 488 struct ogetpeername_args /* { 489 int fdes; 490 caddr_t asa; 491 int *alen; 492 } */ bsd_args; 493 int error; 494 495 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 496 return error; 497 bsd_args.fdes = linux_args.s; 498 bsd_args.asa = (caddr_t) linux_args.addr; 499 bsd_args.alen = linux_args.namelen; 500 return ogetpeername(p, &bsd_args); 501} 502 503struct linux_socketpair_args { 504 int domain; 505 int type; 506 int protocol; 507 int *rsv; 508}; 509 510static int 511linux_socketpair(struct proc *p, struct linux_socketpair_args *args) 512{ 513 struct linux_socketpair_args linux_args; 514 struct socketpair_args /* { 515 int domain; 516 int type; 517 int protocol; 518 int *rsv; 519 } */ bsd_args; 520 int error; 521 522 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 523 return error; 524 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 525 if (bsd_args.domain == -1) 526 return EINVAL; 527 bsd_args.type = linux_args.type; 528 bsd_args.protocol = linux_args.protocol; 529 bsd_args.rsv = linux_args.rsv; 530 return socketpair(p, &bsd_args); 531} 532 533struct linux_send_args { 534 int s; 535 void *msg; 536 int len; 537 int flags; 538}; 539 540static int 541linux_send(struct proc *p, struct linux_send_args *args) 542{ 543 struct linux_send_args linux_args; 544 struct osend_args /* { 545 int s; 546 caddr_t buf; 547 int len; 548 int flags; 549 } */ bsd_args; 550 int error; 551 552 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 553 return error; 554 bsd_args.s = linux_args.s; 555 bsd_args.buf = linux_args.msg; 556 bsd_args.len = linux_args.len; 557 bsd_args.flags = linux_args.flags; 558 return osend(p, &bsd_args); 559} 560 561struct linux_recv_args { 562 int s; 563 void *msg; 564 int len; 565 int flags; 566}; 567 568static int 569linux_recv(struct proc *p, struct linux_recv_args *args) 570{ 571 struct linux_recv_args linux_args; 572 struct orecv_args /* { 573 int s; 574 caddr_t buf; 575 int len; 576 int flags; 577 } */ bsd_args; 578 int error; 579 580 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 581 return error; 582 bsd_args.s = linux_args.s; 583 bsd_args.buf = linux_args.msg; 584 bsd_args.len = linux_args.len; 585 bsd_args.flags = linux_args.flags; 586 return orecv(p, &bsd_args); 587} 588 589struct linux_sendto_args { 590 int s; 591 void *msg; 592 int len; 593 int flags; 594 caddr_t to; 595 int tolen; 596}; 597 598static int 599linux_sendto(struct proc *p, struct linux_sendto_args *args) 600{ 601 struct linux_sendto_args linux_args; 602 struct sendto_args /* { 603 int s; 604 caddr_t buf; 605 size_t len; 606 int flags; 607 caddr_t to; 608 int tolen; 609 } */ bsd_args; 610 int error; 611 612 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 613 return error; 614 bsd_args.s = linux_args.s; 615 bsd_args.buf = linux_args.msg; 616 bsd_args.len = linux_args.len; 617 bsd_args.flags = linux_args.flags; 618 bsd_args.to = linux_args.to; 619 bsd_args.tolen = linux_args.tolen; 620 621 if (linux_check_hdrincl(p, linux_args.s) == 0) 622 /* IP_HDRINCL set, tweak the packet before sending */ 623 return linux_sendto_hdrincl(p, &bsd_args); 624 625 return sendto(p, &bsd_args); 626} 627 628struct linux_recvfrom_args { 629 int s; 630 void *buf; 631 int len; 632 int flags; 633 caddr_t from; 634 int *fromlen; 635}; 636 637static int 638linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args) 639{ 640 struct linux_recvfrom_args linux_args; 641 struct recvfrom_args /* { 642 int s; 643 caddr_t buf; 644 size_t len; 645 int flags; 646 caddr_t from; 647 int *fromlenaddr; 648 } */ bsd_args; 649 int error; 650 651 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 652 return error; 653 bsd_args.s = linux_args.s; 654 bsd_args.buf = linux_args.buf; 655 bsd_args.len = linux_args.len; 656 bsd_args.flags = linux_args.flags; 657 bsd_args.from = linux_args.from; 658 bsd_args.fromlenaddr = linux_args.fromlen; 659 return orecvfrom(p, &bsd_args); 660} 661 662struct linux_shutdown_args { 663 int s; 664 int how; 665}; 666 667static int 668linux_shutdown(struct proc *p, struct linux_shutdown_args *args) 669{ 670 struct linux_shutdown_args linux_args; 671 struct shutdown_args /* { 672 int s; 673 int how; 674 } */ bsd_args; 675 int error; 676 677 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 678 return error; 679 bsd_args.s = linux_args.s; 680 bsd_args.how = linux_args.how; 681 return shutdown(p, &bsd_args); 682} 683 684struct linux_setsockopt_args { 685 int s; 686 int level; 687 int optname; 688 void *optval; 689 int optlen; 690}; 691 692static int 693linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) 694{ 695 struct linux_setsockopt_args linux_args; 696 struct setsockopt_args /* { 697 int s; 698 int level; 699 int name; 700 caddr_t val; 701 int valsize; 702 } */ bsd_args; 703 int error, name; 704 705 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 706 return error; 707 bsd_args.s = linux_args.s; 708 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 709 switch (bsd_args.level) { 710 case SOL_SOCKET: 711 name = linux_to_bsd_so_sockopt(linux_args.optname); 712 break; 713 case IPPROTO_IP: 714 name = linux_to_bsd_ip_sockopt(linux_args.optname); 715 break; 716 case IPPROTO_TCP: 717 /* Linux TCP option values match BSD's */ 718 name = linux_args.optname; 719 break; 720 default: 721 return EINVAL; 722 } 723 if (name == -1) 724 return EINVAL; 725 bsd_args.name = name; 726 bsd_args.val = linux_args.optval; 727 bsd_args.valsize = linux_args.optlen; 728 return setsockopt(p, &bsd_args); 729} 730 731struct linux_getsockopt_args { 732 int s; 733 int level; 734 int optname; 735 void *optval; 736 int *optlen; 737}; 738 739static int 740linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) 741{ 742 struct linux_getsockopt_args linux_args; 743 struct getsockopt_args /* { 744 int s; 745 int level; 746 int name; 747 caddr_t val; 748 int *avalsize; 749 } */ bsd_args; 750 int error, name; 751 752 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 753 return error; 754 bsd_args.s = linux_args.s; 755 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 756 switch (bsd_args.level) { 757 case SOL_SOCKET: 758 name = linux_to_bsd_so_sockopt(linux_args.optname); 759 break; 760 case IPPROTO_IP: 761 name = linux_to_bsd_ip_sockopt(linux_args.optname); 762 break; 763 case IPPROTO_TCP: 764 /* Linux TCP option values match BSD's */ 765 name = linux_args.optname; 766 break; 767 default: 768 return EINVAL; 769 } 770 if (name == -1) 771 return EINVAL; 772 bsd_args.name = name; 773 bsd_args.val = linux_args.optval; 774 bsd_args.avalsize = linux_args.optlen; 775 return getsockopt(p, &bsd_args); 776} 777 778int 779linux_socketcall(struct proc *p, struct linux_socketcall_args *args) 780{ 781 switch (args->what) { 782 case LINUX_SOCKET: 783 return linux_socket(p, args->args); 784 case LINUX_BIND: 785 return linux_bind(p, args->args); 786 case LINUX_CONNECT: 787 return linux_connect(p, args->args); 788 case LINUX_LISTEN: 789 return linux_listen(p, args->args); 790 case LINUX_ACCEPT: 791 return linux_accept(p, args->args); 792 case LINUX_GETSOCKNAME: 793 return linux_getsockname(p, args->args); 794 case LINUX_GETPEERNAME: 795 return linux_getpeername(p, args->args); 796 case LINUX_SOCKETPAIR: 797 return linux_socketpair(p, args->args); 798 case LINUX_SEND: 799 return linux_send(p, args->args); 800 case LINUX_RECV: 801 return linux_recv(p, args->args); 802 case LINUX_SENDTO: 803 return linux_sendto(p, args->args); 804 case LINUX_RECVFROM: 805 return linux_recvfrom(p, args->args); 806 case LINUX_SHUTDOWN: 807 return linux_shutdown(p, args->args); 808 case LINUX_SETSOCKOPT: 809 return linux_setsockopt(p, args->args); 810 case LINUX_GETSOCKOPT: 811 return linux_getsockopt(p, args->args); 812 default: 813 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 814 return ENOSYS; 815 } 816} 817