1995-06-25 17:32:43 +00:00
|
|
|
/*-
|
2012-01-15 13:23:18 +00:00
|
|
|
* Copyright (c) 1995 Søren Schmidt
|
1995-06-25 17:32:43 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
2003-03-03 09:17:12 +00:00
|
|
|
* notice, this list of conditions and the following disclaimer
|
1995-06-25 17:32:43 +00:00
|
|
|
* in this position and unchanged.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
2002-06-02 20:05:59 +00:00
|
|
|
* derived from this software without specific prior written permission
|
1995-06-25 17:32:43 +00:00
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2003-06-10 21:29:12 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1995-11-22 07:43:53 +00:00
|
|
|
/* XXX we use functions that might not exist. */
|
2006-03-19 11:10:33 +00:00
|
|
|
#include "opt_compat.h"
|
2003-02-03 17:43:20 +00:00
|
|
|
#include "opt_inet6.h"
|
1997-12-16 17:40:42 +00:00
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <sys/param.h>
|
1997-12-14 03:17:54 +00:00
|
|
|
#include <sys/proc.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <sys/systm.h>
|
1995-11-22 07:43:53 +00:00
|
|
|
#include <sys/sysproto.h>
|
2014-03-16 10:55:57 +00:00
|
|
|
#include <sys/capsicum.h>
|
1998-02-07 02:13:27 +00:00
|
|
|
#include <sys/fcntl.h>
|
2001-03-01 21:44:40 +00:00
|
|
|
#include <sys/file.h>
|
2003-04-29 13:36:06 +00:00
|
|
|
#include <sys/limits.h>
|
2005-07-09 12:26:22 +00:00
|
|
|
#include <sys/lock.h>
|
2003-02-03 17:43:20 +00:00
|
|
|
#include <sys/malloc.h>
|
2005-07-09 12:26:22 +00:00
|
|
|
#include <sys/mutex.h>
|
2003-11-09 17:04:04 +00:00
|
|
|
#include <sys/mbuf.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <sys/socket.h>
|
2001-03-01 21:44:40 +00:00
|
|
|
#include <sys/socketvar.h>
|
2003-02-03 17:43:20 +00:00
|
|
|
#include <sys/syscallsubr.h>
|
1998-03-28 10:33:27 +00:00
|
|
|
#include <sys/uio.h>
|
2003-02-03 17:43:20 +00:00
|
|
|
#include <sys/syslog.h>
|
2007-02-01 13:36:19 +00:00
|
|
|
#include <sys/un.h>
|
1995-11-22 07:43:53 +00:00
|
|
|
|
2008-12-02 21:37:28 +00:00
|
|
|
#include <net/if.h>
|
2013-10-26 18:18:50 +00:00
|
|
|
#include <net/vnet.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
#include <netinet/in.h>
|
1997-12-14 03:17:54 +00:00
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
2013-01-23 21:44:48 +00:00
|
|
|
#include <netinet/tcp.h>
|
2003-02-03 17:43:20 +00:00
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet/ip6.h>
|
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#endif
|
1995-06-25 17:32:43 +00:00
|
|
|
|
2005-01-14 04:44:56 +00:00
|
|
|
#ifdef COMPAT_LINUX32
|
2004-08-16 07:28:16 +00:00
|
|
|
#include <machine/../linux32/linux.h>
|
|
|
|
#include <machine/../linux32/linux32_proto.h>
|
2005-01-14 04:44:56 +00:00
|
|
|
#else
|
|
|
|
#include <machine/../linux/linux.h>
|
|
|
|
#include <machine/../linux/linux_proto.h>
|
2004-08-16 07:28:16 +00:00
|
|
|
#endif
|
2015-05-24 16:31:44 +00:00
|
|
|
#include <compat/linux/linux_file.h>
|
2000-12-19 00:24:25 +00:00
|
|
|
#include <compat/linux/linux_socket.h>
|
2015-05-24 18:04:04 +00:00
|
|
|
#include <compat/linux/linux_timer.h>
|
2000-08-22 01:51:54 +00:00
|
|
|
#include <compat/linux/linux_util.h>
|
1995-06-25 17:32:43 +00:00
|
|
|
|
2003-02-03 17:43:20 +00:00
|
|
|
static int linux_to_bsd_domain(int);
|
2015-05-24 18:04:04 +00:00
|
|
|
static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
|
|
|
|
l_uint);
|
|
|
|
static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
|
|
|
|
l_uint, struct msghdr *);
|
2015-05-24 18:06:12 +00:00
|
|
|
static int linux_set_socket_flags(int, int *);
|
2003-02-03 17:43:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reads a linux sockaddr and does any necessary translation.
|
|
|
|
* Linux sockaddrs don't have a length field, only a family.
|
|
|
|
* Copy the osockaddr structure pointed to by osa to kernel, adjust
|
|
|
|
* family and convert to sockaddr.
|
2001-10-26 23:10:08 +00:00
|
|
|
*/
|
|
|
|
static int
|
2011-10-06 21:40:08 +00:00
|
|
|
linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
|
2001-10-26 23:10:08 +00:00
|
|
|
{
|
2003-02-03 17:43:20 +00:00
|
|
|
struct sockaddr *sa;
|
|
|
|
struct osockaddr *kosa;
|
|
|
|
#ifdef INET6
|
|
|
|
struct sockaddr_in6 *sin6;
|
2011-10-06 21:17:46 +00:00
|
|
|
int oldv6size;
|
2003-02-03 17:43:20 +00:00
|
|
|
#endif
|
2011-10-06 21:09:28 +00:00
|
|
|
char *name;
|
2011-10-06 21:40:08 +00:00
|
|
|
int bdom, error, hdrlen, namelen;
|
2003-02-03 17:43:20 +00:00
|
|
|
|
2011-10-06 21:40:08 +00:00
|
|
|
if (salen < 2 || salen > UCHAR_MAX || !osa)
|
2003-02-03 17:43:20 +00:00
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
oldv6size = 0;
|
|
|
|
/*
|
|
|
|
* Check for old (pre-RFC2553) sockaddr_in6. We may accept it
|
|
|
|
* if it's a v4-mapped address, so reserve the proper space
|
|
|
|
* for it.
|
|
|
|
*/
|
2011-10-06 21:40:08 +00:00
|
|
|
if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
|
|
|
|
salen += sizeof(uint32_t);
|
2003-02-03 17:43:20 +00:00
|
|
|
oldv6size = 1;
|
|
|
|
}
|
|
|
|
#endif
|
2001-10-26 23:10:08 +00:00
|
|
|
|
2011-10-06 21:40:08 +00:00
|
|
|
kosa = malloc(salen, M_SONAME, M_WAITOK);
|
2001-10-26 23:10:08 +00:00
|
|
|
|
2011-10-06 21:40:08 +00:00
|
|
|
if ((error = copyin(osa, kosa, salen)))
|
2003-02-03 17:43:20 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
bdom = linux_to_bsd_domain(kosa->sa_family);
|
|
|
|
if (bdom == -1) {
|
2010-02-09 22:30:51 +00:00
|
|
|
error = EAFNOSUPPORT;
|
2003-02-03 17:43:20 +00:00
|
|
|
goto out;
|
2001-10-26 23:10:08 +00:00
|
|
|
}
|
2003-02-03 17:43:20 +00:00
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
|
|
|
|
* which lacks the scope id compared with RFC2553 one. If we detect
|
|
|
|
* the situation, reject the address and write a message to system log.
|
|
|
|
*
|
|
|
|
* Still accept addresses for which the scope id is not used.
|
|
|
|
*/
|
2011-10-06 20:48:23 +00:00
|
|
|
if (oldv6size) {
|
|
|
|
if (bdom == AF_INET6) {
|
|
|
|
sin6 = (struct sockaddr_in6 *)kosa;
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
|
|
|
|
(!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
|
|
|
|
!IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
|
|
|
|
!IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
|
|
|
|
!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
|
|
|
|
!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
|
|
|
|
sin6->sin6_scope_id = 0;
|
|
|
|
} else {
|
|
|
|
log(LOG_DEBUG,
|
|
|
|
"obsolete pre-RFC2553 sockaddr_in6 rejected\n");
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else
|
2011-10-06 21:40:08 +00:00
|
|
|
salen -= sizeof(uint32_t);
|
2011-10-06 20:48:23 +00:00
|
|
|
}
|
2003-02-03 17:43:20 +00:00
|
|
|
#endif
|
2010-02-09 22:30:51 +00:00
|
|
|
if (bdom == AF_INET) {
|
2011-10-06 21:40:08 +00:00
|
|
|
if (salen < sizeof(struct sockaddr_in)) {
|
2010-02-09 22:30:51 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-10-06 21:40:08 +00:00
|
|
|
salen = sizeof(struct sockaddr_in);
|
2010-02-09 22:30:51 +00:00
|
|
|
}
|
2003-02-03 17:43:20 +00:00
|
|
|
|
2011-10-06 21:40:08 +00:00
|
|
|
if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
|
2011-10-06 19:59:14 +00:00
|
|
|
hdrlen = offsetof(struct sockaddr_un, sun_path);
|
2011-10-06 21:09:28 +00:00
|
|
|
name = ((struct sockaddr_un *)kosa)->sun_path;
|
|
|
|
if (*name == '\0') {
|
|
|
|
/*
|
|
|
|
* Linux abstract namespace starts with a NULL byte.
|
|
|
|
* XXX We do not support abstract namespace yet.
|
|
|
|
*/
|
2011-10-06 21:40:08 +00:00
|
|
|
namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
|
2011-10-06 21:09:28 +00:00
|
|
|
} else
|
2011-10-06 21:40:08 +00:00
|
|
|
namelen = strnlen(name, salen - hdrlen);
|
2011-10-06 21:55:05 +00:00
|
|
|
salen = hdrlen + namelen;
|
|
|
|
if (salen > sizeof(struct sockaddr_un)) {
|
2011-10-06 20:28:08 +00:00
|
|
|
error = ENAMETOOLONG;
|
2011-10-04 19:07:38 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-06 21:17:46 +00:00
|
|
|
sa = (struct sockaddr *)kosa;
|
2003-02-03 17:43:20 +00:00
|
|
|
sa->sa_family = bdom;
|
2011-10-06 21:40:08 +00:00
|
|
|
sa->sa_len = salen;
|
2003-02-03 17:43:20 +00:00
|
|
|
|
|
|
|
*sap = sa;
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
out:
|
2011-10-06 20:20:30 +00:00
|
|
|
free(kosa, M_SONAME);
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
2001-10-26 23:10:08 +00:00
|
|
|
}
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_domain(int domain)
|
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
switch (domain) {
|
|
|
|
case LINUX_AF_UNSPEC:
|
|
|
|
return (AF_UNSPEC);
|
|
|
|
case LINUX_AF_UNIX:
|
|
|
|
return (AF_LOCAL);
|
|
|
|
case LINUX_AF_INET:
|
|
|
|
return (AF_INET);
|
2003-02-03 17:43:20 +00:00
|
|
|
case LINUX_AF_INET6:
|
|
|
|
return (AF_INET6);
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_AF_AX25:
|
|
|
|
return (AF_CCITT);
|
|
|
|
case LINUX_AF_IPX:
|
|
|
|
return (AF_IPX);
|
|
|
|
case LINUX_AF_APPLETALK:
|
|
|
|
return (AF_APPLETALK);
|
|
|
|
}
|
|
|
|
return (-1);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2003-02-03 17:43:20 +00:00
|
|
|
static int
|
|
|
|
bsd_to_linux_domain(int domain)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (domain) {
|
|
|
|
case AF_UNSPEC:
|
|
|
|
return (LINUX_AF_UNSPEC);
|
|
|
|
case AF_LOCAL:
|
|
|
|
return (LINUX_AF_UNIX);
|
|
|
|
case AF_INET:
|
|
|
|
return (LINUX_AF_INET);
|
|
|
|
case AF_INET6:
|
|
|
|
return (LINUX_AF_INET6);
|
|
|
|
case AF_CCITT:
|
|
|
|
return (LINUX_AF_AX25);
|
|
|
|
case AF_IPX:
|
|
|
|
return (LINUX_AF_IPX);
|
|
|
|
case AF_APPLETALK:
|
|
|
|
return (LINUX_AF_APPLETALK);
|
|
|
|
}
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_sockopt_level(int level)
|
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
switch (level) {
|
|
|
|
case LINUX_SOL_SOCKET:
|
|
|
|
return (SOL_SOCKET);
|
|
|
|
}
|
|
|
|
return (level);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2003-10-11 15:08:32 +00:00
|
|
|
static int
|
|
|
|
bsd_to_linux_sockopt_level(int level)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (level) {
|
|
|
|
case SOL_SOCKET:
|
|
|
|
return (LINUX_SOL_SOCKET);
|
|
|
|
}
|
|
|
|
return (level);
|
|
|
|
}
|
|
|
|
|
2000-08-26 05:12:16 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_ip_sockopt(int opt)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
switch (opt) {
|
|
|
|
case LINUX_IP_TOS:
|
|
|
|
return (IP_TOS);
|
|
|
|
case LINUX_IP_TTL:
|
|
|
|
return (IP_TTL);
|
|
|
|
case LINUX_IP_OPTIONS:
|
|
|
|
return (IP_OPTIONS);
|
|
|
|
case LINUX_IP_MULTICAST_IF:
|
|
|
|
return (IP_MULTICAST_IF);
|
|
|
|
case LINUX_IP_MULTICAST_TTL:
|
|
|
|
return (IP_MULTICAST_TTL);
|
|
|
|
case LINUX_IP_MULTICAST_LOOP:
|
|
|
|
return (IP_MULTICAST_LOOP);
|
|
|
|
case LINUX_IP_ADD_MEMBERSHIP:
|
|
|
|
return (IP_ADD_MEMBERSHIP);
|
|
|
|
case LINUX_IP_DROP_MEMBERSHIP:
|
|
|
|
return (IP_DROP_MEMBERSHIP);
|
|
|
|
case LINUX_IP_HDRINCL:
|
|
|
|
return (IP_HDRINCL);
|
|
|
|
}
|
|
|
|
return (-1);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_so_sockopt(int opt)
|
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
switch (opt) {
|
|
|
|
case LINUX_SO_DEBUG:
|
|
|
|
return (SO_DEBUG);
|
|
|
|
case LINUX_SO_REUSEADDR:
|
|
|
|
return (SO_REUSEADDR);
|
|
|
|
case LINUX_SO_TYPE:
|
|
|
|
return (SO_TYPE);
|
|
|
|
case LINUX_SO_ERROR:
|
|
|
|
return (SO_ERROR);
|
|
|
|
case LINUX_SO_DONTROUTE:
|
|
|
|
return (SO_DONTROUTE);
|
|
|
|
case LINUX_SO_BROADCAST:
|
|
|
|
return (SO_BROADCAST);
|
|
|
|
case LINUX_SO_SNDBUF:
|
|
|
|
return (SO_SNDBUF);
|
|
|
|
case LINUX_SO_RCVBUF:
|
|
|
|
return (SO_RCVBUF);
|
|
|
|
case LINUX_SO_KEEPALIVE:
|
|
|
|
return (SO_KEEPALIVE);
|
|
|
|
case LINUX_SO_OOBINLINE:
|
|
|
|
return (SO_OOBINLINE);
|
|
|
|
case LINUX_SO_LINGER:
|
|
|
|
return (SO_LINGER);
|
2007-02-01 13:36:19 +00:00
|
|
|
case LINUX_SO_PEERCRED:
|
|
|
|
return (LOCAL_PEERCRED);
|
|
|
|
case LINUX_SO_RCVLOWAT:
|
|
|
|
return (SO_RCVLOWAT);
|
|
|
|
case LINUX_SO_SNDLOWAT:
|
|
|
|
return (SO_SNDLOWAT);
|
|
|
|
case LINUX_SO_RCVTIMEO:
|
|
|
|
return (SO_RCVTIMEO);
|
|
|
|
case LINUX_SO_SNDTIMEO:
|
|
|
|
return (SO_SNDTIMEO);
|
|
|
|
case LINUX_SO_TIMESTAMP:
|
|
|
|
return (SO_TIMESTAMP);
|
|
|
|
case LINUX_SO_ACCEPTCONN:
|
|
|
|
return (SO_ACCEPTCONN);
|
2000-08-26 05:12:16 +00:00
|
|
|
}
|
|
|
|
return (-1);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2013-01-23 21:44:48 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_tcp_sockopt(int opt)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (opt) {
|
|
|
|
case LINUX_TCP_NODELAY:
|
|
|
|
return (TCP_NODELAY);
|
|
|
|
case LINUX_TCP_MAXSEG:
|
|
|
|
return (TCP_MAXSEG);
|
|
|
|
case LINUX_TCP_KEEPIDLE:
|
|
|
|
return (TCP_KEEPIDLE);
|
|
|
|
case LINUX_TCP_KEEPINTVL:
|
|
|
|
return (TCP_KEEPINTVL);
|
|
|
|
case LINUX_TCP_KEEPCNT:
|
|
|
|
return (TCP_KEEPCNT);
|
|
|
|
case LINUX_TCP_MD5SIG:
|
|
|
|
return (TCP_MD5SIG);
|
|
|
|
}
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
2000-12-19 00:24:25 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_msg_flags(int flags)
|
|
|
|
{
|
|
|
|
int ret_flags = 0;
|
|
|
|
|
|
|
|
if (flags & LINUX_MSG_OOB)
|
|
|
|
ret_flags |= MSG_OOB;
|
|
|
|
if (flags & LINUX_MSG_PEEK)
|
|
|
|
ret_flags |= MSG_PEEK;
|
|
|
|
if (flags & LINUX_MSG_DONTROUTE)
|
|
|
|
ret_flags |= MSG_DONTROUTE;
|
|
|
|
if (flags & LINUX_MSG_CTRUNC)
|
|
|
|
ret_flags |= MSG_CTRUNC;
|
|
|
|
if (flags & LINUX_MSG_TRUNC)
|
|
|
|
ret_flags |= MSG_TRUNC;
|
|
|
|
if (flags & LINUX_MSG_DONTWAIT)
|
|
|
|
ret_flags |= MSG_DONTWAIT;
|
|
|
|
if (flags & LINUX_MSG_EOR)
|
|
|
|
ret_flags |= MSG_EOR;
|
|
|
|
if (flags & LINUX_MSG_WAITALL)
|
|
|
|
ret_flags |= MSG_WAITALL;
|
2005-03-08 16:11:41 +00:00
|
|
|
if (flags & LINUX_MSG_NOSIGNAL)
|
|
|
|
ret_flags |= MSG_NOSIGNAL;
|
2000-12-19 00:24:25 +00:00
|
|
|
#if 0 /* not handled */
|
|
|
|
if (flags & LINUX_MSG_PROXY)
|
|
|
|
;
|
|
|
|
if (flags & LINUX_MSG_FIN)
|
|
|
|
;
|
|
|
|
if (flags & LINUX_MSG_SYN)
|
|
|
|
;
|
|
|
|
if (flags & LINUX_MSG_CONFIRM)
|
|
|
|
;
|
|
|
|
if (flags & LINUX_MSG_RST)
|
|
|
|
;
|
|
|
|
if (flags & LINUX_MSG_ERRQUEUE)
|
|
|
|
;
|
|
|
|
#endif
|
|
|
|
return ret_flags;
|
|
|
|
}
|
|
|
|
|
2006-03-18 18:20:17 +00:00
|
|
|
/*
|
|
|
|
* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
|
|
|
|
* native syscall will fault. Thus, we don't really need to check the
|
|
|
|
* return values for these functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_sockaddr(struct sockaddr *arg)
|
|
|
|
{
|
|
|
|
struct sockaddr sa;
|
|
|
|
size_t sa_len = sizeof(struct sockaddr);
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((error = copyin(arg, &sa, sa_len)))
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
*(u_short *)&sa = sa.sa_family;
|
|
|
|
|
|
|
|
error = copyout(&sa, arg, sa_len);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
|
|
|
|
{
|
|
|
|
struct sockaddr sa;
|
|
|
|
size_t sa_len = sizeof(struct sockaddr);
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((error = copyin(arg, &sa, sa_len)))
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
sa.sa_family = *(sa_family_t *)&sa;
|
|
|
|
sa.sa_len = len;
|
|
|
|
|
|
|
|
error = copyout(&sa, arg, sa_len);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2003-02-03 17:43:20 +00:00
|
|
|
static int
|
|
|
|
linux_sa_put(struct osockaddr *osa)
|
|
|
|
{
|
|
|
|
struct osockaddr sa;
|
|
|
|
int error, bdom;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only read/write the osockaddr family part, the rest is
|
|
|
|
* not changed.
|
|
|
|
*/
|
2003-03-03 09:14:26 +00:00
|
|
|
error = copyin(osa, &sa, sizeof(sa.sa_family));
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
bdom = bsd_to_linux_domain(sa.sa_family);
|
|
|
|
if (bdom == -1)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
sa.sa_family = bdom;
|
|
|
|
error = copyout(&sa, osa, sizeof(sa.sa_family));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
static int
|
|
|
|
linux_to_bsd_cmsg_type(int cmsg_type)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (cmsg_type) {
|
|
|
|
case LINUX_SCM_RIGHTS:
|
|
|
|
return (SCM_RIGHTS);
|
2011-03-26 11:05:53 +00:00
|
|
|
case LINUX_SCM_CREDENTIALS:
|
|
|
|
return (SCM_CREDS);
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_cmsg_type(int cmsg_type)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (cmsg_type) {
|
|
|
|
case SCM_RIGHTS:
|
|
|
|
return (LINUX_SCM_RIGHTS);
|
2011-03-26 11:05:53 +00:00
|
|
|
case SCM_CREDS:
|
|
|
|
return (LINUX_SCM_CREDENTIALS);
|
2015-05-24 18:13:21 +00:00
|
|
|
case SCM_TIMESTAMP:
|
|
|
|
return (LINUX_SCM_TIMESTAMP);
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
|
|
|
|
{
|
|
|
|
if (lhdr->msg_controllen > INT_MAX)
|
|
|
|
return (ENOBUFS);
|
|
|
|
|
|
|
|
bhdr->msg_name = PTRIN(lhdr->msg_name);
|
|
|
|
bhdr->msg_namelen = lhdr->msg_namelen;
|
|
|
|
bhdr->msg_iov = PTRIN(lhdr->msg_iov);
|
|
|
|
bhdr->msg_iovlen = lhdr->msg_iovlen;
|
|
|
|
bhdr->msg_control = PTRIN(lhdr->msg_control);
|
2011-03-26 11:05:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* msg_controllen is skipped since BSD and LINUX control messages
|
|
|
|
* are potentially different sizes (e.g. the cred structure used
|
|
|
|
* by SCM_CREDS is different between the two operating system).
|
|
|
|
*
|
|
|
|
* The caller can set it (if necessary) after converting all the
|
|
|
|
* control messages.
|
|
|
|
*/
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
|
|
|
|
{
|
|
|
|
lhdr->msg_name = PTROUT(bhdr->msg_name);
|
|
|
|
lhdr->msg_namelen = bhdr->msg_namelen;
|
|
|
|
lhdr->msg_iov = PTROUT(bhdr->msg_iov);
|
|
|
|
lhdr->msg_iovlen = bhdr->msg_iovlen;
|
|
|
|
lhdr->msg_control = PTROUT(bhdr->msg_control);
|
2011-03-26 11:05:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* msg_controllen is skipped since BSD and LINUX control messages
|
|
|
|
* are potentially different sizes (e.g. the cred structure used
|
|
|
|
* by SCM_CREDS is different between the two operating system).
|
|
|
|
*
|
|
|
|
* The caller can set it (if necessary) after converting all the
|
|
|
|
* control messages.
|
|
|
|
*/
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
/* msg_flags skipped */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2009-05-31 12:04:01 +00:00
|
|
|
static int
|
2015-05-24 18:06:12 +00:00
|
|
|
linux_set_socket_flags(int lflags, int *flags)
|
2009-05-31 12:04:01 +00:00
|
|
|
{
|
|
|
|
|
2015-05-24 18:06:12 +00:00
|
|
|
if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
|
|
|
|
return (EINVAL);
|
|
|
|
if (lflags & LINUX_SOCK_NONBLOCK)
|
|
|
|
*flags |= SOCK_NONBLOCK;
|
|
|
|
if (lflags & LINUX_SOCK_CLOEXEC)
|
|
|
|
*flags |= SOCK_CLOEXEC;
|
2009-05-31 12:04:01 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-11-09 17:04:04 +00:00
|
|
|
static int
|
2005-01-30 07:20:36 +00:00
|
|
|
linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
|
2008-11-29 17:14:06 +00:00
|
|
|
struct mbuf *control, enum uio_seg segflg)
|
2003-11-09 17:04:04 +00:00
|
|
|
{
|
|
|
|
struct sockaddr *to;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (mp->msg_name != NULL) {
|
|
|
|
error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
mp->msg_name = to;
|
|
|
|
} else
|
|
|
|
to = NULL;
|
|
|
|
|
2005-01-30 07:20:36 +00:00
|
|
|
error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
|
|
|
|
segflg);
|
2003-11-09 17:04:04 +00:00
|
|
|
|
|
|
|
if (to)
|
2008-10-23 15:53:51 +00:00
|
|
|
free(to, M_SONAME);
|
2003-11-09 17:04:04 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2000-08-26 05:12:16 +00:00
|
|
|
/* Return 0 if IP_HDRINCL is set for the given socket. */
|
1997-12-14 03:17:54 +00:00
|
|
|
static int
|
2004-07-17 21:06:36 +00:00
|
|
|
linux_check_hdrincl(struct thread *td, int s)
|
1997-12-14 03:17:54 +00:00
|
|
|
{
|
2015-01-01 20:53:38 +00:00
|
|
|
int error, optval;
|
|
|
|
socklen_t size_val;
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2004-07-17 21:06:36 +00:00
|
|
|
size_val = sizeof(optval);
|
|
|
|
error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
|
|
|
|
&optval, UIO_SYSSPACE, &size_val);
|
|
|
|
if (error)
|
2000-08-26 05:12:16 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
return (optval == 0);
|
1997-12-14 03:17:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Updated sendto() when IP_HDRINCL is set:
|
|
|
|
* tweak endian-dependent fields in the IP packet.
|
|
|
|
*/
|
|
|
|
static int
|
2004-07-18 04:09:40 +00:00
|
|
|
linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
|
1997-12-14 03:17:54 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* linux_ip_copysize defines how many bytes we should copy
|
|
|
|
* from the beginning of the IP packet before we customize it for BSD.
|
2005-01-30 07:20:36 +00:00
|
|
|
* It should include all the fields we modify (ip_len and ip_off).
|
1997-12-14 03:17:54 +00:00
|
|
|
*/
|
|
|
|
#define linux_ip_copysize 8
|
|
|
|
|
2000-08-26 05:12:16 +00:00
|
|
|
struct ip *packet;
|
2003-11-09 17:04:04 +00:00
|
|
|
struct msghdr msg;
|
2005-01-30 07:20:36 +00:00
|
|
|
struct iovec aiov[1];
|
2000-08-26 05:12:16 +00:00
|
|
|
int error;
|
|
|
|
|
2005-03-23 08:28:00 +00:00
|
|
|
/* Check that the packet isn't too big or too small. */
|
|
|
|
if (linux_args->len < linux_ip_copysize ||
|
|
|
|
linux_args->len > IP_MAXPACKET)
|
2000-08-26 05:12:16 +00:00
|
|
|
return (EINVAL);
|
|
|
|
|
2015-05-24 16:14:41 +00:00
|
|
|
packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2005-01-30 07:20:36 +00:00
|
|
|
/* Make kernel copy of the packet to be sent */
|
2004-08-16 07:28:16 +00:00
|
|
|
if ((error = copyin(PTRIN(linux_args->msg), packet,
|
2005-01-30 07:20:36 +00:00
|
|
|
linux_args->len)))
|
|
|
|
goto goout;
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
/* Convert fields from Linux to BSD raw IP socket format */
|
2003-11-09 17:04:04 +00:00
|
|
|
packet->ip_len = linux_args->len;
|
2000-08-26 05:12:16 +00:00
|
|
|
packet->ip_off = ntohs(packet->ip_off);
|
|
|
|
|
|
|
|
/* Prepare the msghdr and iovec structures describing the new packet */
|
2004-08-16 07:28:16 +00:00
|
|
|
msg.msg_name = PTRIN(linux_args->to);
|
2003-11-09 17:04:04 +00:00
|
|
|
msg.msg_namelen = linux_args->tolen;
|
|
|
|
msg.msg_iov = aiov;
|
2005-01-30 07:20:36 +00:00
|
|
|
msg.msg_iovlen = 1;
|
2003-11-09 17:04:04 +00:00
|
|
|
msg.msg_control = NULL;
|
|
|
|
msg.msg_flags = 0;
|
|
|
|
aiov[0].iov_base = (char *)packet;
|
2005-01-30 07:20:36 +00:00
|
|
|
aiov[0].iov_len = linux_args->len;
|
|
|
|
error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
|
2008-11-29 17:14:06 +00:00
|
|
|
NULL, UIO_SYSSPACE);
|
2005-01-30 07:20:36 +00:00
|
|
|
goout:
|
2015-05-24 16:14:41 +00:00
|
|
|
free(packet, M_LINUX);
|
2003-11-09 17:04:04 +00:00
|
|
|
return (error);
|
1997-12-14 03:17:54 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_socket(struct thread *td, struct linux_socket_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct socket_args /* {
|
|
|
|
int domain;
|
|
|
|
int type;
|
|
|
|
int protocol;
|
|
|
|
} */ bsd_args;
|
2015-05-24 18:06:12 +00:00
|
|
|
int retval_socket;
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.protocol = args->protocol;
|
2009-05-16 18:48:41 +00:00
|
|
|
bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
|
2009-05-16 18:46:51 +00:00
|
|
|
if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
|
|
|
|
return (EINVAL);
|
2015-05-24 18:06:12 +00:00
|
|
|
retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
|
|
|
|
&bsd_args.type);
|
|
|
|
if (retval_socket != 0)
|
|
|
|
return (retval_socket);
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.domain = linux_to_bsd_domain(args->domain);
|
2000-08-26 05:12:16 +00:00
|
|
|
if (bsd_args.domain == -1)
|
2009-05-07 09:34:02 +00:00
|
|
|
return (EAFNOSUPPORT);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2011-09-16 13:58:51 +00:00
|
|
|
retval_socket = sys_socket(td, &bsd_args);
|
2009-05-16 18:44:56 +00:00
|
|
|
if (retval_socket)
|
|
|
|
return (retval_socket);
|
|
|
|
|
2000-08-26 05:12:16 +00:00
|
|
|
if (bsd_args.type == SOCK_RAW
|
|
|
|
&& (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
|
2009-05-16 18:44:56 +00:00
|
|
|
&& bsd_args.domain == PF_INET) {
|
2000-08-26 05:12:16 +00:00
|
|
|
/* It's a raw IP socket: set the IP_HDRINCL option. */
|
2004-07-17 21:06:36 +00:00
|
|
|
int hdrincl;
|
|
|
|
|
|
|
|
hdrincl = 1;
|
|
|
|
/* We ignore any error returned by kern_setsockopt() */
|
|
|
|
kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
|
|
|
|
&hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
|
2000-08-26 05:12:16 +00:00
|
|
|
}
|
2003-02-03 17:43:20 +00:00
|
|
|
#ifdef INET6
|
|
|
|
/*
|
2009-10-25 09:58:56 +00:00
|
|
|
* Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
|
|
|
|
* and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
|
|
|
|
* For simplicity we do this unconditionally of the net.inet6.ip6.v6only
|
|
|
|
* sysctl value.
|
2003-02-03 17:43:20 +00:00
|
|
|
*/
|
2009-10-25 09:58:56 +00:00
|
|
|
if (bsd_args.domain == PF_INET6) {
|
2004-07-17 21:06:36 +00:00
|
|
|
int v6only;
|
|
|
|
|
|
|
|
v6only = 0;
|
2003-02-03 17:43:20 +00:00
|
|
|
/* We ignore any error returned by setsockopt() */
|
2004-07-17 21:06:36 +00:00
|
|
|
kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
|
|
|
|
&v6only, UIO_SYSSPACE, sizeof(v6only));
|
2003-02-03 17:43:20 +00:00
|
|
|
}
|
|
|
|
#endif
|
1997-12-14 03:17:54 +00:00
|
|
|
|
2000-08-26 05:12:16 +00:00
|
|
|
return (retval_socket);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_bind(struct thread *td, struct linux_bind_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2003-02-03 17:43:20 +00:00
|
|
|
struct sockaddr *sa;
|
2000-08-26 05:12:16 +00:00
|
|
|
int error;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
error = linux_getsockaddr(&sa, PTRIN(args->name),
|
|
|
|
args->namelen);
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
2014-11-13 18:01:51 +00:00
|
|
|
error = kern_bindat(td, AT_FDCWD, args->s, sa);
|
2006-07-19 18:28:52 +00:00
|
|
|
free(sa, M_SONAME);
|
2008-09-09 13:01:14 +00:00
|
|
|
if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
|
2006-09-23 19:06:54 +00:00
|
|
|
return (EINVAL);
|
2006-07-19 18:28:52 +00:00
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2000-11-16 01:05:53 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_connect(struct thread *td, struct linux_connect_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
cap_rights_t rights;
|
2001-03-01 21:44:40 +00:00
|
|
|
struct socket *so;
|
2003-02-03 17:43:20 +00:00
|
|
|
struct sockaddr *sa;
|
2001-11-17 18:43:13 +00:00
|
|
|
u_int fflag;
|
2000-08-26 05:12:16 +00:00
|
|
|
int error;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
|
|
|
|
args->namelen);
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
2014-11-13 18:01:51 +00:00
|
|
|
error = kern_connectat(td, AT_FDCWD, args->s, sa);
|
2006-07-19 18:28:52 +00:00
|
|
|
free(sa, M_SONAME);
|
2001-03-01 21:44:40 +00:00
|
|
|
if (error != EISCONN)
|
|
|
|
return (error);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2001-03-01 21:44:40 +00:00
|
|
|
/*
|
|
|
|
* Linux doesn't return EISCONN the first time it occurs,
|
|
|
|
* when on a non-blocking socket. Instead it returns the
|
|
|
|
* error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
|
2006-04-01 15:25:01 +00:00
|
|
|
*
|
|
|
|
* XXXRW: Instead of using fgetsock(), check that it is a
|
|
|
|
* socket and use the file descriptor reference instead of
|
|
|
|
* creating a new one.
|
2001-03-01 21:44:40 +00:00
|
|
|
*/
|
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way.
The cap_rights_t represents capability rights. We used to use one bit to
represent one right, but we are running out of spare bits. Currently the new
structure provides place for 114 rights (so 50 more than the previous
cap_rights_t), but it is possible to grow the structure to hold at least 285
rights, although we can make it even larger if 285 rights won't be enough.
The structure definition looks like this:
struct cap_rights {
uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
};
The initial CAP_RIGHTS_VERSION is 0.
The top two bits in the first element of the cr_rights[] array contain total
number of elements in the array - 2. This means if those two bits are equal to
0, we have 2 array elements.
The top two bits in all remaining array elements should be 0.
The next five bits in all array elements contain array index. Only one bit is
used and bit position in this five-bits range defines array index. This means
there can be at most five array elements in the future.
To define new right the CAPRIGHT() macro must be used. The macro takes two
arguments - an array index and a bit to set, eg.
#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
We still support aliases that combine few rights, but the rights have to belong
to the same array element, eg:
#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
There is new API to manage the new cap_rights_t structure:
cap_rights_t *cap_rights_init(cap_rights_t *rights, ...);
void cap_rights_set(cap_rights_t *rights, ...);
void cap_rights_clear(cap_rights_t *rights, ...);
bool cap_rights_is_set(const cap_rights_t *rights, ...);
bool cap_rights_is_valid(const cap_rights_t *rights);
void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
Capability rights to the cap_rights_init(), cap_rights_set(),
cap_rights_clear() and cap_rights_is_set() functions are provided by
separating them with commas, eg:
cap_rights_t rights;
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT);
There is no need to terminate the list of rights, as those functions are
actually macros that take care of the termination, eg:
#define cap_rights_set(rights, ...) \
__cap_rights_set((rights), __VA_ARGS__, 0ULL)
void __cap_rights_set(cap_rights_t *rights, ...);
Thanks to using one bit as an array index we can assert in those functions that
there are no two rights belonging to different array elements provided
together. For example this is illegal and will be detected, because CAP_LOOKUP
belongs to element 0 and CAP_PDKILL to element 1:
cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL);
Providing several rights that belongs to the same array's element this way is
correct, but is not advised. It should only be used for aliases definition.
This commit also breaks compatibility with some existing Capsicum system calls,
but I see no other way to do that. This should be fine as Capsicum is still
experimental and this change is not going to 9.x.
Sponsored by: The FreeBSD Foundation
2013-09-05 00:09:56 +00:00
|
|
|
error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
|
|
|
|
&so, &fflag);
|
2005-07-09 12:26:22 +00:00
|
|
|
if (error == 0) {
|
|
|
|
error = EISCONN;
|
|
|
|
if (fflag & FNONBLOCK) {
|
|
|
|
SOCK_LOCK(so);
|
|
|
|
if (so->so_emuldata == 0)
|
|
|
|
error = so->so_error;
|
|
|
|
so->so_emuldata = (void *)1;
|
|
|
|
SOCK_UNLOCK(so);
|
|
|
|
}
|
|
|
|
fputsock(so);
|
1998-02-07 02:13:27 +00:00
|
|
|
}
|
2000-08-26 05:12:16 +00:00
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_listen(struct thread *td, struct linux_listen_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct listen_args /* {
|
|
|
|
int s;
|
|
|
|
int backlog;
|
|
|
|
} */ bsd_args;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.backlog = args->backlog;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_listen(td, &bsd_args));
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 20:38:16 +00:00
|
|
|
static int
|
2009-06-01 20:42:27 +00:00
|
|
|
linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
|
2009-06-01 20:54:41 +00:00
|
|
|
l_uintptr_t namelen, int flags)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2015-05-24 18:06:12 +00:00
|
|
|
struct accept4_args /* {
|
2003-12-25 09:59:02 +00:00
|
|
|
int s;
|
|
|
|
struct sockaddr * __restrict name;
|
|
|
|
socklen_t * __restrict anamelen;
|
2015-05-24 18:06:12 +00:00
|
|
|
int flags;
|
2000-08-26 05:12:16 +00:00
|
|
|
} */ bsd_args;
|
2009-06-01 20:44:58 +00:00
|
|
|
int error;
|
|
|
|
|
2009-06-01 20:42:27 +00:00
|
|
|
bsd_args.s = s;
|
2003-12-25 09:59:02 +00:00
|
|
|
/* XXX: */
|
2009-06-01 20:42:27 +00:00
|
|
|
bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
|
|
|
|
bsd_args.anamelen = PTRIN(namelen);/* XXX */
|
2015-05-24 18:06:12 +00:00
|
|
|
error = linux_set_socket_flags(flags, &bsd_args.flags);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
error = sys_accept4(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
|
2006-09-23 19:06:54 +00:00
|
|
|
if (error) {
|
2009-06-01 20:42:27 +00:00
|
|
|
if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
|
2008-09-09 13:01:14 +00:00
|
|
|
return (EINVAL);
|
2000-08-26 05:12:16 +00:00
|
|
|
return (error);
|
2006-09-23 19:06:54 +00:00
|
|
|
}
|
2009-06-01 20:44:58 +00:00
|
|
|
if (addr)
|
|
|
|
error = linux_sa_put(PTRIN(addr));
|
|
|
|
if (error) {
|
|
|
|
(void)kern_close(td, td->td_retval[0]);
|
|
|
|
td->td_retval[0] = 0;
|
|
|
|
}
|
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2009-06-01 20:42:27 +00:00
|
|
|
linux_accept(struct thread *td, struct linux_accept_args *args)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (linux_accept_common(td, args->s, args->addr,
|
2009-06-01 20:54:41 +00:00
|
|
|
args->namelen, 0));
|
2009-06-01 20:42:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2009-06-01 20:48:39 +00:00
|
|
|
linux_accept4(struct thread *td, struct linux_accept4_args *args)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (linux_accept_common(td, args->s, args->addr,
|
|
|
|
args->namelen, args->flags));
|
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct getsockname_args /* {
|
2003-12-25 09:59:02 +00:00
|
|
|
int fdes;
|
|
|
|
struct sockaddr * __restrict asa;
|
|
|
|
socklen_t * __restrict alen;
|
2000-08-26 05:12:16 +00:00
|
|
|
} */ bsd_args;
|
|
|
|
int error;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.fdes = args->s;
|
2003-12-25 09:59:02 +00:00
|
|
|
/* XXX: */
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
|
|
|
|
bsd_args.alen = PTRIN(args->namelen); /* XXX */
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_getsockname(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
2008-09-09 13:01:14 +00:00
|
|
|
error = linux_sa_put(PTRIN(args->addr));
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
return (0);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2006-03-18 18:20:17 +00:00
|
|
|
struct getpeername_args /* {
|
2000-08-26 05:12:16 +00:00
|
|
|
int fdes;
|
|
|
|
caddr_t asa;
|
|
|
|
int *alen;
|
|
|
|
} */ bsd_args;
|
|
|
|
int error;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.fdes = args->s;
|
|
|
|
bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
|
2015-01-01 20:53:38 +00:00
|
|
|
bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_getpeername(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
2008-09-09 13:01:14 +00:00
|
|
|
error = linux_sa_put(PTRIN(args->addr));
|
2003-02-03 17:43:20 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
return (0);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct socketpair_args /* {
|
|
|
|
int domain;
|
|
|
|
int type;
|
|
|
|
int protocol;
|
|
|
|
int *rsv;
|
|
|
|
} */ bsd_args;
|
2015-05-24 18:06:12 +00:00
|
|
|
int error;
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.domain = linux_to_bsd_domain(args->domain);
|
2009-05-07 03:23:22 +00:00
|
|
|
if (bsd_args.domain != PF_LOCAL)
|
|
|
|
return (EAFNOSUPPORT);
|
2009-05-31 12:16:31 +00:00
|
|
|
bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
|
|
|
|
if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
|
|
|
|
return (EINVAL);
|
2015-05-24 18:06:12 +00:00
|
|
|
error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
|
|
|
|
&bsd_args.type);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2009-05-07 03:23:22 +00:00
|
|
|
if (args->protocol != 0 && args->protocol != PF_UNIX)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use of PF_UNIX as protocol argument is not right,
|
|
|
|
* but Linux does it.
|
|
|
|
* Do not map PF_UNIX as its Linux value is identical
|
|
|
|
* to FreeBSD one.
|
|
|
|
*/
|
|
|
|
return (EPROTONOSUPPORT);
|
2009-05-02 10:51:40 +00:00
|
|
|
else
|
2009-05-07 03:23:22 +00:00
|
|
|
bsd_args.protocol = 0;
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.rsv = (int *)PTRIN(args->rsv);
|
2015-05-24 18:06:12 +00:00
|
|
|
return (sys_socketpair(td, &bsd_args));
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
2006-05-10 20:38:16 +00:00
|
|
|
struct linux_send_args {
|
2000-08-26 05:12:16 +00:00
|
|
|
int s;
|
2004-08-16 07:28:16 +00:00
|
|
|
l_uintptr_t msg;
|
2000-08-26 05:12:16 +00:00
|
|
|
int len;
|
|
|
|
int flags;
|
1995-06-25 17:32:43 +00:00
|
|
|
};
|
|
|
|
|
2006-05-10 20:38:16 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_send(struct thread *td, struct linux_send_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2004-07-08 10:18:07 +00:00
|
|
|
struct sendto_args /* {
|
2002-09-24 07:03:01 +00:00
|
|
|
int s;
|
2000-08-26 05:12:16 +00:00
|
|
|
caddr_t buf;
|
2002-09-24 07:03:01 +00:00
|
|
|
int len;
|
2000-08-26 05:12:16 +00:00
|
|
|
int flags;
|
2004-07-08 10:18:07 +00:00
|
|
|
caddr_t to;
|
|
|
|
int tolen;
|
2000-08-26 05:12:16 +00:00
|
|
|
} */ bsd_args;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.buf = (caddr_t)PTRIN(args->msg);
|
|
|
|
bsd_args.len = args->len;
|
|
|
|
bsd_args.flags = args->flags;
|
2004-07-08 10:18:07 +00:00
|
|
|
bsd_args.to = NULL;
|
|
|
|
bsd_args.tolen = 0;
|
2011-09-16 13:58:51 +00:00
|
|
|
return sys_sendto(td, &bsd_args);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 20:38:16 +00:00
|
|
|
struct linux_recv_args {
|
2000-08-26 05:12:16 +00:00
|
|
|
int s;
|
2004-08-16 07:28:16 +00:00
|
|
|
l_uintptr_t msg;
|
2000-08-26 05:12:16 +00:00
|
|
|
int len;
|
|
|
|
int flags;
|
1995-06-25 17:32:43 +00:00
|
|
|
};
|
|
|
|
|
2006-05-10 20:38:16 +00:00
|
|
|
static int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_recv(struct thread *td, struct linux_recv_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2004-07-08 10:18:07 +00:00
|
|
|
struct recvfrom_args /* {
|
2000-08-26 05:12:16 +00:00
|
|
|
int s;
|
|
|
|
caddr_t buf;
|
|
|
|
int len;
|
|
|
|
int flags;
|
2004-07-08 10:18:07 +00:00
|
|
|
struct sockaddr *from;
|
|
|
|
socklen_t fromlenaddr;
|
2000-08-26 05:12:16 +00:00
|
|
|
} */ bsd_args;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.buf = (caddr_t)PTRIN(args->msg);
|
|
|
|
bsd_args.len = args->len;
|
2009-05-11 13:42:40 +00:00
|
|
|
bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
|
2004-07-08 10:18:07 +00:00
|
|
|
bsd_args.from = NULL;
|
|
|
|
bsd_args.fromlenaddr = 0;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_recvfrom(td, &bsd_args));
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
2015-05-24 15:41:27 +00:00
|
|
|
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
1995-06-25 17:32:43 +00:00
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_sendto(struct thread *td, struct linux_sendto_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2003-11-09 17:04:04 +00:00
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec aiov;
|
|
|
|
int error;
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
if (linux_check_hdrincl(td, args->s) == 0)
|
2000-08-26 05:12:16 +00:00
|
|
|
/* IP_HDRINCL set, tweak the packet before sending */
|
2008-09-09 13:01:14 +00:00
|
|
|
return (linux_sendto_hdrincl(td, args));
|
2003-11-09 17:04:04 +00:00
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
msg.msg_name = PTRIN(args->to);
|
|
|
|
msg.msg_namelen = args->tolen;
|
2003-11-09 17:04:04 +00:00
|
|
|
msg.msg_iov = &aiov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
msg.msg_control = NULL;
|
|
|
|
msg.msg_flags = 0;
|
2008-09-09 13:01:14 +00:00
|
|
|
aiov.iov_base = PTRIN(args->msg);
|
|
|
|
aiov.iov_len = args->len;
|
2008-11-29 17:14:06 +00:00
|
|
|
error = linux_sendit(td, args->s, &msg, args->flags, NULL,
|
|
|
|
UIO_USERSPACE);
|
2003-11-09 17:04:04 +00:00
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2015-05-24 16:26:55 +00:00
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec aiov;
|
2000-08-26 05:12:16 +00:00
|
|
|
int error;
|
|
|
|
|
2015-05-24 16:26:55 +00:00
|
|
|
if (PTRIN(args->fromlen) != NULL) {
|
|
|
|
error = copyin(PTRIN(args->fromlen), &msg.msg_namelen,
|
|
|
|
sizeof(msg.msg_namelen));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2015-05-24 16:26:55 +00:00
|
|
|
error = linux_to_bsd_sockaddr((struct sockaddr *)PTRIN(args->from),
|
|
|
|
msg.msg_namelen);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
} else
|
|
|
|
msg.msg_namelen = 0;
|
|
|
|
|
|
|
|
msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
|
|
|
|
msg.msg_iov = &aiov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
aiov.iov_base = PTRIN(args->buf);
|
|
|
|
aiov.iov_len = args->len;
|
|
|
|
msg.msg_control = 0;
|
|
|
|
msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
|
|
|
|
|
|
|
|
error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
|
|
|
|
if (error != 0)
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
2015-05-24 16:26:55 +00:00
|
|
|
|
|
|
|
if (PTRIN(args->from) != NULL) {
|
|
|
|
error = bsd_to_linux_sockaddr((struct sockaddr *)
|
2008-09-09 13:01:14 +00:00
|
|
|
PTRIN(args->from));
|
2015-05-24 16:26:55 +00:00
|
|
|
if (error != 0)
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
2015-05-24 16:26:55 +00:00
|
|
|
|
|
|
|
error = linux_sa_put((struct osockaddr *)
|
|
|
|
PTRIN(args->from));
|
2003-02-03 17:43:20 +00:00
|
|
|
}
|
2015-05-24 16:26:55 +00:00
|
|
|
|
|
|
|
if (PTRIN(args->fromlen) != NULL)
|
|
|
|
error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
|
|
|
|
sizeof(msg.msg_namelen));
|
|
|
|
|
|
|
|
return (error);
|
2003-02-03 17:43:20 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
static int
|
|
|
|
linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
|
|
|
|
l_uint flags)
|
2003-02-03 17:43:20 +00:00
|
|
|
{
|
2008-11-29 17:14:06 +00:00
|
|
|
struct cmsghdr *cmsg;
|
2011-03-26 11:05:53 +00:00
|
|
|
struct cmsgcred cmcred;
|
2008-11-29 17:14:06 +00:00
|
|
|
struct mbuf *control;
|
2003-02-03 17:43:20 +00:00
|
|
|
struct msghdr msg;
|
2008-11-29 17:14:06 +00:00
|
|
|
struct l_cmsghdr linux_cmsg;
|
|
|
|
struct l_cmsghdr *ptr_cmsg;
|
|
|
|
struct l_msghdr linux_msg;
|
2004-07-10 15:42:16 +00:00
|
|
|
struct iovec *iov;
|
2008-11-29 17:14:06 +00:00
|
|
|
socklen_t datalen;
|
2011-03-26 11:05:53 +00:00
|
|
|
struct sockaddr *sa;
|
|
|
|
sa_family_t sa_family;
|
2008-11-29 17:14:06 +00:00
|
|
|
void *data;
|
2003-02-03 17:43:20 +00:00
|
|
|
int error;
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
|
|
|
|
if (error != 0)
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
2007-04-14 10:35:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Some Linux applications (ping) define a non-NULL control data
|
|
|
|
* pointer, but a msg_controllen of 0, which is not allowed in the
|
|
|
|
* FreeBSD system call interface. NULL the msg_control pointer in
|
|
|
|
* order to handle this case. This should be checked, but allows the
|
|
|
|
* Linux ping to work.
|
|
|
|
*/
|
2011-03-26 11:05:53 +00:00
|
|
|
if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
|
|
|
|
linux_msg.msg_control = PTROUT(NULL);
|
|
|
|
|
|
|
|
error = linux_to_bsd_msghdr(&msg, &linux_msg);
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2011-03-26 11:05:53 +00:00
|
|
|
return (error);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
|
|
|
#ifdef COMPAT_LINUX32
|
|
|
|
error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
|
|
|
|
&iov, EMSGSIZE);
|
|
|
|
#else
|
2004-07-10 15:42:16 +00:00
|
|
|
error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
|
2008-11-29 17:14:06 +00:00
|
|
|
#endif
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2004-07-10 15:42:16 +00:00
|
|
|
return (error);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
control = NULL;
|
|
|
|
cmsg = NULL;
|
|
|
|
|
|
|
|
if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
|
2015-05-24 18:04:04 +00:00
|
|
|
error = kern_getsockname(td, s, &sa, &datalen);
|
|
|
|
if (error != 0)
|
2011-03-26 11:05:53 +00:00
|
|
|
goto bad;
|
|
|
|
sa_family = sa->sa_family;
|
|
|
|
free(sa, M_SONAME);
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
error = ENOBUFS;
|
2015-05-24 18:04:04 +00:00
|
|
|
cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO);
|
2012-12-05 08:04:20 +00:00
|
|
|
control = m_get(M_WAITOK, MT_CONTROL);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
error = copyin(ptr_cmsg, &linux_cmsg,
|
|
|
|
sizeof(struct l_cmsghdr));
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
error = EINVAL;
|
|
|
|
if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/*
|
2011-03-26 11:05:53 +00:00
|
|
|
* Now we support only SCM_RIGHTS and SCM_CRED,
|
|
|
|
* so return EINVAL in any other cmsg_type
|
2008-11-29 17:14:06 +00:00
|
|
|
*/
|
2011-03-26 11:05:53 +00:00
|
|
|
cmsg->cmsg_type =
|
|
|
|
linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
|
2008-11-29 17:14:06 +00:00
|
|
|
cmsg->cmsg_level =
|
|
|
|
linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
|
2011-03-26 11:05:53 +00:00
|
|
|
if (cmsg->cmsg_type == -1
|
|
|
|
|| cmsg->cmsg_level != SOL_SOCKET)
|
|
|
|
goto bad;
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
/*
|
|
|
|
* Some applications (e.g. pulseaudio) attempt to
|
|
|
|
* send ancillary data even if the underlying protocol
|
|
|
|
* doesn't support it which is not allowed in the
|
|
|
|
* FreeBSD system call interface.
|
|
|
|
*/
|
|
|
|
if (sa_family != AF_UNIX)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
data = LINUX_CMSG_DATA(ptr_cmsg);
|
2008-11-29 17:14:06 +00:00
|
|
|
datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
|
2011-03-26 11:05:53 +00:00
|
|
|
|
|
|
|
switch (cmsg->cmsg_type)
|
|
|
|
{
|
|
|
|
case SCM_RIGHTS:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCM_CREDS:
|
|
|
|
data = &cmcred;
|
|
|
|
datalen = sizeof(cmcred);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The lower levels will fill in the structure
|
|
|
|
*/
|
|
|
|
bzero(data, datalen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
cmsg->cmsg_len = CMSG_LEN(datalen);
|
|
|
|
|
|
|
|
error = ENOBUFS;
|
2011-10-06 21:17:46 +00:00
|
|
|
if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg))
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
2011-10-06 21:17:46 +00:00
|
|
|
if (!m_append(control, datalen, (c_caddr_t)data))
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
2011-03-26 11:05:53 +00:00
|
|
|
} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
|
|
|
|
|
|
|
|
if (m_length(control, NULL) == 0) {
|
|
|
|
m_freem(control);
|
|
|
|
control = NULL;
|
|
|
|
}
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
|
|
|
|
2003-11-09 17:04:04 +00:00
|
|
|
msg.msg_iov = iov;
|
|
|
|
msg.msg_flags = 0;
|
2015-05-24 18:04:04 +00:00
|
|
|
error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
|
|
|
bad:
|
2015-05-24 18:10:07 +00:00
|
|
|
m_freem(control);
|
2004-07-10 15:42:16 +00:00
|
|
|
free(iov, M_IOV);
|
2008-11-29 17:14:06 +00:00
|
|
|
if (cmsg)
|
2015-05-24 16:14:41 +00:00
|
|
|
free(cmsg, M_LINUX);
|
2003-11-09 17:04:04 +00:00
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2015-05-24 18:04:04 +00:00
|
|
|
linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
|
|
|
|
args->flags));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
|
|
|
|
{
|
|
|
|
struct l_mmsghdr *msg;
|
|
|
|
l_uint retval;
|
|
|
|
int error, datagrams;
|
|
|
|
|
|
|
|
if (args->vlen > UIO_MAXIOV)
|
|
|
|
args->vlen = UIO_MAXIOV;
|
|
|
|
|
|
|
|
msg = PTRIN(args->msg);
|
|
|
|
datagrams = 0;
|
|
|
|
while (datagrams < args->vlen) {
|
|
|
|
error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
|
|
|
|
args->flags);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
retval = td->td_retval[0];
|
|
|
|
error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
++msg;
|
|
|
|
++datagrams;
|
|
|
|
}
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = datagrams;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
|
|
|
|
l_uint flags, struct msghdr *msg)
|
2000-12-19 00:24:25 +00:00
|
|
|
{
|
2008-11-29 17:14:06 +00:00
|
|
|
struct cmsghdr *cm;
|
2011-03-26 11:05:53 +00:00
|
|
|
struct cmsgcred *cmcred;
|
2008-11-29 17:14:06 +00:00
|
|
|
struct l_cmsghdr *linux_cmsg = NULL;
|
2011-03-26 11:05:53 +00:00
|
|
|
struct l_ucred linux_ucred;
|
|
|
|
socklen_t datalen, outlen;
|
2008-11-29 17:14:06 +00:00
|
|
|
struct l_msghdr linux_msg;
|
|
|
|
struct iovec *iov, *uiov;
|
|
|
|
struct mbuf *control = NULL;
|
|
|
|
struct mbuf **controlp;
|
2015-05-24 18:13:21 +00:00
|
|
|
struct timeval *ftmvl;
|
|
|
|
l_timeval ltmvl;
|
2008-11-29 17:14:06 +00:00
|
|
|
caddr_t outbuf;
|
|
|
|
void *data;
|
2009-05-18 04:07:46 +00:00
|
|
|
int error, i, fd, fds, *fdp;
|
2000-12-19 00:24:25 +00:00
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
|
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
return (error);
|
2004-08-16 07:28:16 +00:00
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
error = linux_to_bsd_msghdr(msg, &linux_msg);
|
|
|
|
if (error != 0)
|
2007-02-01 13:36:19 +00:00
|
|
|
return (error);
|
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
#ifdef COMPAT_LINUX32
|
2015-05-24 18:04:04 +00:00
|
|
|
error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
|
2008-11-29 17:14:06 +00:00
|
|
|
&iov, EMSGSIZE);
|
|
|
|
#else
|
2015-05-24 18:04:04 +00:00
|
|
|
error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
|
2008-11-29 17:14:06 +00:00
|
|
|
#endif
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
if (msg->msg_name) {
|
|
|
|
error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
|
|
|
|
msg->msg_namelen);
|
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
2003-10-11 15:08:32 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
uiov = msg->msg_iov;
|
|
|
|
msg->msg_iov = iov;
|
|
|
|
controlp = (msg->msg_control != NULL) ? &control : NULL;
|
|
|
|
error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
|
|
|
|
msg->msg_iov = uiov;
|
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
error = bsd_to_linux_msghdr(msg, &linux_msg);
|
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (linux_msg.msg_name) {
|
|
|
|
error = bsd_to_linux_sockaddr((struct sockaddr *)
|
|
|
|
PTRIN(linux_msg.msg_name));
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
|
|
|
|
error = linux_sa_put(PTRIN(linux_msg.msg_name));
|
2015-05-24 18:04:04 +00:00
|
|
|
if (error != 0)
|
2008-11-29 17:14:06 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
outbuf = PTRIN(linux_msg.msg_control);
|
|
|
|
outlen = 0;
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
if (control) {
|
2015-05-24 16:14:41 +00:00
|
|
|
linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
msg->msg_control = mtod(control, struct cmsghdr *);
|
|
|
|
msg->msg_controllen = control->m_len;
|
2011-03-26 11:05:53 +00:00
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
cm = CMSG_FIRSTHDR(msg);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
while (cm != NULL) {
|
|
|
|
linux_cmsg->cmsg_type =
|
|
|
|
bsd_to_linux_cmsg_type(cm->cmsg_type);
|
|
|
|
linux_cmsg->cmsg_level =
|
|
|
|
bsd_to_linux_sockopt_level(cm->cmsg_level);
|
|
|
|
if (linux_cmsg->cmsg_type == -1
|
|
|
|
|| cm->cmsg_level != SOL_SOCKET)
|
2008-11-29 17:14:06 +00:00
|
|
|
{
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
2011-03-26 11:05:53 +00:00
|
|
|
|
2008-11-29 17:14:06 +00:00
|
|
|
data = CMSG_DATA(cm);
|
|
|
|
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
|
|
|
|
|
2011-03-26 11:05:53 +00:00
|
|
|
switch (cm->cmsg_type)
|
2009-05-18 04:07:46 +00:00
|
|
|
{
|
2011-03-26 11:05:53 +00:00
|
|
|
case SCM_RIGHTS:
|
2015-05-24 18:04:04 +00:00
|
|
|
if (flags & LINUX_MSG_CMSG_CLOEXEC) {
|
2009-05-18 04:07:46 +00:00
|
|
|
fds = datalen / sizeof(int);
|
|
|
|
fdp = data;
|
|
|
|
for (i = 0; i < fds; i++) {
|
|
|
|
fd = *fdp++;
|
|
|
|
(void)kern_fcntl(td, fd,
|
|
|
|
F_SETFD, FD_CLOEXEC);
|
|
|
|
}
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
2009-05-18 04:07:46 +00:00
|
|
|
break;
|
2011-03-26 11:05:53 +00:00
|
|
|
|
|
|
|
case SCM_CREDS:
|
|
|
|
/*
|
|
|
|
* Currently LOCAL_CREDS is never in
|
|
|
|
* effect for Linux so no need to worry
|
|
|
|
* about sockcred
|
|
|
|
*/
|
2011-10-06 21:17:46 +00:00
|
|
|
if (datalen != sizeof(*cmcred)) {
|
2011-03-26 11:05:53 +00:00
|
|
|
error = EMSGSIZE;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
cmcred = (struct cmsgcred *)data;
|
|
|
|
bzero(&linux_ucred, sizeof(linux_ucred));
|
|
|
|
linux_ucred.pid = cmcred->cmcred_pid;
|
|
|
|
linux_ucred.uid = cmcred->cmcred_uid;
|
|
|
|
linux_ucred.gid = cmcred->cmcred_gid;
|
|
|
|
data = &linux_ucred;
|
|
|
|
datalen = sizeof(linux_ucred);
|
|
|
|
break;
|
2015-05-24 18:13:21 +00:00
|
|
|
|
|
|
|
case SCM_TIMESTAMP:
|
|
|
|
if (datalen != sizeof(struct timeval)) {
|
|
|
|
error = EMSGSIZE;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ftmvl = (struct timeval *)data;
|
|
|
|
ltmvl.tv_sec = ftmvl->tv_sec;
|
|
|
|
ltmvl.tv_usec = ftmvl->tv_usec;
|
|
|
|
data = <mvl;
|
|
|
|
datalen = sizeof(ltmvl);
|
|
|
|
break;
|
2011-03-26 11:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (outlen + LINUX_CMSG_LEN(datalen) >
|
|
|
|
linux_msg.msg_controllen) {
|
|
|
|
if (outlen == 0) {
|
|
|
|
error = EMSGSIZE;
|
|
|
|
goto bad;
|
|
|
|
} else {
|
|
|
|
linux_msg.msg_flags |=
|
|
|
|
LINUX_MSG_CTRUNC;
|
|
|
|
goto out;
|
|
|
|
}
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
|
|
|
|
|
|
|
|
error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
|
|
|
|
if (error)
|
|
|
|
goto bad;
|
|
|
|
outbuf += L_CMSG_HDRSZ;
|
|
|
|
|
|
|
|
error = copyout(data, outbuf, datalen);
|
|
|
|
if (error)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
outbuf += LINUX_CMSG_ALIGN(datalen);
|
|
|
|
outlen += LINUX_CMSG_LEN(datalen);
|
2011-03-26 11:05:53 +00:00
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
cm = CMSG_NXTHDR(msg, cm);
|
2008-11-29 17:14:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2011-03-26 11:05:53 +00:00
|
|
|
linux_msg.msg_controllen = outlen;
|
2015-05-24 18:04:04 +00:00
|
|
|
error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
|
2008-11-29 17:14:06 +00:00
|
|
|
|
|
|
|
bad:
|
|
|
|
free(iov, M_IOV);
|
2013-03-04 02:21:34 +00:00
|
|
|
m_freem(control);
|
2015-05-24 16:14:41 +00:00
|
|
|
free(linux_cmsg, M_LINUX);
|
2008-11-29 17:14:06 +00:00
|
|
|
|
2003-02-03 17:43:20 +00:00
|
|
|
return (error);
|
2000-12-19 00:24:25 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 18:04:04 +00:00
|
|
|
int
|
|
|
|
linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
|
|
|
|
{
|
|
|
|
struct msghdr bsd_msg;
|
|
|
|
|
|
|
|
return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
|
|
|
|
args->flags, &bsd_msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
|
|
|
|
{
|
|
|
|
struct l_mmsghdr *msg;
|
|
|
|
struct msghdr bsd_msg;
|
|
|
|
struct l_timespec lts;
|
|
|
|
struct timespec ts, tts;
|
|
|
|
l_uint retval;
|
|
|
|
int error, datagrams;
|
|
|
|
|
|
|
|
if (args->timeout) {
|
|
|
|
error = copyin(args->timeout, <s, sizeof(struct l_timespec));
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
error = linux_to_native_timespec(&ts, <s);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
getnanotime(&tts);
|
|
|
|
timespecadd(&tts, &ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = PTRIN(args->msg);
|
|
|
|
datagrams = 0;
|
|
|
|
while (datagrams < args->vlen) {
|
|
|
|
error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
|
|
|
|
args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
retval = td->td_retval[0];
|
|
|
|
error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
++msg;
|
|
|
|
++datagrams;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
|
|
|
|
*/
|
|
|
|
if (args->flags & LINUX_MSG_WAITFORONE)
|
|
|
|
args->flags |= LINUX_MSG_DONTWAIT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See BUGS section of recvmmsg(2).
|
|
|
|
*/
|
|
|
|
if (args->timeout) {
|
|
|
|
getnanotime(&ts);
|
|
|
|
timespecsub(&ts, &tts);
|
|
|
|
if (!timespecisset(&ts) || ts.tv_sec > 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Out of band data, return right away. */
|
|
|
|
if (bsd_msg.msg_flags & MSG_OOB)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = datagrams;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct shutdown_args /* {
|
|
|
|
int s;
|
|
|
|
int how;
|
|
|
|
} */ bsd_args;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.how = args->how;
|
2011-09-16 13:58:51 +00:00
|
|
|
return (sys_shutdown(td, &bsd_args));
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct setsockopt_args /* {
|
|
|
|
int s;
|
|
|
|
int level;
|
|
|
|
int name;
|
|
|
|
caddr_t val;
|
|
|
|
int valsize;
|
|
|
|
} */ bsd_args;
|
2009-05-11 13:50:42 +00:00
|
|
|
l_timeval linux_tv;
|
|
|
|
struct timeval tv;
|
2000-08-26 05:12:16 +00:00
|
|
|
int error, name;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.level = linux_to_bsd_sockopt_level(args->level);
|
2000-08-26 05:12:16 +00:00
|
|
|
switch (bsd_args.level) {
|
|
|
|
case SOL_SOCKET:
|
2008-09-09 13:01:14 +00:00
|
|
|
name = linux_to_bsd_so_sockopt(args->optname);
|
2009-05-11 13:50:42 +00:00
|
|
|
switch (name) {
|
|
|
|
case SO_RCVTIMEO:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SO_SNDTIMEO:
|
|
|
|
error = copyin(PTRIN(args->optval), &linux_tv,
|
|
|
|
sizeof(linux_tv));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
tv.tv_sec = linux_tv.tv_sec;
|
|
|
|
tv.tv_usec = linux_tv.tv_usec;
|
|
|
|
return (kern_setsockopt(td, args->s, bsd_args.level,
|
|
|
|
name, &tv, UIO_SYSSPACE, sizeof(tv)));
|
|
|
|
/* NOTREACHED */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
case IPPROTO_IP:
|
2008-09-09 13:01:14 +00:00
|
|
|
name = linux_to_bsd_ip_sockopt(args->optname);
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
case IPPROTO_TCP:
|
2013-01-23 21:44:48 +00:00
|
|
|
name = linux_to_bsd_tcp_sockopt(args->optname);
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
name = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (name == -1)
|
2006-09-23 19:06:54 +00:00
|
|
|
return (ENOPROTOOPT);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
|
|
|
bsd_args.name = name;
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.val = PTRIN(args->optval);
|
|
|
|
bsd_args.valsize = args->optlen;
|
2006-03-18 18:20:17 +00:00
|
|
|
|
|
|
|
if (name == IPV6_NEXTHOP) {
|
|
|
|
linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
|
|
|
|
bsd_args.valsize);
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_setsockopt(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
|
|
|
|
} else
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_setsockopt(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
|
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:41:27 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2000-08-26 05:12:16 +00:00
|
|
|
struct getsockopt_args /* {
|
|
|
|
int s;
|
|
|
|
int level;
|
|
|
|
int name;
|
|
|
|
caddr_t val;
|
|
|
|
int *avalsize;
|
|
|
|
} */ bsd_args;
|
2009-05-11 13:50:42 +00:00
|
|
|
l_timeval linux_tv;
|
|
|
|
struct timeval tv;
|
2009-05-16 18:42:18 +00:00
|
|
|
socklen_t tv_len, xulen;
|
|
|
|
struct xucred xu;
|
|
|
|
struct l_ucred lxu;
|
2000-08-26 05:12:16 +00:00
|
|
|
int error, name;
|
|
|
|
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.s = args->s;
|
|
|
|
bsd_args.level = linux_to_bsd_sockopt_level(args->level);
|
2000-08-26 05:12:16 +00:00
|
|
|
switch (bsd_args.level) {
|
|
|
|
case SOL_SOCKET:
|
2008-09-09 13:01:14 +00:00
|
|
|
name = linux_to_bsd_so_sockopt(args->optname);
|
2009-05-11 13:50:42 +00:00
|
|
|
switch (name) {
|
|
|
|
case SO_RCVTIMEO:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SO_SNDTIMEO:
|
|
|
|
tv_len = sizeof(tv);
|
|
|
|
error = kern_getsockopt(td, args->s, bsd_args.level,
|
|
|
|
name, &tv, UIO_SYSSPACE, &tv_len);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
linux_tv.tv_sec = tv.tv_sec;
|
|
|
|
linux_tv.tv_usec = tv.tv_usec;
|
|
|
|
return (copyout(&linux_tv, PTRIN(args->optval),
|
|
|
|
sizeof(linux_tv)));
|
|
|
|
/* NOTREACHED */
|
|
|
|
break;
|
2009-05-16 18:42:18 +00:00
|
|
|
case LOCAL_PEERCRED:
|
|
|
|
if (args->optlen != sizeof(lxu))
|
|
|
|
return (EINVAL);
|
|
|
|
xulen = sizeof(xu);
|
|
|
|
error = kern_getsockopt(td, args->s, bsd_args.level,
|
|
|
|
name, &xu, UIO_SYSSPACE, &xulen);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
/*
|
|
|
|
* XXX Use 0 for pid as the FreeBSD does not cache peer pid.
|
|
|
|
*/
|
|
|
|
lxu.pid = 0;
|
|
|
|
lxu.uid = xu.cr_uid;
|
|
|
|
lxu.gid = xu.cr_gid;
|
|
|
|
return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
|
|
|
|
/* NOTREACHED */
|
|
|
|
break;
|
2009-05-11 13:50:42 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
case IPPROTO_IP:
|
2008-09-09 13:01:14 +00:00
|
|
|
name = linux_to_bsd_ip_sockopt(args->optname);
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
case IPPROTO_TCP:
|
2013-01-23 21:44:48 +00:00
|
|
|
name = linux_to_bsd_tcp_sockopt(args->optname);
|
2000-08-26 05:12:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
name = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (name == -1)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
bsd_args.name = name;
|
2008-09-09 13:01:14 +00:00
|
|
|
bsd_args.val = PTRIN(args->optval);
|
|
|
|
bsd_args.avalsize = PTRIN(args->optlen);
|
2006-03-18 18:20:17 +00:00
|
|
|
|
|
|
|
if (name == IPV6_NEXTHOP) {
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_getsockopt(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
|
|
|
|
} else
|
2011-09-16 13:58:51 +00:00
|
|
|
error = sys_getsockopt(td, &bsd_args);
|
2006-03-18 18:20:17 +00:00
|
|
|
|
|
|
|
return (error);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 15:43:53 +00:00
|
|
|
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
|
|
|
|
2009-05-19 09:10:53 +00:00
|
|
|
/* Argument list sizes for linux_socketcall */
|
|
|
|
|
|
|
|
#define LINUX_AL(x) ((x) * sizeof(l_ulong))
|
|
|
|
|
|
|
|
static const unsigned char lxs_args[] = {
|
|
|
|
LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */,
|
|
|
|
LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */,
|
|
|
|
LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */,
|
|
|
|
LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */,
|
|
|
|
LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */,
|
|
|
|
LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */,
|
|
|
|
LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */,
|
|
|
|
LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */,
|
2009-06-01 20:48:39 +00:00
|
|
|
LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */,
|
2015-05-24 18:04:04 +00:00
|
|
|
LINUX_AL(4) /* accept4 */, LINUX_AL(5) /* recvmmsg */,
|
|
|
|
LINUX_AL(4) /* sendmmsg */
|
2009-05-19 09:10:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
|
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
int
|
2001-09-12 08:38:13 +00:00
|
|
|
linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
|
1995-06-25 17:32:43 +00:00
|
|
|
{
|
2009-05-19 09:10:53 +00:00
|
|
|
l_ulong a[6];
|
|
|
|
void *arg;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
|
|
|
|
return (EINVAL);
|
|
|
|
error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
2000-08-26 05:12:16 +00:00
|
|
|
|
2009-05-19 09:10:53 +00:00
|
|
|
arg = a;
|
2000-08-26 05:12:16 +00:00
|
|
|
switch (args->what) {
|
|
|
|
case LINUX_SOCKET:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_socket(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_BIND:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_bind(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_CONNECT:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_connect(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_LISTEN:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_listen(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_ACCEPT:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_accept(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_GETSOCKNAME:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_getsockname(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_GETPEERNAME:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_getpeername(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SOCKETPAIR:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_socketpair(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SEND:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_send(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_RECV:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_recv(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SENDTO:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_sendto(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_RECVFROM:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_recvfrom(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SHUTDOWN:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_shutdown(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SETSOCKOPT:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_setsockopt(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_GETSOCKOPT:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_getsockopt(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_SENDMSG:
|
2003-02-03 17:43:20 +00:00
|
|
|
return (linux_sendmsg(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
case LINUX_RECVMSG:
|
2001-09-12 08:38:13 +00:00
|
|
|
return (linux_recvmsg(td, arg));
|
2009-06-01 20:48:39 +00:00
|
|
|
case LINUX_ACCEPT4:
|
|
|
|
return (linux_accept4(td, arg));
|
2015-05-24 18:04:04 +00:00
|
|
|
case LINUX_RECVMMSG:
|
|
|
|
return (linux_recvmmsg(td, arg));
|
|
|
|
case LINUX_SENDMMSG:
|
|
|
|
return (linux_sendmmsg(td, arg));
|
2000-08-26 05:12:16 +00:00
|
|
|
}
|
1998-12-30 21:20:00 +00:00
|
|
|
|
1995-06-25 17:32:43 +00:00
|
|
|
uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
|
2000-08-26 05:12:16 +00:00
|
|
|
return (ENOSYS);
|
1995-06-25 17:32:43 +00:00
|
|
|
}
|
2015-05-24 15:41:27 +00:00
|
|
|
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|