The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_socket.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/6.3/sys/compat/linux/linux_socket.c 172041 2007-09-03 13:18:42Z netchild $");
   31 
   32 /* XXX we use functions that might not exist. */
   33 #include "opt_compat.h"
   34 #include "opt_inet6.h"
   35 
   36 #ifndef COMPAT_43
   37 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
   38 #endif
   39 
   40 #include <sys/param.h>
   41 #include <sys/proc.h>
   42 #include <sys/systm.h>
   43 #include <sys/sysproto.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/file.h>
   46 #include <sys/limits.h>
   47 #include <sys/lock.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mutex.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/socket.h>
   52 #include <sys/socketvar.h>
   53 #include <sys/syscallsubr.h>
   54 #include <sys/uio.h>
   55 #include <sys/syslog.h>
   56 #include <sys/un.h>
   57 
   58 #include <netinet/in.h>
   59 #include <netinet/in_systm.h>
   60 #include <netinet/ip.h>
   61 #ifdef INET6
   62 #include <netinet/ip6.h>
   63 #include <netinet6/ip6_var.h>
   64 #endif
   65 
   66 #include "opt_compat.h"
   67 
   68 #ifdef COMPAT_LINUX32
   69 #include <machine/../linux32/linux.h>
   70 #include <machine/../linux32/linux32_proto.h>
   71 #else
   72 #include <machine/../linux/linux.h>
   73 #include <machine/../linux/linux_proto.h>
   74 #endif
   75 #include <compat/linux/linux_socket.h>
   76 #include <compat/linux/linux_util.h>
   77 
   78 static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
   79     struct malloc_type *);
   80 static int linux_to_bsd_domain(int);
   81 
   82 /*
   83  * Reads a linux sockaddr and does any necessary translation.
   84  * Linux sockaddrs don't have a length field, only a family.
   85  */
   86 static int
   87 linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
   88 {
   89         int osalen = len;
   90 
   91         return (do_sa_get(sap, osa, &osalen, M_SONAME));
   92 }
   93 
   94 /*
   95  * Copy the osockaddr structure pointed to by osa to kernel, adjust
   96  * family and convert to sockaddr.
   97  */
   98 static int
   99 do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
  100     struct malloc_type *mtype)
  101 {
  102         int error=0, bdom;
  103         struct sockaddr *sa;
  104         struct osockaddr *kosa;
  105         int alloclen;
  106 #ifdef INET6
  107         int oldv6size;
  108         struct sockaddr_in6 *sin6;
  109 #endif
  110 
  111         if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
  112                 return (EINVAL);
  113 
  114         alloclen = *osalen;
  115 #ifdef INET6
  116         oldv6size = 0;
  117         /*
  118          * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
  119          * if it's a v4-mapped address, so reserve the proper space
  120          * for it.
  121          */
  122         if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
  123                 alloclen = sizeof (struct sockaddr_in6);
  124                 oldv6size = 1;
  125         }
  126 #endif
  127 
  128         MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
  129 
  130         if ((error = copyin(osa, kosa, *osalen)))
  131                 goto out;
  132 
  133         bdom = linux_to_bsd_domain(kosa->sa_family);
  134         if (bdom == -1) {
  135                 error = EINVAL;
  136                 goto out;
  137         }
  138 
  139 #ifdef INET6
  140         /*
  141          * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
  142          * which lacks the scope id compared with RFC2553 one. If we detect
  143          * the situation, reject the address and write a message to system log.
  144          *
  145          * Still accept addresses for which the scope id is not used.
  146          */
  147         if (oldv6size && bdom == AF_INET6) {
  148                 sin6 = (struct sockaddr_in6 *)kosa;
  149                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
  150                     (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
  151                      !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
  152                      !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
  153                      !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
  154                      !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
  155                         sin6->sin6_scope_id = 0;
  156                 } else {
  157                         log(LOG_DEBUG,
  158                             "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
  159                         error = EINVAL;
  160                         goto out;
  161                 }
  162         } else
  163 #endif
  164         if (bdom == AF_INET)
  165                 alloclen = sizeof(struct sockaddr_in);
  166 
  167         sa = (struct sockaddr *) kosa;
  168         sa->sa_family = bdom;
  169         sa->sa_len = alloclen;
  170 
  171         *sap = sa;
  172         *osalen = alloclen;
  173         return (0);
  174 
  175 out:
  176         FREE(kosa, mtype);
  177         return (error);
  178 }
  179 
  180 static int
  181 linux_to_bsd_domain(int domain)
  182 {
  183 
  184         switch (domain) {
  185         case LINUX_AF_UNSPEC:
  186                 return (AF_UNSPEC);
  187         case LINUX_AF_UNIX:
  188                 return (AF_LOCAL);
  189         case LINUX_AF_INET:
  190                 return (AF_INET);
  191         case LINUX_AF_INET6:
  192                 return (AF_INET6);
  193         case LINUX_AF_AX25:
  194                 return (AF_CCITT);
  195         case LINUX_AF_IPX:
  196                 return (AF_IPX);
  197         case LINUX_AF_APPLETALK:
  198                 return (AF_APPLETALK);
  199         }
  200         return (-1);
  201 }
  202 
  203 #ifndef __alpha__
  204 static int
  205 bsd_to_linux_domain(int domain)
  206 {
  207 
  208         switch (domain) {
  209         case AF_UNSPEC:
  210                 return (LINUX_AF_UNSPEC);
  211         case AF_LOCAL:
  212                 return (LINUX_AF_UNIX);
  213         case AF_INET:
  214                 return (LINUX_AF_INET);
  215         case AF_INET6:
  216                 return (LINUX_AF_INET6);
  217         case AF_CCITT:
  218                 return (LINUX_AF_AX25);
  219         case AF_IPX:
  220                 return (LINUX_AF_IPX);
  221         case AF_APPLETALK:
  222                 return (LINUX_AF_APPLETALK);
  223         }
  224         return (-1);
  225 }
  226 
  227 static int
  228 linux_to_bsd_sockopt_level(int level)
  229 {
  230 
  231         switch (level) {
  232         case LINUX_SOL_SOCKET:
  233                 return (SOL_SOCKET);
  234         }
  235         return (level);
  236 }
  237 
  238 static int
  239 bsd_to_linux_sockopt_level(int level)
  240 {
  241 
  242         switch (level) {
  243         case SOL_SOCKET:
  244                 return (LINUX_SOL_SOCKET);
  245         }
  246         return (level);
  247 }
  248 
  249 static int
  250 linux_to_bsd_ip_sockopt(int opt)
  251 {
  252 
  253         switch (opt) {
  254         case LINUX_IP_TOS:
  255                 return (IP_TOS);
  256         case LINUX_IP_TTL:
  257                 return (IP_TTL);
  258         case LINUX_IP_OPTIONS:
  259                 return (IP_OPTIONS);
  260         case LINUX_IP_MULTICAST_IF:
  261                 return (IP_MULTICAST_IF);
  262         case LINUX_IP_MULTICAST_TTL:
  263                 return (IP_MULTICAST_TTL);
  264         case LINUX_IP_MULTICAST_LOOP:
  265                 return (IP_MULTICAST_LOOP);
  266         case LINUX_IP_ADD_MEMBERSHIP:
  267                 return (IP_ADD_MEMBERSHIP);
  268         case LINUX_IP_DROP_MEMBERSHIP:
  269                 return (IP_DROP_MEMBERSHIP);
  270         case LINUX_IP_HDRINCL:
  271                 return (IP_HDRINCL);
  272         }
  273         return (-1);
  274 }
  275 
  276 static int
  277 linux_to_bsd_so_sockopt(int opt)
  278 {
  279 
  280         switch (opt) {
  281         case LINUX_SO_DEBUG:
  282                 return (SO_DEBUG);
  283         case LINUX_SO_REUSEADDR:
  284                 return (SO_REUSEADDR);
  285         case LINUX_SO_TYPE:
  286                 return (SO_TYPE);
  287         case LINUX_SO_ERROR:
  288                 return (SO_ERROR);
  289         case LINUX_SO_DONTROUTE:
  290                 return (SO_DONTROUTE);
  291         case LINUX_SO_BROADCAST:
  292                 return (SO_BROADCAST);
  293         case LINUX_SO_SNDBUF:
  294                 return (SO_SNDBUF);
  295         case LINUX_SO_RCVBUF:
  296                 return (SO_RCVBUF);
  297         case LINUX_SO_KEEPALIVE:
  298                 return (SO_KEEPALIVE);
  299         case LINUX_SO_OOBINLINE:
  300                 return (SO_OOBINLINE);
  301         case LINUX_SO_LINGER:
  302                 return (SO_LINGER);
  303         case LINUX_SO_PEERCRED:
  304                 return (LOCAL_PEERCRED);
  305         case LINUX_SO_RCVLOWAT:
  306                 return (SO_RCVLOWAT);
  307         case LINUX_SO_SNDLOWAT:
  308                 return (SO_SNDLOWAT);
  309         case LINUX_SO_RCVTIMEO:
  310                 return (SO_RCVTIMEO);
  311         case LINUX_SO_SNDTIMEO:
  312                 return (SO_SNDTIMEO);
  313         case LINUX_SO_TIMESTAMP:
  314                 return (SO_TIMESTAMP);
  315         case LINUX_SO_ACCEPTCONN:
  316                 return (SO_ACCEPTCONN);
  317         }
  318         return (-1);
  319 }
  320 
  321 static int
  322 linux_to_bsd_msg_flags(int flags)
  323 {
  324         int ret_flags = 0;
  325 
  326         if (flags & LINUX_MSG_OOB)
  327                 ret_flags |= MSG_OOB;
  328         if (flags & LINUX_MSG_PEEK)
  329                 ret_flags |= MSG_PEEK;
  330         if (flags & LINUX_MSG_DONTROUTE)
  331                 ret_flags |= MSG_DONTROUTE;
  332         if (flags & LINUX_MSG_CTRUNC)
  333                 ret_flags |= MSG_CTRUNC;
  334         if (flags & LINUX_MSG_TRUNC)
  335                 ret_flags |= MSG_TRUNC;
  336         if (flags & LINUX_MSG_DONTWAIT)
  337                 ret_flags |= MSG_DONTWAIT;
  338         if (flags & LINUX_MSG_EOR)
  339                 ret_flags |= MSG_EOR;
  340         if (flags & LINUX_MSG_WAITALL)
  341                 ret_flags |= MSG_WAITALL;
  342         if (flags & LINUX_MSG_NOSIGNAL)
  343                 ret_flags |= MSG_NOSIGNAL;
  344 #if 0 /* not handled */
  345         if (flags & LINUX_MSG_PROXY)
  346                 ;
  347         if (flags & LINUX_MSG_FIN)
  348                 ;
  349         if (flags & LINUX_MSG_SYN)
  350                 ;
  351         if (flags & LINUX_MSG_CONFIRM)
  352                 ;
  353         if (flags & LINUX_MSG_RST)
  354                 ;
  355         if (flags & LINUX_MSG_ERRQUEUE)
  356                 ;
  357 #endif
  358         return ret_flags;
  359 }
  360 
  361 /*
  362 * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
  363 * native syscall will fault.  Thus, we don't really need to check the
  364 * return values for these functions.
  365 */
  366 
  367 static int
  368 bsd_to_linux_sockaddr(struct sockaddr *arg)
  369 {
  370         struct sockaddr sa;
  371         size_t sa_len = sizeof(struct sockaddr);
  372         int error;
  373         
  374         if ((error = copyin(arg, &sa, sa_len)))
  375                 return (error);
  376         
  377         *(u_short *)&sa = sa.sa_family;
  378         
  379         error = copyout(&sa, arg, sa_len);
  380         
  381         return (error);
  382 }
  383 
  384 static int
  385 linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
  386 {
  387         struct sockaddr sa;
  388         size_t sa_len = sizeof(struct sockaddr);
  389         int error;
  390 
  391         if ((error = copyin(arg, &sa, sa_len)))
  392                 return (error);
  393 
  394         sa.sa_family = *(sa_family_t *)&sa;
  395         sa.sa_len = len;
  396 
  397         error = copyout(&sa, arg, sa_len);
  398 
  399         return (error);
  400 }
  401 
  402 
  403 static int
  404 linux_sa_put(struct osockaddr *osa)
  405 {
  406         struct osockaddr sa;
  407         int error, bdom;
  408 
  409         /*
  410          * Only read/write the osockaddr family part, the rest is
  411          * not changed.
  412          */
  413         error = copyin(osa, &sa, sizeof(sa.sa_family));
  414         if (error)
  415                 return (error);
  416 
  417         bdom = bsd_to_linux_domain(sa.sa_family);
  418         if (bdom == -1)
  419                 return (EINVAL);
  420 
  421         sa.sa_family = bdom;
  422         error = copyout(&sa, osa, sizeof(sa.sa_family));
  423         if (error)
  424                 return (error);
  425 
  426         return (0);
  427 }
  428 
  429 static int
  430 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
  431     enum uio_seg segflg)
  432 {
  433         struct mbuf *control;
  434         struct sockaddr *to;
  435         int error;
  436 
  437         if (mp->msg_name != NULL) {
  438                 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
  439                 if (error)
  440                         return (error);
  441                 mp->msg_name = to;
  442         } else
  443                 to = NULL;
  444 
  445         if (mp->msg_control != NULL) {
  446                 struct cmsghdr *cmsg;
  447 
  448                 if (mp->msg_controllen < sizeof(struct cmsghdr)) {
  449                         error = EINVAL;
  450                         goto bad;
  451                 }
  452                 error = sockargs(&control, mp->msg_control,
  453                     mp->msg_controllen, MT_CONTROL);
  454                 if (error)
  455                         goto bad;
  456 
  457                 cmsg = mtod(control, struct cmsghdr *);
  458                 cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
  459         } else
  460                 control = NULL;
  461 
  462         error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
  463             segflg);
  464 
  465 bad:
  466         if (to)
  467                 FREE(to, M_SONAME);
  468         return (error);
  469 }
  470 
  471 /* Return 0 if IP_HDRINCL is set for the given socket. */
  472 static int
  473 linux_check_hdrincl(struct thread *td, int s)
  474 {
  475         int error, optval, size_val;
  476 
  477         size_val = sizeof(optval);
  478         error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
  479             &optval, UIO_SYSSPACE, &size_val);
  480         if (error)
  481                 return (error);
  482 
  483         return (optval == 0);
  484 }
  485 
  486 struct linux_sendto_args {
  487         int s;
  488         l_uintptr_t msg;
  489         int len;
  490         int flags;
  491         l_uintptr_t to;
  492         int tolen;
  493 };
  494 
  495 /*
  496  * Updated sendto() when IP_HDRINCL is set:
  497  * tweak endian-dependent fields in the IP packet.
  498  */
  499 static int
  500 linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
  501 {
  502 /*
  503  * linux_ip_copysize defines how many bytes we should copy
  504  * from the beginning of the IP packet before we customize it for BSD.
  505  * It should include all the fields we modify (ip_len and ip_off).
  506  */
  507 #define linux_ip_copysize       8
  508 
  509         struct ip *packet;
  510         struct msghdr msg;
  511         struct iovec aiov[1];
  512         int error;
  513 
  514         /* Check that the packet isn't too big or too small. */
  515         if (linux_args->len < linux_ip_copysize ||
  516             linux_args->len > IP_MAXPACKET)
  517                 return (EINVAL);
  518 
  519         packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
  520 
  521         /* Make kernel copy of the packet to be sent */
  522         if ((error = copyin(PTRIN(linux_args->msg), packet,
  523             linux_args->len)))
  524                 goto goout;
  525 
  526         /* Convert fields from Linux to BSD raw IP socket format */
  527         packet->ip_len = linux_args->len;
  528         packet->ip_off = ntohs(packet->ip_off);
  529 
  530         /* Prepare the msghdr and iovec structures describing the new packet */
  531         msg.msg_name = PTRIN(linux_args->to);
  532         msg.msg_namelen = linux_args->tolen;
  533         msg.msg_iov = aiov;
  534         msg.msg_iovlen = 1;
  535         msg.msg_control = NULL;
  536         msg.msg_flags = 0;
  537         aiov[0].iov_base = (char *)packet;
  538         aiov[0].iov_len = linux_args->len;
  539         error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
  540             UIO_SYSSPACE);
  541 goout:
  542         free(packet, M_TEMP);
  543         return (error);
  544 }
  545 
  546 struct linux_socket_args {
  547         int domain;
  548         int type;
  549         int protocol;
  550 };
  551 
  552 static int
  553 linux_socket(struct thread *td, struct linux_socket_args *args)
  554 {
  555         struct linux_socket_args linux_args;
  556         struct socket_args /* {
  557                 int domain;
  558                 int type;
  559                 int protocol;
  560         } */ bsd_args;
  561         int error;
  562         int retval_socket;
  563 
  564         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  565                 return (error);
  566 
  567         bsd_args.protocol = linux_args.protocol;
  568         bsd_args.type = linux_args.type;
  569         bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
  570         if (bsd_args.domain == -1)
  571                 return (EINVAL);
  572 
  573         retval_socket = socket(td, &bsd_args);
  574         if (bsd_args.type == SOCK_RAW
  575             && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
  576             && bsd_args.domain == AF_INET
  577             && retval_socket >= 0) {
  578                 /* It's a raw IP socket: set the IP_HDRINCL option. */
  579                 int hdrincl;
  580 
  581                 hdrincl = 1;
  582                 /* We ignore any error returned by kern_setsockopt() */
  583                 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
  584                     &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
  585         }
  586 #ifdef INET6
  587         /*
  588          * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
  589          * default and some apps depend on this. So, set V6ONLY to 0
  590          * for Linux apps if the sysctl value is set to 1.
  591          */
  592         if (bsd_args.domain == PF_INET6 && retval_socket >= 0
  593 #ifndef KLD_MODULE
  594             /*
  595              * XXX: Avoid undefined symbol error with an IPv4 only
  596              * kernel.
  597              */
  598             && ip6_v6only
  599 #endif
  600             ) {
  601                 int v6only;
  602 
  603                 v6only = 0;
  604                 /* We ignore any error returned by setsockopt() */
  605                 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
  606                     &v6only, UIO_SYSSPACE, sizeof(v6only));
  607         }
  608 #endif
  609 
  610         return (retval_socket);
  611 }
  612 
  613 struct linux_bind_args {
  614         int s;
  615         l_uintptr_t name;
  616         int namelen;
  617 };
  618 
  619 static int
  620 linux_bind(struct thread *td, struct linux_bind_args *args)
  621 {
  622         struct linux_bind_args linux_args;
  623         struct sockaddr *sa;
  624         int error;
  625 
  626         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  627                 return (error);
  628 
  629         error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
  630             linux_args.namelen);
  631         if (error)
  632                 return (error);
  633 
  634         error = kern_bind(td, linux_args.s, sa);
  635         if (error == EADDRNOTAVAIL && linux_args.namelen != sizeof(struct sockaddr_in))
  636                 return (EINVAL);
  637         return (error);
  638 }
  639 
  640 struct linux_connect_args {
  641         int s;
  642         l_uintptr_t name;
  643         int namelen;
  644 };
  645 int linux_connect(struct thread *, struct linux_connect_args *);
  646 #endif /* !__alpha__*/
  647 
  648 int
  649 linux_connect(struct thread *td, struct linux_connect_args *args)
  650 {
  651         struct linux_connect_args linux_args;
  652         struct socket *so;
  653         struct sockaddr *sa;
  654         u_int fflag;
  655         int error;
  656 
  657 #ifdef __alpha__
  658         bcopy(args, &linux_args, sizeof(linux_args));
  659 #else
  660         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  661                 return (error);
  662 #endif /* __alpha__ */
  663 
  664         error = linux_getsockaddr(&sa,
  665             (struct osockaddr *)PTRIN(linux_args.name),
  666             linux_args.namelen);
  667         if (error)
  668                 return (error);
  669 
  670         error = kern_connect(td, linux_args.s, sa);
  671         if (error != EISCONN)
  672                 return (error);
  673 
  674         /*
  675          * Linux doesn't return EISCONN the first time it occurs,
  676          * when on a non-blocking socket. Instead it returns the
  677          * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
  678          *
  679          * XXXRW: Instead of using fgetsock(), check that it is a
  680          * socket and use the file descriptor reference instead of
  681          * creating a new one.
  682          */
  683         NET_LOCK_GIANT();
  684         error = fgetsock(td, linux_args.s, &so, &fflag);
  685         if (error == 0) {
  686                 error = EISCONN;
  687                 if (fflag & FNONBLOCK) {
  688                         SOCK_LOCK(so);
  689                         if (so->so_emuldata == 0)
  690                                 error = so->so_error;
  691                         so->so_emuldata = (void *)1;
  692                         SOCK_UNLOCK(so);
  693                 }
  694                 fputsock(so);
  695         }
  696         NET_UNLOCK_GIANT();
  697         return (error);
  698 }
  699 
  700 #ifndef __alpha__
  701 
  702 struct linux_listen_args {
  703         int s;
  704         int backlog;
  705 };
  706 
  707 static int
  708 linux_listen(struct thread *td, struct linux_listen_args *args)
  709 {
  710         struct linux_listen_args linux_args;
  711         struct listen_args /* {
  712                 int s;
  713                 int backlog;
  714         } */ bsd_args;
  715         int error;
  716 
  717         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  718                 return (error);
  719 
  720         bsd_args.s = linux_args.s;
  721         bsd_args.backlog = linux_args.backlog;
  722         return (listen(td, &bsd_args));
  723 }
  724 
  725 struct linux_accept_args {
  726         int s;
  727         l_uintptr_t addr;
  728         l_uintptr_t namelen;
  729 };
  730 
  731 static int
  732 linux_accept(struct thread *td, struct linux_accept_args *args)
  733 {
  734         struct linux_accept_args linux_args;
  735         struct accept_args /* {
  736                 int     s;
  737                 struct sockaddr * __restrict name;
  738                 socklen_t * __restrict anamelen;
  739         } */ bsd_args;
  740         int error, fd;
  741 
  742         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  743                 return (error);
  744 
  745         bsd_args.s = linux_args.s;
  746         /* XXX: */
  747         bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
  748         bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
  749         error = accept(td, &bsd_args);
  750         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
  751         if (error) {
  752                 if (error == EFAULT && linux_args.namelen != sizeof(struct sockaddr_in))
  753                         return (EINVAL);
  754                 return (error);
  755         }
  756         if (linux_args.addr) {
  757                 error = linux_sa_put(PTRIN(linux_args.addr));
  758                 if (error) {
  759                         (void)kern_close(td, td->td_retval[0]);
  760                         return (error);
  761                 }
  762         }
  763 
  764         /*
  765          * linux appears not to copy flags from the parent socket to the
  766          * accepted one, so we must clear the flags in the new descriptor.
  767          * Ignore any errors, because we already have an open fd.
  768          */
  769         fd = td->td_retval[0];
  770         (void)kern_fcntl(td, fd, F_SETFL, 0);
  771         td->td_retval[0] = fd;
  772         return (0);
  773 }
  774 
  775 struct linux_getsockname_args {
  776         int s;
  777         l_uintptr_t addr;
  778         l_uintptr_t namelen;
  779 };
  780 
  781 static int
  782 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
  783 {
  784         struct linux_getsockname_args linux_args;
  785         struct getsockname_args /* {
  786                 int     fdes;
  787                 struct sockaddr * __restrict asa;
  788                 socklen_t * __restrict alen;
  789         } */ bsd_args;
  790         int error;
  791 
  792         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  793                 return (error);
  794 
  795         bsd_args.fdes = linux_args.s;
  796         /* XXX: */
  797         bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
  798         bsd_args.alen = PTRIN(linux_args.namelen);      /* XXX */
  799         error = getsockname(td, &bsd_args);
  800         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
  801         if (error)
  802                 return (error);
  803         error = linux_sa_put(PTRIN(linux_args.addr));
  804         if (error)
  805                 return (error);
  806         return (0);
  807 }
  808 
  809 struct linux_getpeername_args {
  810         int s;
  811         l_uintptr_t addr;
  812         l_uintptr_t namelen;
  813 };
  814 
  815 static int
  816 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
  817 {
  818         struct linux_getpeername_args linux_args;
  819         struct getpeername_args /* {
  820                 int fdes;
  821                 caddr_t asa;
  822                 int *alen;
  823         } */ bsd_args;
  824         int error;
  825 
  826         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  827                 return (error);
  828 
  829         bsd_args.fdes = linux_args.s;
  830         bsd_args.asa = (struct sockaddr *)PTRIN(linux_args.addr);
  831         bsd_args.alen = (int *)PTRIN(linux_args.namelen);
  832         error = getpeername(td, &bsd_args);
  833         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
  834         if (error)
  835                 return (error);
  836         error = linux_sa_put(PTRIN(linux_args.addr));
  837         if (error)
  838                 return (error);
  839         return (0);
  840 }
  841 
  842 struct linux_socketpair_args {
  843         int domain;
  844         int type;
  845         int protocol;
  846         l_uintptr_t rsv;
  847 };
  848 
  849 static int
  850 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
  851 {
  852         struct linux_socketpair_args linux_args;
  853         struct socketpair_args /* {
  854                 int domain;
  855                 int type;
  856                 int protocol;
  857                 int *rsv;
  858         } */ bsd_args;
  859         int error;
  860 
  861         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  862                 return (error);
  863 
  864         bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
  865         if (bsd_args.domain == -1)
  866                 return (EINVAL);
  867 
  868         bsd_args.type = linux_args.type;
  869         bsd_args.protocol = linux_args.protocol;
  870         bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
  871         return (socketpair(td, &bsd_args));
  872 }
  873 
  874 struct linux_send_args {
  875         int s;
  876         l_uintptr_t msg;
  877         int len;
  878         int flags;
  879 };
  880 
  881 static int
  882 linux_send(struct thread *td, struct linux_send_args *args)
  883 {
  884         struct linux_send_args linux_args;
  885         struct sendto_args /* {
  886                 int s;
  887                 caddr_t buf;
  888                 int len;
  889                 int flags;
  890                 caddr_t to;
  891                 int tolen;
  892         } */ bsd_args;
  893         int error;
  894 
  895         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  896                 return (error);
  897 
  898         bsd_args.s = linux_args.s;
  899         bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
  900         bsd_args.len = linux_args.len;
  901         bsd_args.flags = linux_args.flags;
  902         bsd_args.to = NULL;
  903         bsd_args.tolen = 0;
  904         return sendto(td, &bsd_args);
  905 }
  906 
  907 struct linux_recv_args {
  908         int s;
  909         l_uintptr_t msg;
  910         int len;
  911         int flags;
  912 };
  913 
  914 static int
  915 linux_recv(struct thread *td, struct linux_recv_args *args)
  916 {
  917         struct linux_recv_args linux_args;
  918         struct recvfrom_args /* {
  919                 int s;
  920                 caddr_t buf;
  921                 int len;
  922                 int flags;
  923                 struct sockaddr *from;
  924                 socklen_t fromlenaddr;
  925         } */ bsd_args;
  926         int error;
  927 
  928         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  929                 return (error);
  930 
  931         bsd_args.s = linux_args.s;
  932         bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
  933         bsd_args.len = linux_args.len;
  934         bsd_args.flags = linux_args.flags;
  935         bsd_args.from = NULL;
  936         bsd_args.fromlenaddr = 0;
  937         return (recvfrom(td, &bsd_args));
  938 }
  939 
  940 static int
  941 linux_sendto(struct thread *td, struct linux_sendto_args *args)
  942 {
  943         struct linux_sendto_args linux_args;
  944         struct msghdr msg;
  945         struct iovec aiov;
  946         int error;
  947 
  948         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  949                 return (error);
  950 
  951         if (linux_check_hdrincl(td, linux_args.s) == 0)
  952                 /* IP_HDRINCL set, tweak the packet before sending */
  953                 return (linux_sendto_hdrincl(td, &linux_args));
  954 
  955         msg.msg_name = PTRIN(linux_args.to);
  956         msg.msg_namelen = linux_args.tolen;
  957         msg.msg_iov = &aiov;
  958         msg.msg_iovlen = 1;
  959         msg.msg_control = NULL;
  960         msg.msg_flags = 0;
  961         aiov.iov_base = PTRIN(linux_args.msg);
  962         aiov.iov_len = linux_args.len;
  963         error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
  964             UIO_USERSPACE);
  965         return (error);
  966 }
  967 
  968 struct linux_recvfrom_args {
  969         int s;
  970         l_uintptr_t buf;
  971         int len;
  972         int flags;
  973         l_uintptr_t from;
  974         l_uintptr_t fromlen;
  975 };
  976 
  977 static int
  978 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
  979 {
  980         struct linux_recvfrom_args linux_args;
  981         struct recvfrom_args /* {
  982                 int     s;
  983                 caddr_t buf;
  984                 size_t  len;
  985                 int     flags;
  986                 struct sockaddr * __restrict from;
  987                 socklen_t * __restrict fromlenaddr;
  988         } */ bsd_args;
  989         size_t len;
  990         int error;
  991 
  992         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
  993                 return (error);
  994 
  995         if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
  996                 return (error);
  997 
  998         bsd_args.s = linux_args.s;
  999         bsd_args.buf = PTRIN(linux_args.buf);
 1000         bsd_args.len = linux_args.len;
 1001         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
 1002         /* XXX: */
 1003         bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
 1004         bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
 1005         
 1006         linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
 1007         error = recvfrom(td, &bsd_args);
 1008         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
 1009         
 1010         if (error)
 1011                 return (error);
 1012         if (linux_args.from) {
 1013                 error = linux_sa_put((struct osockaddr *)
 1014                     PTRIN(linux_args.from));
 1015                 if (error)
 1016                         return (error);
 1017         }
 1018         return (0);
 1019 }
 1020 
 1021 struct linux_sendmsg_args {
 1022         int s;
 1023         l_uintptr_t msg;
 1024         int flags;
 1025 };
 1026 
 1027 static int
 1028 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
 1029 {
 1030         struct linux_sendmsg_args linux_args;
 1031         struct msghdr msg;
 1032         struct iovec *iov;
 1033         int error;
 1034 
 1035         /* XXXTJR sendmsg is broken on amd64 */
 1036 
 1037         error = copyin(args, &linux_args, sizeof(linux_args));
 1038         if (error)
 1039                 return (error);
 1040         error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
 1041         if (error)
 1042                 return (error);
 1043 
 1044         /*
 1045          * Some Linux applications (ping) define a non-NULL control data
 1046          * pointer, but a msg_controllen of 0, which is not allowed in the
 1047          * FreeBSD system call interface.  NULL the msg_control pointer in
 1048          * order to handle this case.  This should be checked, but allows the
 1049          * Linux ping to work.
 1050          */
 1051         if (msg.msg_control != NULL && msg.msg_controllen == 0)
 1052                 msg.msg_control = NULL;
 1053         error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
 1054         if (error)
 1055                 return (error);
 1056         msg.msg_iov = iov;
 1057         msg.msg_flags = 0;
 1058         error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
 1059             UIO_USERSPACE);
 1060         free(iov, M_IOV);
 1061         return (error);
 1062 }
 1063 
 1064 struct linux_recvmsg_args {
 1065         int s;
 1066         l_uintptr_t msg;
 1067         int flags;
 1068 };
 1069 
 1070 static int
 1071 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
 1072 {
 1073         struct linux_recvmsg_args linux_args;
 1074         struct recvmsg_args /* {
 1075                 int     s;
 1076                 struct  msghdr *msg;
 1077                 int     flags;
 1078         } */ bsd_args;
 1079         struct msghdr msg;
 1080         struct cmsghdr *cmsg;
 1081         int error;
 1082 
 1083         /* XXXTJR recvmsg is broken on amd64 */
 1084 
 1085         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
 1086                 return (error);
 1087 
 1088         if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg))))
 1089                 return (error);
 1090 
 1091         bsd_args.s = linux_args.s;
 1092         bsd_args.msg = PTRIN(linux_args.msg);
 1093         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
 1094         if (msg.msg_name) {
 1095                 linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
 1096                       msg.msg_namelen);
 1097                 error = recvmsg(td, &bsd_args);
 1098                 bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name);
 1099         } else
 1100                 error = recvmsg(td, &bsd_args);
 1101         if (error)
 1102                 return (error);
 1103 
 1104         if (bsd_args.msg->msg_control != NULL &&
 1105             bsd_args.msg->msg_controllen > 0) {
 1106                 cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
 1107                 cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
 1108         }
 1109 
 1110         error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
 1111         if (error)
 1112                 return (error);
 1113         if (msg.msg_name && msg.msg_namelen > 2)
 1114                 error = linux_sa_put(msg.msg_name);
 1115         return (error);
 1116 }
 1117 
 1118 struct linux_shutdown_args {
 1119         int s;
 1120         int how;
 1121 };
 1122 
 1123 static int
 1124 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
 1125 {
 1126         struct linux_shutdown_args linux_args;
 1127         struct shutdown_args /* {
 1128                 int s;
 1129                 int how;
 1130         } */ bsd_args;
 1131         int error;
 1132 
 1133         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
 1134                 return (error);
 1135 
 1136         bsd_args.s = linux_args.s;
 1137         bsd_args.how = linux_args.how;
 1138         return (shutdown(td, &bsd_args));
 1139 }
 1140 
 1141 struct linux_setsockopt_args {
 1142         int s;
 1143         int level;
 1144         int optname;
 1145         l_uintptr_t optval;
 1146         int optlen;
 1147 };
 1148 
 1149 static int
 1150 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
 1151 {
 1152         struct linux_setsockopt_args linux_args;
 1153         struct setsockopt_args /* {
 1154                 int s;
 1155                 int level;
 1156                 int name;
 1157                 caddr_t val;
 1158                 int valsize;
 1159         } */ bsd_args;
 1160         int error, name;
 1161 
 1162         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
 1163                 return (error);
 1164 
 1165         bsd_args.s = linux_args.s;
 1166         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
 1167         switch (bsd_args.level) {
 1168         case SOL_SOCKET:
 1169                 name = linux_to_bsd_so_sockopt(linux_args.optname);
 1170                 break;
 1171         case IPPROTO_IP:
 1172                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
 1173                 break;
 1174         case IPPROTO_TCP:
 1175                 /* Linux TCP option values match BSD's */
 1176                 name = linux_args.optname;
 1177                 break;
 1178         default:
 1179                 name = -1;
 1180                 break;
 1181         }
 1182         if (name == -1)
 1183                 return (ENOPROTOOPT);
 1184 
 1185         bsd_args.name = name;
 1186         bsd_args.val = PTRIN(linux_args.optval);
 1187         bsd_args.valsize = linux_args.optlen;
 1188 
 1189         if (name == IPV6_NEXTHOP) {
 1190                 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
 1191                         bsd_args.valsize);
 1192                 error = setsockopt(td, &bsd_args);
 1193                 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
 1194         } else
 1195                 error = setsockopt(td, &bsd_args);
 1196 
 1197         return (error);
 1198 }
 1199 
 1200 struct linux_getsockopt_args {
 1201         int s;
 1202         int level;
 1203         int optname;
 1204         l_uintptr_t optval;
 1205         l_uintptr_t optlen;
 1206 };
 1207 
 1208 static int
 1209 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 1210 {
 1211         struct linux_getsockopt_args linux_args;
 1212         struct getsockopt_args /* {
 1213                 int s;
 1214                 int level;
 1215                 int name;
 1216                 caddr_t val;
 1217                 int *avalsize;
 1218         } */ bsd_args;
 1219         int error, name;
 1220 
 1221         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
 1222                 return (error);
 1223 
 1224         bsd_args.s = linux_args.s;
 1225         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
 1226         switch (bsd_args.level) {
 1227         case SOL_SOCKET:
 1228                 name = linux_to_bsd_so_sockopt(linux_args.optname);
 1229                 break;
 1230         case IPPROTO_IP:
 1231                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
 1232                 break;
 1233         case IPPROTO_TCP:
 1234                 /* Linux TCP option values match BSD's */
 1235                 name = linux_args.optname;
 1236                 break;
 1237         default:
 1238                 name = -1;
 1239                 break;
 1240         }
 1241         if (name == -1)
 1242                 return (EINVAL);
 1243 
 1244         bsd_args.name = name;
 1245         bsd_args.val = PTRIN(linux_args.optval);
 1246         bsd_args.avalsize = PTRIN(linux_args.optlen);
 1247 
 1248         if (name == IPV6_NEXTHOP) {
 1249                 error = getsockopt(td, &bsd_args);
 1250                 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
 1251         } else
 1252                 error = getsockopt(td, &bsd_args);
 1253 
 1254         return (error);
 1255 }
 1256 
 1257 int
 1258 linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
 1259 {
 1260         void *arg = (void *)(intptr_t)args->args;
 1261 
 1262         switch (args->what) {
 1263         case LINUX_SOCKET:
 1264                 return (linux_socket(td, arg));
 1265         case LINUX_BIND:
 1266                 return (linux_bind(td, arg));
 1267         case LINUX_CONNECT:
 1268                 return (linux_connect(td, arg));
 1269         case LINUX_LISTEN:
 1270                 return (linux_listen(td, arg));
 1271         case LINUX_ACCEPT:
 1272                 return (linux_accept(td, arg));
 1273         case LINUX_GETSOCKNAME:
 1274                 return (linux_getsockname(td, arg));
 1275         case LINUX_GETPEERNAME:
 1276                 return (linux_getpeername(td, arg));
 1277         case LINUX_SOCKETPAIR:
 1278                 return (linux_socketpair(td, arg));
 1279         case LINUX_SEND:
 1280                 return (linux_send(td, arg));
 1281         case LINUX_RECV:
 1282                 return (linux_recv(td, arg));
 1283         case LINUX_SENDTO:
 1284                 return (linux_sendto(td, arg));
 1285         case LINUX_RECVFROM:
 1286                 return (linux_recvfrom(td, arg));
 1287         case LINUX_SHUTDOWN:
 1288                 return (linux_shutdown(td, arg));
 1289         case LINUX_SETSOCKOPT:
 1290                 return (linux_setsockopt(td, arg));
 1291         case LINUX_GETSOCKOPT:
 1292                 return (linux_getsockopt(td, arg));
 1293         case LINUX_SENDMSG:
 1294                 return (linux_sendmsg(td, arg));
 1295         case LINUX_RECVMSG:
 1296                 return (linux_recvmsg(td, arg));
 1297         }
 1298 
 1299         uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
 1300         return (ENOSYS);
 1301 }
 1302 #endif  /*!__alpha__*/

Cache object: ff5e06a5eacd78e23d3cfb08097dd036


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.