linux_socket.c revision 83221
11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1995 S�ren Schmidt 31558Srgrimes * All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer 101558Srgrimes * in this position and unchanged. 111558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer in the 131558Srgrimes * documentation and/or other materials provided with the distribution. 141558Srgrimes * 3. The name of the author may not be used to endorse or promote products 151558Srgrimes * derived from this software withough specific prior written permission 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 181558Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 191558Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 201558Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 211558Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 221558Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231558Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241558Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251558Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 261558Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271558Srgrimes * 281558Srgrimes * $FreeBSD: head/sys/compat/linux/linux_socket.c 83221 2001-09-08 19:07:04Z marcel $ 291558Srgrimes */ 301558Srgrimes 311558Srgrimes/* XXX we use functions that might not exist. */ 321558Srgrimes#include "opt_compat.h" 331558Srgrimes 341558Srgrimes#ifndef COMPAT_43 351558Srgrimes#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 361558Srgrimes#endif 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/proc.h> 401558Srgrimes#include <sys/systm.h> 411558Srgrimes#include <sys/sysproto.h> 421558Srgrimes#include <sys/fcntl.h> 431558Srgrimes#include <sys/file.h> 441558Srgrimes#include <sys/socket.h> 451558Srgrimes#include <sys/socketvar.h> 461558Srgrimes#include <sys/uio.h> 471558Srgrimes 481558Srgrimes#include <netinet/in.h> 491558Srgrimes#include <netinet/in_systm.h> 501558Srgrimes#include <netinet/ip.h> 511558Srgrimes 521558Srgrimes#include <machine/../linux/linux.h> 531558Srgrimes#include <machine/../linux/linux_proto.h> 541558Srgrimes#include <compat/linux/linux_socket.h> 551558Srgrimes#include <compat/linux/linux_util.h> 561558Srgrimes 571558Srgrimes#ifndef __alpha__ 581558Srgrimesstatic int 591558Srgrimeslinux_to_bsd_domain(int domain) 601558Srgrimes{ 611558Srgrimes 621558Srgrimes switch (domain) { 631558Srgrimes case LINUX_AF_UNSPEC: 641558Srgrimes return (AF_UNSPEC); 651558Srgrimes case LINUX_AF_UNIX: 661558Srgrimes return (AF_LOCAL); 671558Srgrimes case LINUX_AF_INET: 681558Srgrimes return (AF_INET); 691558Srgrimes case LINUX_AF_AX25: 701558Srgrimes return (AF_CCITT); 711558Srgrimes case LINUX_AF_IPX: 721558Srgrimes return (AF_IPX); 731558Srgrimes case LINUX_AF_APPLETALK: 741558Srgrimes return (AF_APPLETALK); 751558Srgrimes } 761558Srgrimes return (-1); 771558Srgrimes} 781558Srgrimes 791558Srgrimesstatic int 801558Srgrimeslinux_to_bsd_sockopt_level(int level) 811558Srgrimes{ 821558Srgrimes 831558Srgrimes switch (level) { 841558Srgrimes case LINUX_SOL_SOCKET: 851558Srgrimes return (SOL_SOCKET); 861558Srgrimes } 871558Srgrimes return (level); 881558Srgrimes} 891558Srgrimes 901558Srgrimesstatic int 911558Srgrimeslinux_to_bsd_ip_sockopt(int opt) 921558Srgrimes{ 931558Srgrimes 941558Srgrimes switch (opt) { 951558Srgrimes case LINUX_IP_TOS: 961558Srgrimes return (IP_TOS); 971558Srgrimes case LINUX_IP_TTL: 981558Srgrimes return (IP_TTL); 991558Srgrimes case LINUX_IP_OPTIONS: 1001558Srgrimes return (IP_OPTIONS); 1011558Srgrimes case LINUX_IP_MULTICAST_IF: 1021558Srgrimes return (IP_MULTICAST_IF); 1031558Srgrimes case LINUX_IP_MULTICAST_TTL: 1041558Srgrimes return (IP_MULTICAST_TTL); 1051558Srgrimes case LINUX_IP_MULTICAST_LOOP: 1061558Srgrimes return (IP_MULTICAST_LOOP); 1071558Srgrimes case LINUX_IP_ADD_MEMBERSHIP: 1081558Srgrimes return (IP_ADD_MEMBERSHIP); 1091558Srgrimes case LINUX_IP_DROP_MEMBERSHIP: 1101558Srgrimes return (IP_DROP_MEMBERSHIP); 1111558Srgrimes case LINUX_IP_HDRINCL: 1121558Srgrimes return (IP_HDRINCL); 1131558Srgrimes } 1141558Srgrimes return (-1); 1151558Srgrimes} 1161558Srgrimes 1171558Srgrimesstatic int 1181558Srgrimeslinux_to_bsd_so_sockopt(int opt) 1191558Srgrimes{ 1201558Srgrimes 1211558Srgrimes switch (opt) { 1221558Srgrimes case LINUX_SO_DEBUG: 1231558Srgrimes return (SO_DEBUG); 1241558Srgrimes case LINUX_SO_REUSEADDR: 1251558Srgrimes return (SO_REUSEADDR); 1261558Srgrimes case LINUX_SO_TYPE: 1271558Srgrimes return (SO_TYPE); 1281558Srgrimes case LINUX_SO_ERROR: 1291558Srgrimes return (SO_ERROR); 1301558Srgrimes case LINUX_SO_DONTROUTE: 1311558Srgrimes return (SO_DONTROUTE); 1321558Srgrimes case LINUX_SO_BROADCAST: 1331558Srgrimes return (SO_BROADCAST); 1341558Srgrimes case LINUX_SO_SNDBUF: 1351558Srgrimes return (SO_SNDBUF); 1361558Srgrimes case LINUX_SO_RCVBUF: 1371558Srgrimes return (SO_RCVBUF); 1381558Srgrimes case LINUX_SO_KEEPALIVE: 1391558Srgrimes return (SO_KEEPALIVE); 1401558Srgrimes case LINUX_SO_OOBINLINE: 1411558Srgrimes return (SO_OOBINLINE); 1421558Srgrimes case LINUX_SO_LINGER: 1431558Srgrimes return (SO_LINGER); 1441558Srgrimes } 1451558Srgrimes return (-1); 1461558Srgrimes} 1471558Srgrimes 1481558Srgrimesstatic int 1491558Srgrimeslinux_to_bsd_msg_flags(int flags) 1501558Srgrimes{ 1511558Srgrimes int ret_flags = 0; 1521558Srgrimes 1531558Srgrimes if (flags & LINUX_MSG_OOB) 1541558Srgrimes ret_flags |= MSG_OOB; 1551558Srgrimes if (flags & LINUX_MSG_PEEK) 1561558Srgrimes ret_flags |= MSG_PEEK; 1571558Srgrimes if (flags & LINUX_MSG_DONTROUTE) 1581558Srgrimes ret_flags |= MSG_DONTROUTE; 1591558Srgrimes if (flags & LINUX_MSG_CTRUNC) 1601558Srgrimes ret_flags |= MSG_CTRUNC; 1611558Srgrimes if (flags & LINUX_MSG_TRUNC) 1621558Srgrimes ret_flags |= MSG_TRUNC; 1631558Srgrimes if (flags & LINUX_MSG_DONTWAIT) 1641558Srgrimes ret_flags |= MSG_DONTWAIT; 1651558Srgrimes if (flags & LINUX_MSG_EOR) 1661558Srgrimes ret_flags |= MSG_EOR; 1671558Srgrimes if (flags & LINUX_MSG_WAITALL) 1681558Srgrimes ret_flags |= MSG_WAITALL; 1691558Srgrimes#if 0 /* not handled */ 1701558Srgrimes if (flags & LINUX_MSG_PROXY) 1711558Srgrimes ; 1721558Srgrimes if (flags & LINUX_MSG_FIN) 1731558Srgrimes ; 1741558Srgrimes if (flags & LINUX_MSG_SYN) 1751558Srgrimes ; 1761558Srgrimes if (flags & LINUX_MSG_CONFIRM) 1771558Srgrimes ; 1781558Srgrimes if (flags & LINUX_MSG_RST) 1791558Srgrimes ; 1801558Srgrimes if (flags & LINUX_MSG_ERRQUEUE) 1811558Srgrimes ; 1821558Srgrimes if (flags & LINUX_MSG_NOSIGNAL) 1831558Srgrimes ; 1841558Srgrimes#endif 1851558Srgrimes return ret_flags; 1861558Srgrimes} 1871558Srgrimes 1881558Srgrimes/* Return 0 if IP_HDRINCL is set for the given socket. */ 1891558Srgrimesstatic int 1901558Srgrimeslinux_check_hdrincl(struct proc *p, int s) 1911558Srgrimes{ 1921558Srgrimes struct getsockopt_args /* { 1931558Srgrimes int s; 1941558Srgrimes int level; 1951558Srgrimes int name; 1961558Srgrimes caddr_t val; 1971558Srgrimes int *avalsize; 1981558Srgrimes } */ bsd_args; 1991558Srgrimes int error; 2001558Srgrimes caddr_t sg, val, valsize; 2011558Srgrimes int size_val = sizeof val; 2021558Srgrimes int optval; 2031558Srgrimes 2041558Srgrimes sg = stackgap_init(); 2051558Srgrimes val = stackgap_alloc(&sg, sizeof(int)); 2061558Srgrimes valsize = stackgap_alloc(&sg, sizeof(int)); 2071558Srgrimes 2081558Srgrimes if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 2091558Srgrimes return (error); 2101558Srgrimes 2111558Srgrimes bsd_args.s = s; 2121558Srgrimes bsd_args.level = IPPROTO_IP; 2131558Srgrimes bsd_args.name = IP_HDRINCL; 2141558Srgrimes bsd_args.val = val; 2151558Srgrimes bsd_args.avalsize = (int *)valsize; 2161558Srgrimes if ((error = getsockopt(p, &bsd_args))) 2171558Srgrimes return (error); 2181558Srgrimes 2191558Srgrimes if ((error = copyin(val, &optval, sizeof(optval)))) 2201558Srgrimes return (error); 2211558Srgrimes 2221558Srgrimes return (optval == 0); 2231558Srgrimes} 2241558Srgrimes 2251558Srgrimes/* 2261558Srgrimes * Updated sendto() when IP_HDRINCL is set: 2271558Srgrimes * tweak endian-dependent fields in the IP packet. 2281558Srgrimes */ 2291558Srgrimesstatic int 2301558Srgrimeslinux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args) 2311558Srgrimes{ 2321558Srgrimes/* 2331558Srgrimes * linux_ip_copysize defines how many bytes we should copy 2341558Srgrimes * from the beginning of the IP packet before we customize it for BSD. 2351558Srgrimes * It should include all the fields we modify (ip_len and ip_off) 2361558Srgrimes * and be as small as possible to minimize copying overhead. 2371558Srgrimes */ 2381558Srgrimes#define linux_ip_copysize 8 2391558Srgrimes 2401558Srgrimes caddr_t sg; 2411558Srgrimes struct ip *packet; 2421558Srgrimes struct msghdr *msg; 2431558Srgrimes struct iovec *iov; 2441558Srgrimes 2451558Srgrimes int error; 2461558Srgrimes struct sendmsg_args /* { 2471558Srgrimes int s; 2481558Srgrimes caddr_t msg; 2491558Srgrimes int flags; 2501558Srgrimes } */ sendmsg_args; 2511558Srgrimes 2521558Srgrimes /* Check the packet isn't too small before we mess with it */ 2531558Srgrimes if (bsd_args->len < linux_ip_copysize) 2541558Srgrimes return (EINVAL); 2551558Srgrimes 2561558Srgrimes /* 2571558Srgrimes * Tweaking the user buffer in place would be bad manners. 2581558Srgrimes * We create a corrected IP header with just the needed length, 2591558Srgrimes * then use an iovec to glue it to the rest of the user packet 2601558Srgrimes * when calling sendmsg(). 2611558Srgrimes */ 2621558Srgrimes sg = stackgap_init(); 2631558Srgrimes packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 2641558Srgrimes msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 2651558Srgrimes iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 2661558Srgrimes 2671558Srgrimes /* Make a copy of the beginning of the packet to be sent */ 2681558Srgrimes if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize))) 2691558Srgrimes return (error); 2701558Srgrimes 2711558Srgrimes /* Convert fields from Linux to BSD raw IP socket format */ 2721558Srgrimes packet->ip_len = bsd_args->len; 2731558Srgrimes packet->ip_off = ntohs(packet->ip_off); 2741558Srgrimes 2751558Srgrimes /* Prepare the msghdr and iovec structures describing the new packet */ 2761558Srgrimes msg->msg_name = bsd_args->to; 2771558Srgrimes msg->msg_namelen = bsd_args->tolen; 2781558Srgrimes msg->msg_iov = iov; 2791558Srgrimes msg->msg_iovlen = 2; 2801558Srgrimes msg->msg_control = NULL; 2811558Srgrimes msg->msg_controllen = 0; 2821558Srgrimes msg->msg_flags = 0; 2831558Srgrimes iov[0].iov_base = (char *)packet; 2841558Srgrimes iov[0].iov_len = linux_ip_copysize; 285 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 286 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 287 288 sendmsg_args.s = bsd_args->s; 289 sendmsg_args.msg = (caddr_t)msg; 290 sendmsg_args.flags = bsd_args->flags; 291 return (sendmsg(p, &sendmsg_args)); 292} 293 294struct linux_socket_args { 295 int domain; 296 int type; 297 int protocol; 298}; 299 300static int 301linux_socket(struct proc *p, struct linux_socket_args *args) 302{ 303 struct linux_socket_args linux_args; 304 struct socket_args /* { 305 int domain; 306 int type; 307 int protocol; 308 } */ bsd_args; 309 int error; 310 int retval_socket; 311 312 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 313 return (error); 314 315 bsd_args.protocol = linux_args.protocol; 316 bsd_args.type = linux_args.type; 317 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 318 if (bsd_args.domain == -1) 319 return (EINVAL); 320 321 retval_socket = socket(p, &bsd_args); 322 if (bsd_args.type == SOCK_RAW 323 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 324 && bsd_args.domain == AF_INET 325 && retval_socket >= 0) { 326 /* It's a raw IP socket: set the IP_HDRINCL option. */ 327 struct setsockopt_args /* { 328 int s; 329 int level; 330 int name; 331 caddr_t val; 332 int valsize; 333 } */ bsd_setsockopt_args; 334 caddr_t sg; 335 int *hdrincl; 336 337 sg = stackgap_init(); 338 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 339 *hdrincl = 1; 340 bsd_setsockopt_args.s = p->p_retval[0]; 341 bsd_setsockopt_args.level = IPPROTO_IP; 342 bsd_setsockopt_args.name = IP_HDRINCL; 343 bsd_setsockopt_args.val = (caddr_t)hdrincl; 344 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 345 /* We ignore any error returned by setsockopt() */ 346 setsockopt(p, &bsd_setsockopt_args); 347 /* Copy back the return value from socket() */ 348 p->p_retval[0] = bsd_setsockopt_args.s; 349 } 350 351 return (retval_socket); 352} 353 354struct linux_bind_args { 355 int s; 356 struct sockaddr *name; 357 int namelen; 358}; 359 360static int 361linux_bind(struct proc *p, struct linux_bind_args *args) 362{ 363 struct linux_bind_args linux_args; 364 struct bind_args /* { 365 int s; 366 caddr_t name; 367 int namelen; 368 } */ bsd_args; 369 int error; 370 371 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 372 return (error); 373 374 bsd_args.s = linux_args.s; 375 bsd_args.name = (caddr_t)linux_args.name; 376 bsd_args.namelen = linux_args.namelen; 377 return (bind(p, &bsd_args)); 378} 379 380struct linux_connect_args { 381 int s; 382 struct sockaddr * name; 383 int namelen; 384}; 385int linux_connect(struct proc *, struct linux_connect_args *); 386#endif /* !__alpha__*/ 387 388int 389linux_connect(struct proc *p, struct linux_connect_args *args) 390{ 391 struct linux_connect_args linux_args; 392 struct connect_args /* { 393 int s; 394 caddr_t name; 395 int namelen; 396 } */ bsd_args; 397 struct socket *so; 398 struct file *fp; 399 int error; 400 401#ifdef __alpha__ 402 bcopy(args, &linux_args, sizeof(linux_args)); 403#else 404 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 405 return (error); 406#endif /* __alpha__ */ 407 408 bsd_args.s = linux_args.s; 409 bsd_args.name = (caddr_t)linux_args.name; 410 bsd_args.namelen = linux_args.namelen; 411 error = connect(p, &bsd_args); 412 if (error != EISCONN) 413 return (error); 414 415 /* 416 * Linux doesn't return EISCONN the first time it occurs, 417 * when on a non-blocking socket. Instead it returns the 418 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 419 */ 420 error = holdsock(p->p_fd, linux_args.s, &fp); 421 if (error) 422 return (error); 423 error = EISCONN; 424 if (fp->f_flag & FNONBLOCK) { 425 so = (struct socket *)fp->f_data; 426 if (so->so_emuldata == 0) 427 error = so->so_error; 428 so->so_emuldata = (void *)1; 429 } 430 fdrop(fp, p); 431 return (error); 432} 433 434#ifndef __alpha__ 435 436struct linux_listen_args { 437 int s; 438 int backlog; 439}; 440 441static int 442linux_listen(struct proc *p, struct linux_listen_args *args) 443{ 444 struct linux_listen_args linux_args; 445 struct listen_args /* { 446 int s; 447 int backlog; 448 } */ bsd_args; 449 int error; 450 451 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 452 return (error); 453 454 bsd_args.s = linux_args.s; 455 bsd_args.backlog = linux_args.backlog; 456 return (listen(p, &bsd_args)); 457} 458 459struct linux_accept_args { 460 int s; 461 struct sockaddr *addr; 462 int *namelen; 463}; 464 465static int 466linux_accept(struct proc *p, struct linux_accept_args *args) 467{ 468 struct linux_accept_args linux_args; 469 struct accept_args /* { 470 int s; 471 caddr_t name; 472 int *anamelen; 473 } */ bsd_args; 474 struct fcntl_args /* { 475 int fd; 476 int cmd; 477 long arg; 478 } */ f_args; 479 int error; 480 481 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 482 return (error); 483 484 bsd_args.s = linux_args.s; 485 bsd_args.name = (caddr_t)linux_args.addr; 486 bsd_args.anamelen = linux_args.namelen; 487 error = oaccept(p, &bsd_args); 488 if (error) 489 return (error); 490 491 /* 492 * linux appears not to copy flags from the parent socket to the 493 * accepted one, so we must clear the flags in the new descriptor. 494 * Ignore any errors, because we already have an open fd. 495 */ 496 f_args.fd = p->p_retval[0]; 497 f_args.cmd = F_SETFL; 498 f_args.arg = 0; 499 (void)fcntl(p, &f_args); 500 p->p_retval[0] = f_args.fd; 501 return (0); 502} 503 504struct linux_getsockname_args { 505 int s; 506 struct sockaddr *addr; 507 int *namelen; 508}; 509 510static int 511linux_getsockname(struct proc *p, struct linux_getsockname_args *args) 512{ 513 struct linux_getsockname_args linux_args; 514 struct getsockname_args /* { 515 int fdes; 516 caddr_t asa; 517 int *alen; 518 } */ bsd_args; 519 int error; 520 521 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 522 return (error); 523 524 bsd_args.fdes = linux_args.s; 525 bsd_args.asa = (caddr_t) linux_args.addr; 526 bsd_args.alen = linux_args.namelen; 527 return (ogetsockname(p, &bsd_args)); 528} 529 530struct linux_getpeername_args { 531 int s; 532 struct sockaddr *addr; 533 int *namelen; 534}; 535 536static int 537linux_getpeername(struct proc *p, struct linux_getpeername_args *args) 538{ 539 struct linux_getpeername_args linux_args; 540 struct ogetpeername_args /* { 541 int fdes; 542 caddr_t asa; 543 int *alen; 544 } */ bsd_args; 545 int error; 546 547 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 548 return (error); 549 550 bsd_args.fdes = linux_args.s; 551 bsd_args.asa = (caddr_t) linux_args.addr; 552 bsd_args.alen = linux_args.namelen; 553 return (ogetpeername(p, &bsd_args)); 554} 555 556struct linux_socketpair_args { 557 int domain; 558 int type; 559 int protocol; 560 int *rsv; 561}; 562 563static int 564linux_socketpair(struct proc *p, struct linux_socketpair_args *args) 565{ 566 struct linux_socketpair_args linux_args; 567 struct socketpair_args /* { 568 int domain; 569 int type; 570 int protocol; 571 int *rsv; 572 } */ bsd_args; 573 int error; 574 575 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 576 return (error); 577 578 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 579 if (bsd_args.domain == -1) 580 return (EINVAL); 581 582 bsd_args.type = linux_args.type; 583 bsd_args.protocol = linux_args.protocol; 584 bsd_args.rsv = linux_args.rsv; 585 return (socketpair(p, &bsd_args)); 586} 587 588struct linux_send_args { 589 int s; 590 void *msg; 591 int len; 592 int flags; 593}; 594 595static int 596linux_send(struct proc *p, struct linux_send_args *args) 597{ 598 struct linux_send_args linux_args; 599 struct osend_args /* { 600 int s; 601 caddr_t buf; 602 int len; 603 int flags; 604 } */ bsd_args; 605 int error; 606 607 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 608 return (error); 609 610 bsd_args.s = linux_args.s; 611 bsd_args.buf = linux_args.msg; 612 bsd_args.len = linux_args.len; 613 bsd_args.flags = linux_args.flags; 614 return (osend(p, &bsd_args)); 615} 616 617struct linux_recv_args { 618 int s; 619 void *msg; 620 int len; 621 int flags; 622}; 623 624static int 625linux_recv(struct proc *p, struct linux_recv_args *args) 626{ 627 struct linux_recv_args linux_args; 628 struct orecv_args /* { 629 int s; 630 caddr_t buf; 631 int len; 632 int flags; 633 } */ bsd_args; 634 int error; 635 636 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 637 return (error); 638 639 bsd_args.s = linux_args.s; 640 bsd_args.buf = linux_args.msg; 641 bsd_args.len = linux_args.len; 642 bsd_args.flags = linux_args.flags; 643 return (orecv(p, &bsd_args)); 644} 645 646struct linux_sendto_args { 647 int s; 648 void *msg; 649 int len; 650 int flags; 651 caddr_t to; 652 int tolen; 653}; 654 655static int 656linux_sendto(struct proc *p, struct linux_sendto_args *args) 657{ 658 struct linux_sendto_args linux_args; 659 struct sendto_args /* { 660 int s; 661 caddr_t buf; 662 size_t len; 663 int flags; 664 caddr_t to; 665 int tolen; 666 } */ bsd_args; 667 int error; 668 669 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 670 return (error); 671 672 bsd_args.s = linux_args.s; 673 bsd_args.buf = linux_args.msg; 674 bsd_args.len = linux_args.len; 675 bsd_args.flags = linux_args.flags; 676 bsd_args.to = linux_args.to; 677 bsd_args.tolen = linux_args.tolen; 678 679 if (linux_check_hdrincl(p, linux_args.s) == 0) 680 /* IP_HDRINCL set, tweak the packet before sending */ 681 return (linux_sendto_hdrincl(p, &bsd_args)); 682 683 return (sendto(p, &bsd_args)); 684} 685 686struct linux_recvfrom_args { 687 int s; 688 void *buf; 689 int len; 690 int flags; 691 caddr_t from; 692 int *fromlen; 693}; 694 695static int 696linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args) 697{ 698 struct linux_recvfrom_args linux_args; 699 struct recvfrom_args /* { 700 int s; 701 caddr_t buf; 702 size_t len; 703 int flags; 704 caddr_t from; 705 int *fromlenaddr; 706 } */ bsd_args; 707 int error; 708 709 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 710 return (error); 711 712 bsd_args.s = linux_args.s; 713 bsd_args.buf = linux_args.buf; 714 bsd_args.len = linux_args.len; 715 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 716 bsd_args.from = linux_args.from; 717 bsd_args.fromlenaddr = linux_args.fromlen; 718 return (orecvfrom(p, &bsd_args)); 719} 720 721struct linux_recvmsg_args { 722 int s; 723 struct msghdr *msg; 724 int flags; 725}; 726 727static int 728linux_recvmsg(struct proc *p, struct linux_recvmsg_args *args) 729{ 730 struct linux_recvmsg_args linux_args; 731 struct recvmsg_args /* { 732 int s; 733 struct msghdr *msg; 734 int flags; 735 } */ bsd_args; 736 int error; 737 738 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 739 return (error); 740 741 bsd_args.s = linux_args.s; 742 bsd_args.msg = linux_args.msg; 743 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 744 return (recvmsg(p, &bsd_args)); 745} 746 747struct linux_shutdown_args { 748 int s; 749 int how; 750}; 751 752static int 753linux_shutdown(struct proc *p, struct linux_shutdown_args *args) 754{ 755 struct linux_shutdown_args linux_args; 756 struct shutdown_args /* { 757 int s; 758 int how; 759 } */ bsd_args; 760 int error; 761 762 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 763 return (error); 764 765 bsd_args.s = linux_args.s; 766 bsd_args.how = linux_args.how; 767 return (shutdown(p, &bsd_args)); 768} 769 770struct linux_setsockopt_args { 771 int s; 772 int level; 773 int optname; 774 void *optval; 775 int optlen; 776}; 777 778static int 779linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) 780{ 781 struct linux_setsockopt_args linux_args; 782 struct setsockopt_args /* { 783 int s; 784 int level; 785 int name; 786 caddr_t val; 787 int valsize; 788 } */ bsd_args; 789 int error, name; 790 791 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 792 return (error); 793 794 bsd_args.s = linux_args.s; 795 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 796 switch (bsd_args.level) { 797 case SOL_SOCKET: 798 name = linux_to_bsd_so_sockopt(linux_args.optname); 799 break; 800 case IPPROTO_IP: 801 name = linux_to_bsd_ip_sockopt(linux_args.optname); 802 break; 803 case IPPROTO_TCP: 804 /* Linux TCP option values match BSD's */ 805 name = linux_args.optname; 806 break; 807 default: 808 name = -1; 809 break; 810 } 811 if (name == -1) 812 return (EINVAL); 813 814 bsd_args.name = name; 815 bsd_args.val = linux_args.optval; 816 bsd_args.valsize = linux_args.optlen; 817 return (setsockopt(p, &bsd_args)); 818} 819 820struct linux_getsockopt_args { 821 int s; 822 int level; 823 int optname; 824 void *optval; 825 int *optlen; 826}; 827 828static int 829linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) 830{ 831 struct linux_getsockopt_args linux_args; 832 struct getsockopt_args /* { 833 int s; 834 int level; 835 int name; 836 caddr_t val; 837 int *avalsize; 838 } */ bsd_args; 839 int error, name; 840 841 if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 842 return (error); 843 844 bsd_args.s = linux_args.s; 845 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 846 switch (bsd_args.level) { 847 case SOL_SOCKET: 848 name = linux_to_bsd_so_sockopt(linux_args.optname); 849 break; 850 case IPPROTO_IP: 851 name = linux_to_bsd_ip_sockopt(linux_args.optname); 852 break; 853 case IPPROTO_TCP: 854 /* Linux TCP option values match BSD's */ 855 name = linux_args.optname; 856 break; 857 default: 858 name = -1; 859 break; 860 } 861 if (name == -1) 862 return (EINVAL); 863 864 bsd_args.name = name; 865 bsd_args.val = linux_args.optval; 866 bsd_args.avalsize = linux_args.optlen; 867 return (getsockopt(p, &bsd_args)); 868} 869 870int 871linux_socketcall(struct proc *p, struct linux_socketcall_args *args) 872{ 873 void *arg = (void *)args->args; 874 875 switch (args->what) { 876 case LINUX_SOCKET: 877 return (linux_socket(p, arg)); 878 case LINUX_BIND: 879 return (linux_bind(p, arg)); 880 case LINUX_CONNECT: 881 return (linux_connect(p, arg)); 882 case LINUX_LISTEN: 883 return (linux_listen(p, arg)); 884 case LINUX_ACCEPT: 885 return (linux_accept(p, arg)); 886 case LINUX_GETSOCKNAME: 887 return (linux_getsockname(p, arg)); 888 case LINUX_GETPEERNAME: 889 return (linux_getpeername(p, arg)); 890 case LINUX_SOCKETPAIR: 891 return (linux_socketpair(p, arg)); 892 case LINUX_SEND: 893 return (linux_send(p, arg)); 894 case LINUX_RECV: 895 return (linux_recv(p, arg)); 896 case LINUX_SENDTO: 897 return (linux_sendto(p, arg)); 898 case LINUX_RECVFROM: 899 return (linux_recvfrom(p, arg)); 900 case LINUX_SHUTDOWN: 901 return (linux_shutdown(p, arg)); 902 case LINUX_SETSOCKOPT: 903 return (linux_setsockopt(p, arg)); 904 case LINUX_GETSOCKOPT: 905 return (linux_getsockopt(p, arg)); 906 case LINUX_SENDMSG: 907 do { 908 int error; 909 int level; 910 caddr_t control; 911 struct { 912 int s; 913 const struct msghdr *msg; 914 int flags; 915 } *uap = arg; 916 917 error = copyin(&uap->msg->msg_control, &control, 918 sizeof(caddr_t)); 919 if (error) 920 return (error); 921 922 if (control == NULL) 923 goto done; 924 925 error = copyin(&((struct cmsghdr*)control)->cmsg_level, 926 &level, sizeof(int)); 927 if (error) 928 return (error); 929 930 if (level == 1) { 931 /* 932 * Linux thinks that SOL_SOCKET is 1; we know 933 * that it's really 0xffff, of course. 934 */ 935 level = SOL_SOCKET; 936 error = copyout(&level, 937 &((struct cmsghdr *)control)->cmsg_level, 938 sizeof(int)); 939 if (error) 940 return (error); 941 } 942 done: 943 return (sendmsg(p, arg)); 944 } while (0); 945 case LINUX_RECVMSG: 946 return (linux_recvmsg(p, arg)); 947 } 948 949 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 950 return (ENOSYS); 951} 952#endif /*!__alpha__*/ 953