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