linux_socket.c revision 191548
118316Swollman/*- 218316Swollman * Copyright (c) 1995 S�ren Schmidt 318316Swollman * All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer 1018316Swollman * in this position and unchanged. 1118316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1218316Swollman * notice, this list of conditions and the following disclaimer in the 1318316Swollman * documentation and/or other materials provided with the distribution. 1446303Smarkm * 3. The name of the author may not be used to endorse or promote products 1518316Swollman * derived from this software without specific prior written permission 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1818316Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1918316Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2018316Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2118316Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2218316Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2318316Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2418316Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2518316Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2618316Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2718316Swollman */ 2818316Swollman 2918316Swollman#include <sys/cdefs.h> 3018316Swollman__FBSDID("$FreeBSD: head/sys/compat/linux/linux_socket.c 191548 2009-04-26 22:06:42Z zec $"); 3118316Swollman 3246303Smarkm/* XXX we use functions that might not exist. */ 3350476Speter#include "opt_compat.h" 3418316Swollman#include "opt_inet6.h" 3518316Swollman 3646303Smarkm#include <sys/param.h> 3718316Swollman#include <sys/proc.h> 3818316Swollman#include <sys/systm.h> 3918316Swollman#include <sys/sysproto.h> 4046303Smarkm#include <sys/fcntl.h> 4118316Swollman#include <sys/file.h> 4246303Smarkm#include <sys/limits.h> 4318316Swollman#include <sys/lock.h> 4418316Swollman#include <sys/malloc.h> 4518316Swollman#include <sys/mutex.h> 4618316Swollman#include <sys/mbuf.h> 4718316Swollman#include <sys/socket.h> 4818316Swollman#include <sys/socketvar.h> 4946303Smarkm#include <sys/syscallsubr.h> 5032502Scharnier#include <sys/uio.h> 5146303Smarkm#include <sys/syslog.h> 5218316Swollman#include <sys/un.h> 5318316Swollman#include <sys/vimage.h> 5418316Swollman 5518316Swollman#include <net/if.h> 5618316Swollman#include <netinet/in.h> 5718316Swollman#include <netinet/in_systm.h> 5818316Swollman#include <netinet/ip.h> 5918316Swollman#ifdef INET6 6046303Smarkm#include <netinet/ip6.h> 6146303Smarkm#include <netinet6/ip6_var.h> 6246303Smarkm#include <netinet6/in6_var.h> 6346303Smarkm#include <netinet6/vinet6.h> 6446303Smarkm#endif 6550476Speter 6646303Smarkm#ifdef COMPAT_LINUX32 6718316Swollman#include <machine/../linux32/linux.h> 6818316Swollman#include <machine/../linux32/linux32_proto.h> 6918316Swollman#else 7018316Swollman#include <machine/../linux/linux.h> 7146303Smarkm#include <machine/../linux/linux_proto.h> 7246303Smarkm#endif 7346303Smarkm#include <compat/linux/linux_socket.h> 7446303Smarkm#include <compat/linux/linux_util.h> 7546303Smarkm 7646303Smarkmstatic int do_sa_get(struct sockaddr **, const struct osockaddr *, int *, 7746303Smarkm struct malloc_type *); 7846303Smarkmstatic int linux_to_bsd_domain(int); 7946303Smarkm 8046303Smarkm/* 8146303Smarkm * Reads a linux sockaddr and does any necessary translation. 8218316Swollman * Linux sockaddrs don't have a length field, only a family. 8318316Swollman */ 8418316Swollmanstatic int 8546303Smarkmlinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len) 8618316Swollman{ 8746303Smarkm int osalen = len; 8846303Smarkm 8918316Swollman return (do_sa_get(sap, osa, &osalen, M_SONAME)); 9018316Swollman} 9118316Swollman 9218316Swollman/* 9318316Swollman * Copy the osockaddr structure pointed to by osa to kernel, adjust 9418316Swollman * family and convert to sockaddr. 9518316Swollman */ 9618316Swollmanstatic int 9718316Swollmando_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen, 9818316Swollman struct malloc_type *mtype) 9918316Swollman{ 10018316Swollman int error=0, bdom; 10118316Swollman struct sockaddr *sa; 10218316Swollman struct osockaddr *kosa; 10318316Swollman int alloclen; 10418316Swollman#ifdef INET6 10518316Swollman int oldv6size; 10618316Swollman struct sockaddr_in6 *sin6; 10719880Swollman#endif 10819880Swollman 10919880Swollman if (*osalen < 2 || *osalen > UCHAR_MAX || !osa) 11019880Swollman return (EINVAL); 11118316Swollman 11218316Swollman alloclen = *osalen; 11318316Swollman#ifdef INET6 11446303Smarkm oldv6size = 0; 11546303Smarkm /* 11646303Smarkm * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 11718316Swollman * if it's a v4-mapped address, so reserve the proper space 11846303Smarkm * for it. 11946303Smarkm */ 12046303Smarkm if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) { 12118316Swollman alloclen = sizeof (struct sockaddr_in6); 12218316Swollman oldv6size = 1; 12346303Smarkm } 12437908Scharnier#endif 12518316Swollman 12646303Smarkm kosa = malloc(alloclen, mtype, M_WAITOK); 12737908Scharnier 12818316Swollman if ((error = copyin(osa, kosa, *osalen))) 12918316Swollman goto out; 13018316Swollman 13118316Swollman bdom = linux_to_bsd_domain(kosa->sa_family); 13219880Swollman if (bdom == -1) { 13346303Smarkm error = EINVAL; 13418316Swollman goto out; 13518316Swollman } 13618316Swollman 13718316Swollman#ifdef INET6 13818316Swollman /* 13946303Smarkm * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 14024359Simp * which lacks the scope id compared with RFC2553 one. If we detect 14118316Swollman * the situation, reject the address and write a message to system log. 14218316Swollman * 14318316Swollman * Still accept addresses for which the scope id is not used. 14418316Swollman */ 14518316Swollman if (oldv6size && bdom == AF_INET6) { 14618316Swollman sin6 = (struct sockaddr_in6 *)kosa; 14718316Swollman if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 14818316Swollman (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 14918316Swollman !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 15018316Swollman !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 15118316Swollman !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 15218316Swollman !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 15318316Swollman sin6->sin6_scope_id = 0; 15418316Swollman } else { 15518316Swollman log(LOG_DEBUG, 15618316Swollman "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); 15718316Swollman error = EINVAL; 15818316Swollman goto out; 15918316Swollman } 16018316Swollman } else 16137908Scharnier#endif 16218316Swollman if (bdom == AF_INET) 16318316Swollman alloclen = sizeof(struct sockaddr_in); 16418316Swollman 16518316Swollman sa = (struct sockaddr *) kosa; 16618316Swollman sa->sa_family = bdom; 16737908Scharnier sa->sa_len = alloclen; 16818316Swollman 16918316Swollman *sap = sa; 17018316Swollman *osalen = alloclen; 17146303Smarkm return (0); 17246303Smarkm 17346303Smarkmout: 17446303Smarkm free(kosa, mtype); 17546303Smarkm return (error); 17646303Smarkm} 17746303Smarkm 17846303Smarkmstatic int 17918316Swollmanlinux_to_bsd_domain(int domain) 18018316Swollman{ 18118316Swollman 18218316Swollman switch (domain) { 18318316Swollman case LINUX_AF_UNSPEC: 18418316Swollman return (AF_UNSPEC); 18518316Swollman case LINUX_AF_UNIX: 18618316Swollman return (AF_LOCAL); 18718316Swollman case LINUX_AF_INET: 18818316Swollman return (AF_INET); 18946303Smarkm case LINUX_AF_INET6: 19046303Smarkm return (AF_INET6); 19146303Smarkm case LINUX_AF_AX25: 19246303Smarkm return (AF_CCITT); 19346303Smarkm case LINUX_AF_IPX: 19446303Smarkm return (AF_IPX); 19518316Swollman case LINUX_AF_APPLETALK: 19646303Smarkm return (AF_APPLETALK); 19718316Swollman } 19846303Smarkm return (-1); 19918316Swollman} 20046303Smarkm 20118316Swollmanstatic int 20246303Smarkmbsd_to_linux_domain(int domain) 20318316Swollman{ 20418316Swollman 20546303Smarkm switch (domain) { 20618316Swollman case AF_UNSPEC: 20718316Swollman return (LINUX_AF_UNSPEC); 20818316Swollman case AF_LOCAL: 20918316Swollman return (LINUX_AF_UNIX); 21018316Swollman case AF_INET: 21146303Smarkm return (LINUX_AF_INET); 21246303Smarkm case AF_INET6: 21318316Swollman return (LINUX_AF_INET6); 21418316Swollman case AF_CCITT: 21518316Swollman return (LINUX_AF_AX25); 21646303Smarkm case AF_IPX: 21718316Swollman return (LINUX_AF_IPX); 21818316Swollman case AF_APPLETALK: 21918316Swollman return (LINUX_AF_APPLETALK); 22018316Swollman } 22146303Smarkm return (-1); 22218316Swollman} 22318316Swollman 22418316Swollmanstatic int 22518316Swollmanlinux_to_bsd_sockopt_level(int level) 22646303Smarkm{ 22718316Swollman 22846303Smarkm switch (level) { 22918316Swollman case LINUX_SOL_SOCKET: 23018316Swollman return (SOL_SOCKET); 23137908Scharnier } 23218316Swollman return (level); 23346303Smarkm} 23446303Smarkm 23518316Swollmanstatic int 23618316Swollmanbsd_to_linux_sockopt_level(int level) 23718316Swollman{ 23819880Swollman 23919880Swollman switch (level) { 24019880Swollman case SOL_SOCKET: 24119880Swollman return (LINUX_SOL_SOCKET); 24237908Scharnier } 24319880Swollman return (level); 24419880Swollman} 24519880Swollman 24619880Swollmanstatic int 24719880Swollmanlinux_to_bsd_ip_sockopt(int opt) 24819880Swollman{ 24937908Scharnier 25019880Swollman switch (opt) { 25146303Smarkm case LINUX_IP_TOS: 25237908Scharnier return (IP_TOS); 25319880Swollman case LINUX_IP_TTL: 25419880Swollman return (IP_TTL); 25519880Swollman case LINUX_IP_OPTIONS: 25619880Swollman return (IP_OPTIONS); 25737908Scharnier case LINUX_IP_MULTICAST_IF: 25819880Swollman return (IP_MULTICAST_IF); 25937908Scharnier case LINUX_IP_MULTICAST_TTL: 26019880Swollman return (IP_MULTICAST_TTL); 26119880Swollman case LINUX_IP_MULTICAST_LOOP: 26219880Swollman return (IP_MULTICAST_LOOP); 26318316Swollman case LINUX_IP_ADD_MEMBERSHIP: 26437908Scharnier return (IP_ADD_MEMBERSHIP); 26518316Swollman case LINUX_IP_DROP_MEMBERSHIP: 26618316Swollman return (IP_DROP_MEMBERSHIP); 26718316Swollman case LINUX_IP_HDRINCL: 26846303Smarkm return (IP_HDRINCL); 26937908Scharnier } 27046303Smarkm return (-1); 27146303Smarkm} 27246303Smarkm 27346303Smarkmstatic int 27418316Swollmanlinux_to_bsd_so_sockopt(int opt) 27546303Smarkm{ 27646303Smarkm 27746524Smarkm switch (opt) { 27846524Smarkm case LINUX_SO_DEBUG: 27946303Smarkm return (SO_DEBUG); 28018316Swollman case LINUX_SO_REUSEADDR: 28118316Swollman return (SO_REUSEADDR); 28218316Swollman case LINUX_SO_TYPE: 28346303Smarkm return (SO_TYPE); 28418316Swollman case LINUX_SO_ERROR: 28518316Swollman return (SO_ERROR); 28618316Swollman case LINUX_SO_DONTROUTE: 28746524Smarkm return (SO_DONTROUTE); 28818316Swollman case LINUX_SO_BROADCAST: 28918316Swollman return (SO_BROADCAST); 29018316Swollman case LINUX_SO_SNDBUF: 29118316Swollman return (SO_SNDBUF); 29218316Swollman case LINUX_SO_RCVBUF: 29318316Swollman return (SO_RCVBUF); 29418316Swollman case LINUX_SO_KEEPALIVE: 29518316Swollman return (SO_KEEPALIVE); 29618316Swollman case LINUX_SO_OOBINLINE: 29746303Smarkm return (SO_OOBINLINE); 29818316Swollman case LINUX_SO_LINGER: 29918316Swollman return (SO_LINGER); 30046303Smarkm case LINUX_SO_PEERCRED: 30137908Scharnier return (LOCAL_PEERCRED); 30246303Smarkm case LINUX_SO_RCVLOWAT: 30337908Scharnier return (SO_RCVLOWAT); 30446303Smarkm case LINUX_SO_SNDLOWAT: 30546303Smarkm return (SO_SNDLOWAT); 30646303Smarkm case LINUX_SO_RCVTIMEO: 30746303Smarkm return (SO_RCVTIMEO); 30846303Smarkm case LINUX_SO_SNDTIMEO: 30937908Scharnier return (SO_SNDTIMEO); 31037908Scharnier case LINUX_SO_TIMESTAMP: 31118316Swollman return (SO_TIMESTAMP); 31246303Smarkm case LINUX_SO_ACCEPTCONN: 31318316Swollman return (SO_ACCEPTCONN); 31418316Swollman } 31518316Swollman return (-1); 31618316Swollman} 31718316Swollman 31818316Swollmanstatic int 31918316Swollmanlinux_to_bsd_msg_flags(int flags) 32018316Swollman{ 32146303Smarkm int ret_flags = 0; 32246303Smarkm 32346303Smarkm if (flags & LINUX_MSG_OOB) 32446303Smarkm ret_flags |= MSG_OOB; 32518316Swollman if (flags & LINUX_MSG_PEEK) 32618316Swollman ret_flags |= MSG_PEEK; 32718316Swollman if (flags & LINUX_MSG_DONTROUTE) 32818316Swollman ret_flags |= MSG_DONTROUTE; 32918316Swollman if (flags & LINUX_MSG_CTRUNC) 33018316Swollman ret_flags |= MSG_CTRUNC; 33118316Swollman if (flags & LINUX_MSG_TRUNC) 33246303Smarkm ret_flags |= MSG_TRUNC; 33318316Swollman if (flags & LINUX_MSG_DONTWAIT) 33418316Swollman ret_flags |= MSG_DONTWAIT; 33518316Swollman if (flags & LINUX_MSG_EOR) 33618316Swollman ret_flags |= MSG_EOR; 33718316Swollman if (flags & LINUX_MSG_WAITALL) 33846303Smarkm ret_flags |= MSG_WAITALL; 33946303Smarkm if (flags & LINUX_MSG_NOSIGNAL) 34046303Smarkm ret_flags |= MSG_NOSIGNAL; 34146524Smarkm#if 0 /* not handled */ 34246524Smarkm if (flags & LINUX_MSG_PROXY) 34346303Smarkm ; 34418316Swollman if (flags & LINUX_MSG_FIN) 34518316Swollman ; 34618316Swollman if (flags & LINUX_MSG_SYN) 34718316Swollman ; 34818316Swollman if (flags & LINUX_MSG_CONFIRM) 34918316Swollman ; 35018316Swollman if (flags & LINUX_MSG_RST) 35118316Swollman ; 35218316Swollman if (flags & LINUX_MSG_ERRQUEUE) 35318316Swollman ; 35418316Swollman#endif 35518316Swollman return ret_flags; 35618316Swollman} 35718316Swollman 35818316Swollman/* 35918316Swollman* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the 36018316Swollman* native syscall will fault. Thus, we don't really need to check the 36119880Swollman* return values for these functions. 36219880Swollman*/ 36318316Swollman 36418316Swollmanstatic int 36518316Swollmanbsd_to_linux_sockaddr(struct sockaddr *arg) 36618316Swollman{ 36718316Swollman struct sockaddr sa; 36818316Swollman size_t sa_len = sizeof(struct sockaddr); 36918316Swollman int error; 37018316Swollman 37118316Swollman if ((error = copyin(arg, &sa, sa_len))) 37218316Swollman return (error); 37319880Swollman 37418316Swollman *(u_short *)&sa = sa.sa_family; 37518316Swollman 37618316Swollman error = copyout(&sa, arg, sa_len); 37718316Swollman 37818316Swollman return (error); 37919880Swollman} 38019880Swollman 38119880Swollmanstatic int 38219880Swollmanlinux_to_bsd_sockaddr(struct sockaddr *arg, int len) 38346303Smarkm{ 38419880Swollman struct sockaddr sa; 38519880Swollman size_t sa_len = sizeof(struct sockaddr); 38619880Swollman int error; 38719880Swollman 38819880Swollman if ((error = copyin(arg, &sa, sa_len))) 38919880Swollman return (error); 39019880Swollman 39146303Smarkm sa.sa_family = *(sa_family_t *)&sa; 39219880Swollman sa.sa_len = len; 39346303Smarkm 39446303Smarkm error = copyout(&sa, arg, sa_len); 39519880Swollman 39646303Smarkm return (error); 39719880Swollman} 39846303Smarkm 39946303Smarkm 40046303Smarkmstatic int 40146303Smarkmlinux_sa_put(struct osockaddr *osa) 40219880Swollman{ 40319880Swollman struct osockaddr sa; 40419880Swollman int error, bdom; 40519880Swollman 40618316Swollman /* 40718316Swollman * Only read/write the osockaddr family part, the rest is 40818316Swollman * not changed. 40918316Swollman */ 41018316Swollman error = copyin(osa, &sa, sizeof(sa.sa_family)); 41118316Swollman if (error) 41218316Swollman return (error); 41318316Swollman 41418316Swollman bdom = bsd_to_linux_domain(sa.sa_family); 41546303Smarkm if (bdom == -1) 41618316Swollman return (EINVAL); 41718316Swollman 41818316Swollman sa.sa_family = bdom; 41918316Swollman error = copyout(&sa, osa, sizeof(sa.sa_family)); 42018316Swollman if (error) 42146303Smarkm return (error); 42218316Swollman 42318316Swollman return (0); 42446303Smarkm} 42518316Swollman 42618316Swollmanstatic int 42746303Smarkmlinux_to_bsd_cmsg_type(int cmsg_type) 42818316Swollman{ 42918316Swollman 43046303Smarkm switch (cmsg_type) { 43146524Smarkm case LINUX_SCM_RIGHTS: 43246524Smarkm return (SCM_RIGHTS); 43346303Smarkm } 43418316Swollman return (-1); 43518316Swollman} 43618316Swollman 43718316Swollmanstatic int 43818316Swollmanbsd_to_linux_cmsg_type(int cmsg_type) 43918316Swollman{ 44018316Swollman 44118316Swollman switch (cmsg_type) { 44218316Swollman case SCM_RIGHTS: 44318316Swollman return (LINUX_SCM_RIGHTS); 44418316Swollman } 44518316Swollman return (-1); 44646303Smarkm} 44746303Smarkm 44846303Smarkm 44946303Smarkm 45046303Smarkmstatic int 45118316Swollmanlinux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 45218316Swollman{ 45318316Swollman if (lhdr->msg_controllen > INT_MAX) 45418316Swollman return (ENOBUFS); 45518316Swollman 45618316Swollman bhdr->msg_name = PTRIN(lhdr->msg_name); 45718316Swollman bhdr->msg_namelen = lhdr->msg_namelen; 45818316Swollman bhdr->msg_iov = PTRIN(lhdr->msg_iov); 45918316Swollman bhdr->msg_iovlen = lhdr->msg_iovlen; 46018316Swollman bhdr->msg_control = PTRIN(lhdr->msg_control); 46118316Swollman bhdr->msg_controllen = lhdr->msg_controllen; 46232502Scharnier bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 46318316Swollman return (0); 46446524Smarkm} 46546524Smarkm 46618316Swollmanstatic int 46718316Swollmanbsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 46818316Swollman{ 46918316Swollman lhdr->msg_name = PTROUT(bhdr->msg_name); 47018316Swollman lhdr->msg_namelen = bhdr->msg_namelen; 47118316Swollman lhdr->msg_iov = PTROUT(bhdr->msg_iov); 47218316Swollman lhdr->msg_iovlen = bhdr->msg_iovlen; 47318316Swollman lhdr->msg_control = PTROUT(bhdr->msg_control); 47418316Swollman lhdr->msg_controllen = bhdr->msg_controllen; 47518316Swollman /* msg_flags skipped */ 47618316Swollman return (0); 47718316Swollman} 47818316Swollman 47918316Swollmanstatic int 48018316Swollmanlinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 48118316Swollman struct mbuf *control, enum uio_seg segflg) 48246303Smarkm{ 48346524Smarkm struct sockaddr *to; 48446524Smarkm int error; 48546303Smarkm 48618316Swollman if (mp->msg_name != NULL) { 48718316Swollman error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 48818316Swollman if (error) 48918316Swollman return (error); 49018316Swollman mp->msg_name = to; 49118316Swollman } else 49218316Swollman to = NULL; 49318316Swollman 49418316Swollman error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 49519880Swollman segflg); 49618316Swollman 49718316Swollman if (to) 49846303Smarkm free(to, M_SONAME); 49918316Swollman return (error); 50018316Swollman} 50118316Swollman 50218316Swollman/* Return 0 if IP_HDRINCL is set for the given socket. */ 50318316Swollmanstatic int 50446524Smarkmlinux_check_hdrincl(struct thread *td, int s) 50546524Smarkm{ 50618316Swollman int error, optval, size_val; 50718316Swollman 50846303Smarkm size_val = sizeof(optval); 50918316Swollman error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 51018316Swollman &optval, UIO_SYSSPACE, &size_val); 51118316Swollman if (error) 51218316Swollman return (error); 51318316Swollman 51418316Swollman return (optval == 0); 51518316Swollman} 51618316Swollman 51718316Swollmanstruct linux_sendto_args { 51818316Swollman int s; 51946303Smarkm l_uintptr_t msg; 52018316Swollman int len; 52118316Swollman int flags; 52218316Swollman l_uintptr_t to; 52346303Smarkm int tolen; 52418316Swollman}; 52546524Smarkm 52646524Smarkm/* 52718316Swollman * Updated sendto() when IP_HDRINCL is set: 52818316Swollman * tweak endian-dependent fields in the IP packet. 52918316Swollman */ 53018316Swollmanstatic int 53118316Swollmanlinux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 53218316Swollman{ 53318316Swollman/* 53419880Swollman * linux_ip_copysize defines how many bytes we should copy 53519880Swollman * from the beginning of the IP packet before we customize it for BSD. 53619880Swollman * It should include all the fields we modify (ip_len and ip_off). 53719880Swollman */ 53819880Swollman#define linux_ip_copysize 8 53919880Swollman 54019880Swollman struct ip *packet; 54119880Swollman struct msghdr msg; 54219880Swollman struct iovec aiov[1]; 54319880Swollman int error; 54419880Swollman 54519880Swollman /* Check that the packet isn't too big or too small. */ 54619880Swollman if (linux_args->len < linux_ip_copysize || 54719880Swollman linux_args->len > IP_MAXPACKET) 54819880Swollman return (EINVAL); 54919880Swollman 55019880Swollman packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK); 55119880Swollman 55219880Swollman /* Make kernel copy of the packet to be sent */ 55319880Swollman if ((error = copyin(PTRIN(linux_args->msg), packet, 55419880Swollman linux_args->len))) 55519880Swollman goto goout; 55619880Swollman 55719880Swollman /* Convert fields from Linux to BSD raw IP socket format */ 55819880Swollman packet->ip_len = linux_args->len; 55919880Swollman packet->ip_off = ntohs(packet->ip_off); 56019880Swollman 56119880Swollman /* Prepare the msghdr and iovec structures describing the new packet */ 56219880Swollman msg.msg_name = PTRIN(linux_args->to); 56319880Swollman msg.msg_namelen = linux_args->tolen; 56419880Swollman msg.msg_iov = aiov; 56519880Swollman msg.msg_iovlen = 1; 56619880Swollman msg.msg_control = NULL; 56719880Swollman msg.msg_flags = 0; 56819880Swollman aiov[0].iov_base = (char *)packet; 56919880Swollman aiov[0].iov_len = linux_args->len; 57019880Swollman error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 57119880Swollman NULL, UIO_SYSSPACE); 57219880Swollmangoout: 57319880Swollman free(packet, M_TEMP); 57419880Swollman return (error); 57519880Swollman} 57619880Swollman 57719880Swollmanstruct linux_socket_args { 57819880Swollman int domain; 57919880Swollman int type; 58019880Swollman int protocol; 58119880Swollman}; 58219880Swollman 58319880Swollmanstatic int 58419880Swollmanlinux_socket(struct thread *td, struct linux_socket_args *args) 58519880Swollman{ 58619880Swollman#ifdef INET6 58719880Swollman#ifndef KLD_MODULE 58818316Swollman INIT_VNET_INET6(curvnet); 58918316Swollman#endif 59018316Swollman#endif 59118316Swollman struct socket_args /* { 59218316Swollman int domain; 59318316Swollman int type; 59418316Swollman int protocol; 59518316Swollman } */ bsd_args; 59646303Smarkm int retval_socket; 59718316Swollman 59846303Smarkm bsd_args.protocol = args->protocol; 59946303Smarkm bsd_args.type = args->type; 60046303Smarkm bsd_args.domain = linux_to_bsd_domain(args->domain); 60118316Swollman if (bsd_args.domain == -1) 60218316Swollman return (EINVAL); 60318316Swollman 60418316Swollman retval_socket = socket(td, &bsd_args); 60518316Swollman if (bsd_args.type == SOCK_RAW 60619880Swollman && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 60718316Swollman && bsd_args.domain == AF_INET 60818316Swollman && retval_socket >= 0) { 60918316Swollman /* It's a raw IP socket: set the IP_HDRINCL option. */ 61018316Swollman int hdrincl; 61118316Swollman 61218316Swollman hdrincl = 1; 61318316Swollman /* We ignore any error returned by kern_setsockopt() */ 61418316Swollman kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 61518316Swollman &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 61618316Swollman } 61718316Swollman#ifdef INET6 61818316Swollman /* 61918316Swollman * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 62018316Swollman * default and some apps depend on this. So, set V6ONLY to 0 62118316Swollman * for Linux apps if the sysctl value is set to 1. 62218316Swollman */ 62318316Swollman if (bsd_args.domain == PF_INET6 && retval_socket >= 0 62418316Swollman#ifndef KLD_MODULE 62518316Swollman /* 62618316Swollman * XXX: Avoid undefined symbol error with an IPv4 only 62718316Swollman * kernel. 62818316Swollman */ 62918316Swollman && V_ip6_v6only 63046303Smarkm#endif 63118316Swollman ) { 63218316Swollman int v6only; 63346303Smarkm 63418316Swollman v6only = 0; 63518316Swollman /* We ignore any error returned by setsockopt() */ 63618316Swollman kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 63718316Swollman &v6only, UIO_SYSSPACE, sizeof(v6only)); 63818316Swollman } 63918316Swollman#endif 64018316Swollman 64118316Swollman return (retval_socket); 64218316Swollman} 64318316Swollman 64418316Swollmanstruct linux_bind_args { 64518316Swollman int s; 64618316Swollman l_uintptr_t name; 64718316Swollman int namelen; 64818316Swollman}; 64918316Swollman 65018316Swollmanstatic int 65118316Swollmanlinux_bind(struct thread *td, struct linux_bind_args *args) 65218316Swollman{ 65318316Swollman struct sockaddr *sa; 65418316Swollman int error; 65518316Swollman 65618316Swollman error = linux_getsockaddr(&sa, PTRIN(args->name), 65718316Swollman args->namelen); 65818316Swollman if (error) 65918316Swollman return (error); 66018316Swollman 66118316Swollman error = kern_bind(td, args->s, sa); 66218316Swollman free(sa, M_SONAME); 66318316Swollman if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 66418316Swollman return (EINVAL); 66518316Swollman return (error); 66618316Swollman} 66718316Swollman 66818316Swollmanstruct linux_connect_args { 66918316Swollman int s; 67018316Swollman l_uintptr_t name; 67118316Swollman int namelen; 67218316Swollman}; 67318316Swollmanint linux_connect(struct thread *, struct linux_connect_args *); 67418316Swollman 67518316Swollmanint 67618316Swollmanlinux_connect(struct thread *td, struct linux_connect_args *args) 67718316Swollman{ 67818316Swollman struct socket *so; 67918316Swollman struct sockaddr *sa; 68018316Swollman u_int fflag; 68118316Swollman int error; 68218316Swollman 68318316Swollman error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), 68418316Swollman args->namelen); 68518316Swollman if (error) 68618316Swollman return (error); 68718316Swollman 68818316Swollman error = kern_connect(td, args->s, sa); 68918316Swollman free(sa, M_SONAME); 69018316Swollman if (error != EISCONN) 69118316Swollman return (error); 69218316Swollman 69318316Swollman /* 69418316Swollman * Linux doesn't return EISCONN the first time it occurs, 69518316Swollman * when on a non-blocking socket. Instead it returns the 69618316Swollman * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 69718316Swollman * 69818316Swollman * XXXRW: Instead of using fgetsock(), check that it is a 69918316Swollman * socket and use the file descriptor reference instead of 70018316Swollman * creating a new one. 70118316Swollman */ 70218316Swollman error = fgetsock(td, args->s, &so, &fflag); 70319880Swollman if (error == 0) { 70419880Swollman error = EISCONN; 70519880Swollman if (fflag & FNONBLOCK) { 70619880Swollman SOCK_LOCK(so); 70719880Swollman if (so->so_emuldata == 0) 70819880Swollman error = so->so_error; 70919880Swollman so->so_emuldata = (void *)1; 71019880Swollman SOCK_UNLOCK(so); 71119880Swollman } 71219880Swollman fputsock(so); 71319880Swollman } 71419880Swollman return (error); 71546303Smarkm} 71619880Swollman 71746303Smarkmstruct linux_listen_args { 71846303Smarkm int s; 71919880Swollman int backlog; 72046303Smarkm}; 72119880Swollman 72246303Smarkmstatic int 72346303Smarkmlinux_listen(struct thread *td, struct linux_listen_args *args) 72419880Swollman{ 72519880Swollman struct listen_args /* { 72646303Smarkm int s; 72719880Swollman int backlog; 72819880Swollman } */ bsd_args; 72919880Swollman 73019880Swollman bsd_args.s = args->s; 73146303Smarkm bsd_args.backlog = args->backlog; 73219880Swollman return (listen(td, &bsd_args)); 73318316Swollman} 73446303Smarkm 73546303Smarkmstruct linux_accept_args { 73646303Smarkm int s; 73746303Smarkm l_uintptr_t addr; 73846303Smarkm l_uintptr_t namelen; 73946303Smarkm}; 74046303Smarkm 74146303Smarkmstatic int 74246303Smarkmlinux_accept(struct thread *td, struct linux_accept_args *args) 74346303Smarkm{ 74446303Smarkm struct accept_args /* { 74546303Smarkm int s; 74646303Smarkm struct sockaddr * __restrict name; 74718316Swollman socklen_t * __restrict anamelen; 74818316Swollman } */ bsd_args; 74918316Swollman int error, fd; 75018316Swollman 75118316Swollman bsd_args.s = args->s; 75218316Swollman /* XXX: */ 75318316Swollman bsd_args.name = (struct sockaddr * __restrict)PTRIN(args->addr); 75418316Swollman bsd_args.anamelen = PTRIN(args->namelen);/* XXX */ 75518316Swollman error = accept(td, &bsd_args); 75618316Swollman bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); 75718316Swollman if (error) { 75818316Swollman if (error == EFAULT && args->namelen != sizeof(struct sockaddr_in)) 75946303Smarkm return (EINVAL); 76018316Swollman return (error); 76118316Swollman } 76218316Swollman if (args->addr) { 76318316Swollman error = linux_sa_put(PTRIN(args->addr)); 76418316Swollman if (error) { 76518316Swollman (void)kern_close(td, td->td_retval[0]); 76618316Swollman return (error); 76718316Swollman } 76818316Swollman } 76918316Swollman 77018316Swollman /* 77118316Swollman * linux appears not to copy flags from the parent socket to the 77218316Swollman * accepted one, so we must clear the flags in the new descriptor. 77318316Swollman * Ignore any errors, because we already have an open fd. 77418316Swollman */ 77518316Swollman fd = td->td_retval[0]; 77618316Swollman (void)kern_fcntl(td, fd, F_SETFL, 0); 77718316Swollman td->td_retval[0] = fd; 77818316Swollman return (0); 77918316Swollman} 78018316Swollman 78118316Swollmanstruct linux_getsockname_args { 78218316Swollman int s; 78318316Swollman l_uintptr_t addr; 78418316Swollman l_uintptr_t namelen; 78590868Smike}; 78618316Swollman 78718316Swollmanstatic int 78818316Swollmanlinux_getsockname(struct thread *td, struct linux_getsockname_args *args) 78918316Swollman{ 79018316Swollman struct getsockname_args /* { 79118316Swollman int fdes; 79218316Swollman struct sockaddr * __restrict asa; 79318316Swollman socklen_t * __restrict alen; 79418316Swollman } */ bsd_args; 79518316Swollman int error; 79618316Swollman 79718316Swollman bsd_args.fdes = args->s; 79818316Swollman /* XXX: */ 79918316Swollman bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); 80018316Swollman bsd_args.alen = PTRIN(args->namelen); /* XXX */ 80118316Swollman error = getsockname(td, &bsd_args); 80218316Swollman bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 80318316Swollman if (error) 80418316Swollman return (error); 80518316Swollman error = linux_sa_put(PTRIN(args->addr)); 80618316Swollman if (error) 80718316Swollman return (error); 80818316Swollman return (0); 80918316Swollman} 81018316Swollman 81118316Swollmanstruct linux_getpeername_args { 81218316Swollman int s; 81318316Swollman l_uintptr_t addr; 81446303Smarkm l_uintptr_t namelen; 81518316Swollman}; 81646303Smarkm 81718316Swollmanstatic int 81846303Smarkmlinux_getpeername(struct thread *td, struct linux_getpeername_args *args) 81918316Swollman{ 82018316Swollman struct getpeername_args /* { 82118316Swollman int fdes; 82218316Swollman caddr_t asa; 82318316Swollman int *alen; 82418316Swollman } */ bsd_args; 82518316Swollman int error; 82618316Swollman 82718316Swollman bsd_args.fdes = args->s; 82890868Smike bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); 82918316Swollman bsd_args.alen = (int *)PTRIN(args->namelen); 83018316Swollman error = getpeername(td, &bsd_args); 83118316Swollman bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 83218316Swollman if (error) 83318316Swollman return (error); 83418316Swollman error = linux_sa_put(PTRIN(args->addr)); 83518316Swollman if (error) 83618316Swollman return (error); 83718316Swollman return (0); 83818316Swollman} 83918316Swollman 84018316Swollmanstruct linux_socketpair_args { 84118316Swollman int domain; 84218316Swollman int type; 84318316Swollman int protocol; 84418316Swollman l_uintptr_t rsv; 84518316Swollman}; 84618316Swollman 84718316Swollmanstatic int 84818316Swollmanlinux_socketpair(struct thread *td, struct linux_socketpair_args *args) 84919880Swollman{ 85019880Swollman struct socketpair_args /* { 85119880Swollman int domain; 85219880Swollman int type; 85319880Swollman int protocol; 85419880Swollman int *rsv; 85546303Smarkm } */ bsd_args; 85619880Swollman 85719880Swollman bsd_args.domain = linux_to_bsd_domain(args->domain); 85819880Swollman if (bsd_args.domain == -1) 85919880Swollman return (EINVAL); 86046303Smarkm 86146303Smarkm bsd_args.type = args->type; 86219880Swollman bsd_args.protocol = args->protocol; 86319880Swollman bsd_args.rsv = (int *)PTRIN(args->rsv); 86419880Swollman return (socketpair(td, &bsd_args)); 86519880Swollman} 86619880Swollman 86719880Swollmanstruct linux_send_args { 86819880Swollman int s; 86919880Swollman l_uintptr_t msg; 87019880Swollman int len; 87119880Swollman int flags; 87219880Swollman}; 87319880Swollman 87419880Swollmanstatic int 87537815Sphklinux_send(struct thread *td, struct linux_send_args *args) 87619880Swollman{ 87719880Swollman struct sendto_args /* { 87819880Swollman int s; 87919880Swollman caddr_t buf; 88019880Swollman int len; 88119880Swollman int flags; 88219880Swollman caddr_t to; 88319880Swollman int tolen; 88419880Swollman } */ bsd_args; 88519880Swollman 88619880Swollman bsd_args.s = args->s; 88719880Swollman bsd_args.buf = (caddr_t)PTRIN(args->msg); 88819880Swollman bsd_args.len = args->len; 88919880Swollman bsd_args.flags = args->flags; 89019880Swollman bsd_args.to = NULL; 89119880Swollman bsd_args.tolen = 0; 89219880Swollman return sendto(td, &bsd_args); 89319880Swollman} 89419880Swollman 89519880Swollmanstruct linux_recv_args { 89619880Swollman int s; 89719880Swollman l_uintptr_t msg; 89819880Swollman int len; 89919880Swollman int flags; 90019880Swollman}; 90119880Swollman 90219880Swollmanstatic int 90319880Swollmanlinux_recv(struct thread *td, struct linux_recv_args *args) 90419880Swollman{ 90519880Swollman struct recvfrom_args /* { 90619880Swollman int s; 90719880Swollman caddr_t buf; 90819880Swollman int len; 90919880Swollman int flags; 91019880Swollman struct sockaddr *from; 911 socklen_t fromlenaddr; 912 } */ bsd_args; 913 914 bsd_args.s = args->s; 915 bsd_args.buf = (caddr_t)PTRIN(args->msg); 916 bsd_args.len = args->len; 917 bsd_args.flags = args->flags; 918 bsd_args.from = NULL; 919 bsd_args.fromlenaddr = 0; 920 return (recvfrom(td, &bsd_args)); 921} 922 923static int 924linux_sendto(struct thread *td, struct linux_sendto_args *args) 925{ 926 struct msghdr msg; 927 struct iovec aiov; 928 int error; 929 930 if (linux_check_hdrincl(td, args->s) == 0) 931 /* IP_HDRINCL set, tweak the packet before sending */ 932 return (linux_sendto_hdrincl(td, args)); 933 934 msg.msg_name = PTRIN(args->to); 935 msg.msg_namelen = args->tolen; 936 msg.msg_iov = &aiov; 937 msg.msg_iovlen = 1; 938 msg.msg_control = NULL; 939 msg.msg_flags = 0; 940 aiov.iov_base = PTRIN(args->msg); 941 aiov.iov_len = args->len; 942 error = linux_sendit(td, args->s, &msg, args->flags, NULL, 943 UIO_USERSPACE); 944 return (error); 945} 946 947struct linux_recvfrom_args { 948 int s; 949 l_uintptr_t buf; 950 int len; 951 int flags; 952 l_uintptr_t from; 953 l_uintptr_t fromlen; 954}; 955 956static int 957linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 958{ 959 struct recvfrom_args /* { 960 int s; 961 caddr_t buf; 962 size_t len; 963 int flags; 964 struct sockaddr * __restrict from; 965 socklen_t * __restrict fromlenaddr; 966 } */ bsd_args; 967 size_t len; 968 int error; 969 970 if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t)))) 971 return (error); 972 973 bsd_args.s = args->s; 974 bsd_args.buf = PTRIN(args->buf); 975 bsd_args.len = args->len; 976 bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 977 /* XXX: */ 978 bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from); 979 bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */ 980 981 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len); 982 error = recvfrom(td, &bsd_args); 983 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from); 984 985 if (error) 986 return (error); 987 if (args->from) { 988 error = linux_sa_put((struct osockaddr *) 989 PTRIN(args->from)); 990 if (error) 991 return (error); 992 } 993 return (0); 994} 995 996struct linux_sendmsg_args { 997 int s; 998 l_uintptr_t msg; 999 int flags; 1000}; 1001 1002static int 1003linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1004{ 1005 struct cmsghdr *cmsg; 1006 struct mbuf *control; 1007 struct msghdr msg; 1008 struct l_cmsghdr linux_cmsg; 1009 struct l_cmsghdr *ptr_cmsg; 1010 struct l_msghdr linux_msg; 1011 struct iovec *iov; 1012 socklen_t datalen; 1013 void *data; 1014 int error; 1015 1016 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1017 if (error) 1018 return (error); 1019 error = linux_to_bsd_msghdr(&msg, &linux_msg); 1020 if (error) 1021 return (error); 1022 1023 /* 1024 * Some Linux applications (ping) define a non-NULL control data 1025 * pointer, but a msg_controllen of 0, which is not allowed in the 1026 * FreeBSD system call interface. NULL the msg_control pointer in 1027 * order to handle this case. This should be checked, but allows the 1028 * Linux ping to work. 1029 */ 1030 if (msg.msg_control != NULL && msg.msg_controllen == 0) 1031 msg.msg_control = NULL; 1032 1033#ifdef COMPAT_LINUX32 1034 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1035 &iov, EMSGSIZE); 1036#else 1037 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1038#endif 1039 if (error) 1040 return (error); 1041 1042 if (msg.msg_control != NULL) { 1043 error = ENOBUFS; 1044 cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1045 control = m_get(M_WAIT, MT_CONTROL); 1046 if (control == NULL) 1047 goto bad; 1048 ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg); 1049 1050 do { 1051 error = copyin(ptr_cmsg, &linux_cmsg, 1052 sizeof(struct l_cmsghdr)); 1053 if (error) 1054 goto bad; 1055 1056 error = EINVAL; 1057 if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) 1058 goto bad; 1059 1060 /* 1061 * Now we support only SCM_RIGHTS, so return EINVAL 1062 * in any other cmsg_type 1063 */ 1064 if ((cmsg->cmsg_type = 1065 linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1) 1066 goto bad; 1067 cmsg->cmsg_level = 1068 linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1069 1070 datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1071 cmsg->cmsg_len = CMSG_LEN(datalen); 1072 data = LINUX_CMSG_DATA(ptr_cmsg); 1073 1074 error = ENOBUFS; 1075 if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg)) 1076 goto bad; 1077 if (!m_append(control, datalen, (c_caddr_t) data)) 1078 goto bad; 1079 } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg))); 1080 } else { 1081 control = NULL; 1082 cmsg = NULL; 1083 } 1084 1085 msg.msg_iov = iov; 1086 msg.msg_flags = 0; 1087 error = linux_sendit(td, args->s, &msg, args->flags, control, 1088 UIO_USERSPACE); 1089 1090bad: 1091 free(iov, M_IOV); 1092 if (cmsg) 1093 free(cmsg, M_TEMP); 1094 return (error); 1095} 1096 1097struct linux_recvmsg_args { 1098 int s; 1099 l_uintptr_t msg; 1100 int flags; 1101}; 1102 1103static int 1104linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1105{ 1106 struct cmsghdr *cm; 1107 struct msghdr msg; 1108 struct l_cmsghdr *linux_cmsg = NULL; 1109 socklen_t datalen, outlen, clen; 1110 struct l_msghdr linux_msg; 1111 struct iovec *iov, *uiov; 1112 struct mbuf *control = NULL; 1113 struct mbuf **controlp; 1114 caddr_t outbuf; 1115 void *data; 1116 int error; 1117 1118 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1119 if (error) 1120 return (error); 1121 1122 error = linux_to_bsd_msghdr(&msg, &linux_msg); 1123 if (error) 1124 return (error); 1125 1126#ifdef COMPAT_LINUX32 1127 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1128 &iov, EMSGSIZE); 1129#else 1130 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1131#endif 1132 if (error) 1133 return (error); 1134 1135 if (msg.msg_name) { 1136 error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, 1137 msg.msg_namelen); 1138 if (error) 1139 goto bad; 1140 } 1141 1142 uiov = msg.msg_iov; 1143 msg.msg_iov = iov; 1144 controlp = (msg.msg_control != NULL) ? &control : NULL; 1145 error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); 1146 msg.msg_iov = uiov; 1147 if (error) 1148 goto bad; 1149 1150 error = bsd_to_linux_msghdr(&msg, &linux_msg); 1151 if (error) 1152 goto bad; 1153 1154 if (linux_msg.msg_name) { 1155 error = bsd_to_linux_sockaddr((struct sockaddr *) 1156 PTRIN(linux_msg.msg_name)); 1157 if (error) 1158 goto bad; 1159 } 1160 if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { 1161 error = linux_sa_put(PTRIN(linux_msg.msg_name)); 1162 if (error) 1163 goto bad; 1164 } 1165 1166 if (control) { 1167 1168 linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1169 outbuf = PTRIN(linux_msg.msg_control); 1170 cm = mtod(control, struct cmsghdr *); 1171 outlen = 0; 1172 clen = control->m_len; 1173 1174 while (cm != NULL) { 1175 1176 if ((linux_cmsg->cmsg_type = 1177 bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1) 1178 { 1179 error = EINVAL; 1180 goto bad; 1181 } 1182 data = CMSG_DATA(cm); 1183 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1184 1185 if (outlen + LINUX_CMSG_LEN(datalen) > 1186 linux_msg.msg_controllen) { 1187 if (outlen == 0) { 1188 error = EMSGSIZE; 1189 goto bad; 1190 } else { 1191 linux_msg.msg_flags |= LINUX_MSG_CTRUNC; 1192 goto out; 1193 } 1194 } 1195 1196 linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 1197 linux_cmsg->cmsg_level = 1198 bsd_to_linux_sockopt_level(cm->cmsg_level); 1199 1200 error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1201 if (error) 1202 goto bad; 1203 outbuf += L_CMSG_HDRSZ; 1204 1205 error = copyout(data, outbuf, datalen); 1206 if (error) 1207 goto bad; 1208 1209 outbuf += LINUX_CMSG_ALIGN(datalen); 1210 outlen += LINUX_CMSG_LEN(datalen); 1211 linux_msg.msg_controllen = outlen; 1212 1213 if (CMSG_SPACE(datalen) < clen) { 1214 clen -= CMSG_SPACE(datalen); 1215 cm = (struct cmsghdr *) 1216 ((caddr_t)cm + CMSG_SPACE(datalen)); 1217 } else 1218 cm = NULL; 1219 } 1220 } 1221 1222out: 1223 error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); 1224 1225bad: 1226 free(iov, M_IOV); 1227 if (control != NULL) 1228 m_freem(control); 1229 if (linux_cmsg != NULL) 1230 free(linux_cmsg, M_TEMP); 1231 1232 return (error); 1233} 1234 1235struct linux_shutdown_args { 1236 int s; 1237 int how; 1238}; 1239 1240static int 1241linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1242{ 1243 struct shutdown_args /* { 1244 int s; 1245 int how; 1246 } */ bsd_args; 1247 1248 bsd_args.s = args->s; 1249 bsd_args.how = args->how; 1250 return (shutdown(td, &bsd_args)); 1251} 1252 1253struct linux_setsockopt_args { 1254 int s; 1255 int level; 1256 int optname; 1257 l_uintptr_t optval; 1258 int optlen; 1259}; 1260 1261static int 1262linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1263{ 1264 struct setsockopt_args /* { 1265 int s; 1266 int level; 1267 int name; 1268 caddr_t val; 1269 int valsize; 1270 } */ bsd_args; 1271 int error, name; 1272 1273 bsd_args.s = args->s; 1274 bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1275 switch (bsd_args.level) { 1276 case SOL_SOCKET: 1277 name = linux_to_bsd_so_sockopt(args->optname); 1278 break; 1279 case IPPROTO_IP: 1280 name = linux_to_bsd_ip_sockopt(args->optname); 1281 break; 1282 case IPPROTO_TCP: 1283 /* Linux TCP option values match BSD's */ 1284 name = args->optname; 1285 break; 1286 default: 1287 name = -1; 1288 break; 1289 } 1290 if (name == -1) 1291 return (ENOPROTOOPT); 1292 1293 bsd_args.name = name; 1294 bsd_args.val = PTRIN(args->optval); 1295 bsd_args.valsize = args->optlen; 1296 1297 if (name == IPV6_NEXTHOP) { 1298 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, 1299 bsd_args.valsize); 1300 error = setsockopt(td, &bsd_args); 1301 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1302 } else 1303 error = setsockopt(td, &bsd_args); 1304 1305 return (error); 1306} 1307 1308struct linux_getsockopt_args { 1309 int s; 1310 int level; 1311 int optname; 1312 l_uintptr_t optval; 1313 l_uintptr_t optlen; 1314}; 1315 1316static int 1317linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1318{ 1319 struct getsockopt_args /* { 1320 int s; 1321 int level; 1322 int name; 1323 caddr_t val; 1324 int *avalsize; 1325 } */ bsd_args; 1326 int error, name; 1327 1328 bsd_args.s = args->s; 1329 bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1330 switch (bsd_args.level) { 1331 case SOL_SOCKET: 1332 name = linux_to_bsd_so_sockopt(args->optname); 1333 break; 1334 case IPPROTO_IP: 1335 name = linux_to_bsd_ip_sockopt(args->optname); 1336 break; 1337 case IPPROTO_TCP: 1338 /* Linux TCP option values match BSD's */ 1339 name = args->optname; 1340 break; 1341 default: 1342 name = -1; 1343 break; 1344 } 1345 if (name == -1) 1346 return (EINVAL); 1347 1348 bsd_args.name = name; 1349 bsd_args.val = PTRIN(args->optval); 1350 bsd_args.avalsize = PTRIN(args->optlen); 1351 1352 if (name == IPV6_NEXTHOP) { 1353 error = getsockopt(td, &bsd_args); 1354 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1355 } else 1356 error = getsockopt(td, &bsd_args); 1357 1358 return (error); 1359} 1360 1361int 1362linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1363{ 1364 void *arg = (void *)(intptr_t)args->args; 1365 1366 switch (args->what) { 1367 case LINUX_SOCKET: 1368 return (linux_socket(td, arg)); 1369 case LINUX_BIND: 1370 return (linux_bind(td, arg)); 1371 case LINUX_CONNECT: 1372 return (linux_connect(td, arg)); 1373 case LINUX_LISTEN: 1374 return (linux_listen(td, arg)); 1375 case LINUX_ACCEPT: 1376 return (linux_accept(td, arg)); 1377 case LINUX_GETSOCKNAME: 1378 return (linux_getsockname(td, arg)); 1379 case LINUX_GETPEERNAME: 1380 return (linux_getpeername(td, arg)); 1381 case LINUX_SOCKETPAIR: 1382 return (linux_socketpair(td, arg)); 1383 case LINUX_SEND: 1384 return (linux_send(td, arg)); 1385 case LINUX_RECV: 1386 return (linux_recv(td, arg)); 1387 case LINUX_SENDTO: 1388 return (linux_sendto(td, arg)); 1389 case LINUX_RECVFROM: 1390 return (linux_recvfrom(td, arg)); 1391 case LINUX_SHUTDOWN: 1392 return (linux_shutdown(td, arg)); 1393 case LINUX_SETSOCKOPT: 1394 return (linux_setsockopt(td, arg)); 1395 case LINUX_GETSOCKOPT: 1396 return (linux_getsockopt(td, arg)); 1397 case LINUX_SENDMSG: 1398 return (linux_sendmsg(td, arg)); 1399 case LINUX_RECVMSG: 1400 return (linux_recvmsg(td, arg)); 1401 } 1402 1403 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1404 return (ENOSYS); 1405} 1406