1995-06-25 17:32:43 +00:00
/*-
2018-02-16 15:00:14 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause - FreeBSD
2017-11-27 15:13:23 +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
2018-02-16 15:00:14 +00:00
* notice , this list of conditions and the following disclaimer .
1995-06-25 17:32:43 +00:00
* 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 .
*
2018-02-16 15:00:14 +00:00
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` 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 OR CONTRIBUTORS 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 .
1995-06-25 17:32:43 +00:00
*/
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>
2020-07-01 10:37:08 +00:00
# include <sys/filedesc.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>
2020-02-05 16:53:02 +00:00
# include <sys/stat.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>
2020-02-05 16:53:02 +00:00
# include <sys/unistd.h>
# include <security/audit/audit.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
2019-05-13 17:48:16 +00:00
# include <compat/linux/linux_common.h>
2022-05-28 20:45:39 +00:00
# include <compat/linux/linux_emul.h>
2015-05-24 16:31:44 +00:00
# include <compat/linux/linux_file.h>
2020-01-28 13:51:53 +00:00
# include <compat/linux/linux_mib.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
2021-02-07 20:28:35 +00:00
# define SECURITY_CONTEXT_STRING "unconfined"
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
2022-08-26 14:34:15 +00:00
# define SOL_NETLINK 270
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
2020-06-12 14:23:10 +00:00
if ( level = = LINUX_SOL_SOCKET )
2000-08-26 05:12:16 +00:00
return ( SOL_SOCKET ) ;
2020-06-12 14:23:10 +00:00
/* Remaining values are RFC-defined protocol numbers. */
2000-08-26 05:12:16 +00:00
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 )
{
2020-06-12 14:23:10 +00:00
if ( level = = SOL_SOCKET )
2003-10-11 15:08:32 +00:00
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 ) {
2020-11-08 09:50:58 +00:00
/* known and translated sockopts */
2000-08-26 05:12:16 +00:00
case LINUX_IP_TOS :
return ( IP_TOS ) ;
case LINUX_IP_TTL :
return ( IP_TTL ) ;
2020-11-08 09:50:58 +00:00
case LINUX_IP_HDRINCL :
return ( IP_HDRINCL ) ;
2000-08-26 05:12:16 +00:00
case LINUX_IP_OPTIONS :
return ( IP_OPTIONS ) ;
2020-11-08 09:50:58 +00:00
case LINUX_IP_RECVOPTS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_RECVOPTS " ) ;
return ( IP_RECVOPTS ) ;
case LINUX_IP_RETOPTS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_REETOPTS " ) ;
return ( IP_RETOPTS ) ;
case LINUX_IP_RECVTTL :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_RECVTTL " ) ;
return ( IP_RECVTTL ) ;
case LINUX_IP_RECVTOS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_RECVTOS " ) ;
return ( IP_RECVTOS ) ;
case LINUX_IP_FREEBIND :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_FREEBIND " ) ;
return ( IP_BINDANY ) ;
case LINUX_IP_IPSEC_POLICY :
/* we have this option, but not documented in ip(4) manpage */
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_IPSEC_POLICY " ) ;
return ( IP_IPSEC_POLICY ) ;
case LINUX_IP_MINTTL :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_MINTTL " ) ;
return ( IP_MINTTL ) ;
2000-08-26 05:12:16 +00:00
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 ) ;
2020-11-08 09:50:58 +00:00
case LINUX_IP_UNBLOCK_SOURCE :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_UNBLOCK_SOURCE " ) ;
return ( IP_UNBLOCK_SOURCE ) ;
case LINUX_IP_BLOCK_SOURCE :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_BLOCK_SOURCE " ) ;
return ( IP_BLOCK_SOURCE ) ;
case LINUX_IP_ADD_SOURCE_MEMBERSHIP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_ADD_SOURCE_MEMBERSHIP " ) ;
return ( IP_ADD_SOURCE_MEMBERSHIP ) ;
case LINUX_IP_DROP_SOURCE_MEMBERSHIP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_DROP_SOURCE_MEMBERSHIP " ) ;
return ( IP_DROP_SOURCE_MEMBERSHIP ) ;
case LINUX_MCAST_JOIN_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_MCAST_JOIN_GROUP " ) ;
return ( MCAST_JOIN_GROUP ) ;
case LINUX_MCAST_LEAVE_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_MCAST_LEAVE_GROUP " ) ;
return ( MCAST_LEAVE_GROUP ) ;
case LINUX_MCAST_JOIN_SOURCE_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_MCAST_JOIN_SOURCE_GROUP " ) ;
return ( MCAST_JOIN_SOURCE_GROUP ) ;
case LINUX_MCAST_LEAVE_SOURCE_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv4 socket option IP_MCAST_LEAVE_SOURCE_GROUP " ) ;
return ( MCAST_LEAVE_SOURCE_GROUP ) ;
2022-05-28 20:47:40 +00:00
case LINUX_IP_RECVORIGDSTADDR :
return ( IP_RECVORIGDSTADDR ) ;
2020-11-08 09:50:58 +00:00
/* known but not implemented sockopts */
case LINUX_IP_ROUTER_ALERT :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_ROUTER_ALERT (%d), you can not do user-space routing from linux programs " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_PKTINFO :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_PKTINFO (%d), you can not get extended packet info for datagram sockets in linux programs " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_PKTOPTIONS :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_PKTOPTIONS (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_MTU_DISCOVER :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_RECVERR :
/* needed by steam */
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_RECVERR (%d), you can not get extended reliability info in linux programs " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_MTU :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_MTU (%d), your linux program can not control the MTU on this socket " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_XFRM_POLICY :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_XFRM_POLICY (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_PASSSEC :
/* needed by steam */
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_PASSSEC (%d), you can not get IPSEC related credential information associated with this socket in linux programs -- if you do not use IPSEC, you can ignore this " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_TRANSPARENT :
/* IP_BINDANY or more? */
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_NODEFRAG :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_NODEFRAG (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_CHECKSUM :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_CHECKSUM (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_BIND_ADDRESS_NO_PORT :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_BIND_ADDRESS_NO_PORT (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_RECVFRAGSIZE :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_RECVFRAGSIZE (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_MSFILTER :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_MCAST_MSFILTER (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_MULTICAST_ALL :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_MULTICAST_ALL (%d), your linux program will not see all multicast groups joined by the entire system, only those the program joined itself on this socket " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IP_UNICAST_IF :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv4 socket option IP_UNICAST_IF (%d) " ,
opt ) ;
return ( - 2 ) ;
/* unknown sockopts */
default :
return ( - 1 ) ;
2000-08-26 05:12:16 +00:00
}
1995-06-25 17:32:43 +00:00
}
2016-03-09 09:12:40 +00:00
static int
linux_to_bsd_ip6_sockopt ( int opt )
{
switch ( opt ) {
2020-11-08 09:50:58 +00:00
/* known and translated sockopts */
case LINUX_IPV6_2292PKTINFO :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292PKTINFO " ) ;
return ( IPV6_2292PKTINFO ) ;
case LINUX_IPV6_2292HOPOPTS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292HOPOPTS " ) ;
return ( IPV6_2292HOPOPTS ) ;
case LINUX_IPV6_2292DSTOPTS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292DSTOPTS " ) ;
return ( IPV6_2292DSTOPTS ) ;
case LINUX_IPV6_2292RTHDR :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292RTHDR " ) ;
return ( IPV6_2292RTHDR ) ;
case LINUX_IPV6_2292PKTOPTIONS :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292PKTOPTIONS " ) ;
return ( IPV6_2292PKTOPTIONS ) ;
case LINUX_IPV6_CHECKSUM :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_CHECKSUM " ) ;
return ( IPV6_CHECKSUM ) ;
case LINUX_IPV6_2292HOPLIMIT :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_2292HOPLIMIT " ) ;
return ( IPV6_2292HOPLIMIT ) ;
2016-03-09 09:12:40 +00:00
case LINUX_IPV6_NEXTHOP :
return ( IPV6_NEXTHOP ) ;
case LINUX_IPV6_UNICAST_HOPS :
return ( IPV6_UNICAST_HOPS ) ;
case LINUX_IPV6_MULTICAST_IF :
return ( IPV6_MULTICAST_IF ) ;
case LINUX_IPV6_MULTICAST_HOPS :
return ( IPV6_MULTICAST_HOPS ) ;
case LINUX_IPV6_MULTICAST_LOOP :
return ( IPV6_MULTICAST_LOOP ) ;
case LINUX_IPV6_ADD_MEMBERSHIP :
return ( IPV6_JOIN_GROUP ) ;
case LINUX_IPV6_DROP_MEMBERSHIP :
return ( IPV6_LEAVE_GROUP ) ;
case LINUX_IPV6_V6ONLY :
return ( IPV6_V6ONLY ) ;
2020-11-08 09:50:58 +00:00
case LINUX_IPV6_IPSEC_POLICY :
/* we have this option, but not documented in ip6(4) manpage */
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_IPSEC_POLICY " ) ;
return ( IPV6_IPSEC_POLICY ) ;
case LINUX_MCAST_JOIN_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_JOIN_GROUP " ) ;
return ( IPV6_JOIN_GROUP ) ;
case LINUX_MCAST_LEAVE_GROUP :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_LEAVE_GROUP " ) ;
return ( IPV6_LEAVE_GROUP ) ;
2016-03-09 09:12:40 +00:00
case LINUX_IPV6_RECVPKTINFO :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVPKTINFO " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVPKTINFO ) ;
case LINUX_IPV6_PKTINFO :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_PKTINFO " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_PKTINFO ) ;
case LINUX_IPV6_RECVHOPLIMIT :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVHOPLIMIT " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVHOPLIMIT ) ;
case LINUX_IPV6_HOPLIMIT :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_HOPLIMIT " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_HOPLIMIT ) ;
case LINUX_IPV6_RECVHOPOPTS :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVHOPOPTS " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVHOPOPTS ) ;
case LINUX_IPV6_HOPOPTS :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_HOPOPTS " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_HOPOPTS ) ;
case LINUX_IPV6_RTHDRDSTOPTS :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RTHDRDSTOPTS " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RTHDRDSTOPTS ) ;
case LINUX_IPV6_RECVRTHDR :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVRTHDR " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVRTHDR ) ;
case LINUX_IPV6_RTHDR :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RTHDR " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RTHDR ) ;
case LINUX_IPV6_RECVDSTOPTS :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVDSTOPTS " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVDSTOPTS ) ;
case LINUX_IPV6_DSTOPTS :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_DSTOPTS " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_DSTOPTS ) ;
case LINUX_IPV6_RECVPATHMTU :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVPATHMTU " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_RECVPATHMTU ) ;
case LINUX_IPV6_PATHMTU :
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_PATHMTU " ) ;
2016-03-09 09:12:40 +00:00
return ( IPV6_PATHMTU ) ;
2020-11-08 09:50:58 +00:00
case LINUX_IPV6_DONTFRAG :
return ( IPV6_DONTFRAG ) ;
case LINUX_IPV6_AUTOFLOWLABEL :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_AUTOFLOWLABEL " ) ;
return ( IPV6_AUTOFLOWLABEL ) ;
case LINUX_IPV6_ORIGDSTADDR :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_ORIGDSTADDR " ) ;
return ( IPV6_ORIGDSTADDR ) ;
case LINUX_IPV6_FREEBIND :
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_FREEBIND " ) ;
return ( IPV6_BINDANY ) ;
/* known but not implemented sockopts */
case LINUX_IPV6_ADDRFORM :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_ADDRFORM (%d), you linux program can not convert the socket to IPv4 " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_AUTHHDR :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_AUTHHDR (%d), your linux program can not get the authentication header info of IPv6 packets " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_FLOWINFO :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_FLOWINFO (%d), your linux program can not get the flowid of IPv6 packets " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_ROUTER_ALERT :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_ROUTER_ALERT (%d), you can not do user-space routing from linux programs " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_MTU_DISCOVER :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_MTU_DISCOVER (%d), your linux program can not control path-MTU discovery " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_MTU :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_MTU (%d), your linux program can not control the MTU on this socket " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_JOIN_ANYCAST :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_JOIN_ANYCAST (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_LEAVE_ANYCAST :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_LEAVE_ANYCAST (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_MULTICAST_ALL :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_MULTICAST_ALL (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_ROUTER_ALERT_ISOLATE :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_ROUTER_ALERT_ISOLATE (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_FLOWLABEL_MGR :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_FLOWLABEL_MGR (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_FLOWINFO_SEND :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_FLOWINFO_SEND (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_XFRM_POLICY :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_XFRM_POLICY (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_HDRINCL :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_HDRINCL (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_BLOCK_SOURCE :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option MCAST_BLOCK_SOURCE (%d), your linux program may see more multicast stuff than it wants " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_UNBLOCK_SOURCE :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option MCAST_UNBLOCK_SOURCE (%d), your linux program may not see all the multicast stuff it wants " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_JOIN_SOURCE_GROUP :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option MCAST_JOIN_SOURCE_GROUP (%d), your linux program is not able to join a multicast source group " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_LEAVE_SOURCE_GROUP :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option MCAST_LEAVE_SOURCE_GROUP (%d), your linux program is not able to leave a multicast source group -- but it was also not able to join one, so no issue " ,
opt ) ;
return ( - 2 ) ;
case LINUX_MCAST_MSFILTER :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option MCAST_MSFILTER (%d), your linux program can not manipulate the multicast filter, it may see more multicast data than it wants to see " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_ADDR_PREFERENCES :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_ADDR_PREFERENCES (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_MINHOPCOUNT :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_MINHOPCOUNT (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_TRANSPARENT :
/* IP_BINDANY or more? */
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_TRANSPARENT (%d), you can not enable transparent proxying in linux programs -- note, IP_FREEBIND is supported, no idea if the FreeBSD IP_BINDANY is equivalent to the Linux IP_TRANSPARENT or not, any info is welcome " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_UNICAST_IF :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_UNICAST_IF (%d) " ,
opt ) ;
return ( - 2 ) ;
case LINUX_IPV6_RECVFRAGSIZE :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported IPv6 socket option IPV6_RECVFRAGSIZE (%d) " ,
opt ) ;
return ( - 2 ) ;
/* unknown sockopts */
default :
return ( - 1 ) ;
2016-03-09 09:12:40 +00:00
}
}
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 :
2020-06-10 18:43:43 +00:00
case LINUX_SO_SNDBUFFORCE :
2000-08-26 05:12:16 +00:00
return ( SO_SNDBUF ) ;
case LINUX_SO_RCVBUF :
2020-06-10 18:43:43 +00:00
case LINUX_SO_RCVBUFFORCE :
2000-08-26 05:12:16 +00:00
return ( SO_RCVBUF ) ;
case LINUX_SO_KEEPALIVE :
return ( SO_KEEPALIVE ) ;
case LINUX_SO_OOBINLINE :
return ( SO_OOBINLINE ) ;
case LINUX_SO_LINGER :
return ( SO_LINGER ) ;
2020-06-11 12:25:49 +00:00
case LINUX_SO_REUSEPORT :
return ( SO_REUSEPORT_LB ) ;
2020-11-03 01:19:13 +00:00
case LINUX_SO_PASSCRED :
return ( LOCAL_CREDS_PERSISTENT ) ;
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 ) ;
2022-05-28 20:45:39 +00:00
case LINUX_SO_TIMESTAMPO :
case LINUX_SO_TIMESTAMPN :
2007-02-01 13:36:19 +00:00
return ( SO_TIMESTAMP ) ;
2022-05-28 20:46:05 +00:00
case LINUX_SO_TIMESTAMPNSO :
case LINUX_SO_TIMESTAMPNSN :
return ( SO_BINTIME ) ;
2007-02-01 13:36:19 +00:00
case LINUX_SO_ACCEPTCONN :
return ( SO_ACCEPTCONN ) ;
2020-06-28 18:56:32 +00:00
case LINUX_SO_PROTOCOL :
return ( SO_PROTOCOL ) ;
2022-04-11 20:31:28 +00:00
case LINUX_SO_DOMAIN :
return ( SO_DOMAIN ) ;
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 ) ;
2020-01-28 13:57:24 +00:00
case LINUX_TCP_CORK :
return ( TCP_NOPUSH ) ;
2013-01-23 21:44:48 +00:00
case LINUX_TCP_KEEPIDLE :
return ( TCP_KEEPIDLE ) ;
case LINUX_TCP_KEEPINTVL :
return ( TCP_KEEPINTVL ) ;
case LINUX_TCP_KEEPCNT :
return ( TCP_KEEPCNT ) ;
2021-10-17 12:19:05 +00:00
case LINUX_TCP_INFO :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported TCP socket option TCP_INFO (%d) " , opt ) ;
return ( - 2 ) ;
2013-01-23 21:44:48 +00:00
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 ( flags & LINUX_MSG_PROXY )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_PROXY (%d) not handled " ,
LINUX_MSG_PROXY ) ;
2000-12-19 00:24:25 +00:00
if ( flags & LINUX_MSG_FIN )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_FIN (%d) not handled " ,
LINUX_MSG_FIN ) ;
2000-12-19 00:24:25 +00:00
if ( flags & LINUX_MSG_SYN )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_SYN (%d) not handled " ,
LINUX_MSG_SYN ) ;
2000-12-19 00:24:25 +00:00
if ( flags & LINUX_MSG_CONFIRM )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_CONFIRM (%d) not handled " ,
LINUX_MSG_CONFIRM ) ;
2000-12-19 00:24:25 +00:00
if ( flags & LINUX_MSG_RST )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_RST (%d) not handled " ,
LINUX_MSG_RST ) ;
2000-12-19 00:24:25 +00:00
if ( flags & LINUX_MSG_ERRQUEUE )
2020-11-08 09:50:58 +00:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_ERRQUEUE (%d) not handled " ,
LINUX_MSG_ERRQUEUE ) ;
2016-03-27 08:10:20 +00:00
return ( ret_flags ) ;
2000-12-19 00:24:25 +00:00
}
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
2022-05-28 20:47:40 +00:00
bsd_to_linux_ip_cmsg_type ( int cmsg_type )
{
switch ( cmsg_type ) {
case IP_RECVORIGDSTADDR :
return ( LINUX_IP_RECVORIGDSTADDR ) ;
}
return ( - 1 ) ;
}
static int
bsd_to_linux_cmsg_type ( struct proc * p , int cmsg_type , int cmsg_level )
2008-11-29 17:14:06 +00:00
{
2022-05-28 20:45:39 +00:00
struct linux_pemuldata * pem ;
2022-05-28 20:47:40 +00:00
if ( cmsg_level = = IPPROTO_IP )
return ( bsd_to_linux_ip_cmsg_type ( cmsg_type ) ) ;
if ( cmsg_level ! = SOL_SOCKET )
return ( - 1 ) ;
2022-05-28 20:45:39 +00:00
pem = pem_find ( p ) ;
2008-11-29 17:14:06 +00:00
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 ) ;
2020-11-17 20:01:21 +00:00
case SCM_CREDS2 :
return ( LINUX_SCM_CREDENTIALS ) ;
2015-05-24 18:13:21 +00:00
case SCM_TIMESTAMP :
2022-05-28 20:45:39 +00:00
return ( pem - > so_timestamp ) ;
2022-05-28 20:46:05 +00:00
case SCM_BINTIME :
return ( pem - > so_timestampns ) ;
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 ) ;
}
2020-09-17 12:14:24 +00:00
static int
linux_copyout_sockaddr ( const struct sockaddr * sa , void * uaddr , size_t len )
{
struct l_sockaddr * lsa ;
int error ;
error = bsd_to_linux_sockaddr ( sa , & lsa , len ) ;
if ( error ! = 0 )
return ( error ) ;
2022-03-31 18:23:12 +00:00
2020-09-17 12:14:24 +00:00
error = copyout ( lsa , uaddr , len ) ;
2022-05-28 20:44:48 +00:00
free ( lsa , M_LINUX ) ;
2020-09-17 12:14:24 +00:00
return ( error ) ;
}
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 ;
2019-05-13 17:48:16 +00:00
int error , len ;
2003-11-09 17:04:04 +00:00
if ( mp - > msg_name ! = NULL ) {
2019-05-13 17:48:16 +00:00
len = mp - > msg_namelen ;
error = linux_to_bsd_sockaddr ( mp - > msg_name , & to , & len ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2003-11-09 17:04:04 +00:00
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 ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
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
}
2020-11-03 19:50:42 +00:00
static const char * linux_netlink_names [ ] = {
[ LINUX_NETLINK_ROUTE ] = " ROUTE " ,
[ LINUX_NETLINK_SOCK_DIAG ] = " SOCK_DIAG " ,
[ LINUX_NETLINK_NFLOG ] = " NFLOG " ,
[ LINUX_NETLINK_SELINUX ] = " SELINUX " ,
[ LINUX_NETLINK_AUDIT ] = " AUDIT " ,
[ LINUX_NETLINK_FIB_LOOKUP ] = " FIB_LOOKUP " ,
[ LINUX_NETLINK_NETFILTER ] = " NETFILTER " ,
[ LINUX_NETLINK_KOBJECT_UEVENT ] = " KOBJECT_UEVENT " ,
} ;
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
{
2017-01-30 12:57:22 +00:00
int domain , retval_socket , type ;
2000-08-26 05:12:16 +00:00
2017-01-30 12:57:22 +00:00
type = args - > type & LINUX_SOCK_TYPE_MASK ;
if ( type < 0 | | type > LINUX_SOCK_MAX )
2009-05-16 18:46:51 +00:00
return ( EINVAL ) ;
2015-05-24 18:06:12 +00:00
retval_socket = linux_set_socket_flags ( args - > type & ~ LINUX_SOCK_TYPE_MASK ,
2017-01-30 12:57:22 +00:00
& type ) ;
2015-05-24 18:06:12 +00:00
if ( retval_socket ! = 0 )
return ( retval_socket ) ;
2017-01-30 12:57:22 +00:00
domain = linux_to_bsd_domain ( args - > domain ) ;
2020-10-21 18:45:48 +00:00
if ( domain = = - 1 ) {
2020-11-03 19:50:42 +00:00
/* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */
type = args - > type & LINUX_SOCK_TYPE_MASK ;
2021-01-12 18:00:18 +00:00
if ( args - > domain = = LINUX_AF_NETLINK & &
args - > protocol = = LINUX_NETLINK_AUDIT ) {
; /* Do nothing, quietly. */
} else if ( args - > domain = = LINUX_AF_NETLINK ) {
2020-11-03 19:50:42 +00:00
const char * nl_name ;
if ( args - > protocol > = 0 & &
args - > protocol < nitems ( linux_netlink_names ) )
nl_name = linux_netlink_names [ args - > protocol ] ;
else
nl_name = NULL ;
if ( nl_name ! = NULL )
linux_msg ( curthread ,
" unsupported socket(AF_NETLINK, %d, "
" NETLINK_%s) " , type , nl_name ) ;
else
linux_msg ( curthread ,
" unsupported socket(AF_NETLINK, %d, %d) " ,
type , args - > protocol ) ;
} else {
linux_msg ( curthread , " unsupported socket domain %d, "
" type %d, protocol %d " , args - > domain , type ,
args - > protocol ) ;
2020-10-24 14:25:38 +00:00
}
2009-05-07 09:34:02 +00:00
return ( EAFNOSUPPORT ) ;
2020-10-21 18:45:48 +00:00
}
2000-08-26 05:12:16 +00:00
2017-01-30 12:57:22 +00:00
retval_socket = kern_socket ( td , domain , type , args - > protocol ) ;
2009-05-16 18:44:56 +00:00
if ( retval_socket )
return ( retval_socket ) ;
2017-01-30 12:57:22 +00:00
if ( type = = SOCK_RAW
& & ( args - > protocol = = IPPROTO_RAW | | args - > protocol = = 0 )
& & 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
*/
2017-01-30 12:57:22 +00:00
if ( 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 ;
2019-05-13 17:48:16 +00:00
error = linux_to_bsd_sockaddr ( PTRIN ( args - > name ) , & sa ,
& args - > namelen ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2003-02-03 17:43:20 +00:00
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 ) ;
2019-05-13 17:48:16 +00:00
/* XXX */
2008-09-09 13:01:14 +00:00
if ( error = = EADDRNOTAVAIL & & args - > namelen ! = sizeof ( struct sockaddr_in ) )
2018-02-05 17:29:12 +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
{
2001-03-01 21:44:40 +00:00
struct socket * so ;
2003-02-03 17:43:20 +00:00
struct sockaddr * sa ;
2017-01-06 04:38:38 +00:00
struct file * fp ;
2000-08-26 05:12:16 +00:00
int error ;
2019-05-13 17:48:16 +00:00
error = linux_to_bsd_sockaddr ( PTRIN ( args - > name ) , & sa ,
& args - > namelen ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2003-02-03 17:43:20 +00:00
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 .
*/
2022-09-07 15:41:55 +00:00
error = getsock ( td , args - > s , & cap_connect_rights , & fp ) ;
2017-01-06 04:38:38 +00:00
if ( error ! = 0 )
return ( error ) ;
error = EISCONN ;
so = fp - > f_data ;
2022-09-07 15:41:55 +00:00
if ( atomic_load_int ( & fp - > f_flag ) & FNONBLOCK ) {
2017-01-06 04:38:38 +00:00
SOCK_LOCK ( so ) ;
if ( so - > so_emuldata = = 0 )
error = so - > so_error ;
so - > so_emuldata = ( void * ) 1 ;
SOCK_UNLOCK ( so ) ;
1998-02-07 02:13:27 +00:00
}
2017-01-06 04:38:38 +00:00
fdrop ( fp , td ) ;
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
2017-01-30 12:57:22 +00:00
return ( kern_listen ( td , args - > s , args - > backlog ) ) ;
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
{
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
2020-07-01 10:37:08 +00:00
struct file * fp , * fp1 ;
2019-05-13 17:48:16 +00:00
int bflags , len ;
struct socket * so ;
2016-03-08 15:15:34 +00:00
int error , error1 ;
2009-06-01 20:44:58 +00:00
2019-05-13 17:48:16 +00:00
bflags = 0 ;
2020-07-01 10:37:08 +00:00
fp = NULL ;
sa = NULL ;
2019-05-13 17:48:16 +00:00
error = linux_set_socket_flags ( flags , & bflags ) ;
2015-05-24 18:06:12 +00:00
if ( error ! = 0 )
return ( error ) ;
2019-05-13 17:48:16 +00:00
if ( PTRIN ( addr ) = = NULL ) {
len = 0 ;
error = kern_accept4 ( td , s , NULL , NULL , bflags , NULL ) ;
} else {
error = copyin ( PTRIN ( namelen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
if ( len < 0 )
return ( EINVAL ) ;
error = kern_accept4 ( td , s , & sa , & len , bflags , & fp ) ;
}
2020-07-01 10:37:08 +00:00
/*
* Translate errno values into ones used by Linux .
*/
2017-02-18 10:01:17 +00:00
if ( error ! = 0 ) {
2019-05-13 17:48:16 +00:00
/*
* XXX . This is wrong , different sockaddr structures
* have different sizes .
*/
2020-07-01 10:37:08 +00:00
switch ( error ) {
case EFAULT :
if ( namelen ! = sizeof ( struct sockaddr_in ) )
error = EINVAL ;
break ;
case EINVAL :
2022-09-07 15:41:55 +00:00
error1 = getsock ( td , s , & cap_accept_rights , & fp1 ) ;
2019-05-13 17:48:16 +00:00
if ( error1 ! = 0 ) {
error = error1 ;
2020-07-01 10:37:08 +00:00
break ;
2016-03-08 15:55:43 +00:00
}
2020-07-01 10:37:08 +00:00
so = fp1 - > f_data ;
2019-05-13 17:48:16 +00:00
if ( so - > so_type = = SOCK_DGRAM )
error = EOPNOTSUPP ;
2020-07-01 10:37:08 +00:00
fdrop ( fp1 , td ) ;
break ;
2016-03-08 15:15:34 +00:00
}
2020-07-01 10:37:08 +00:00
return ( error ) ;
2019-05-13 17:48:16 +00:00
}
2020-07-01 10:37:08 +00:00
if ( len ! = 0 ) {
2020-09-17 12:14:24 +00:00
error = linux_copyout_sockaddr ( sa , PTRIN ( addr ) , len ) ;
2022-04-11 20:33:27 +00:00
if ( error = = 0 )
error = copyout ( & len , PTRIN ( namelen ) ,
sizeof ( len ) ) ;
2020-07-01 10:37:08 +00:00
if ( error ! = 0 ) {
fdclose ( td , fp , td - > td_retval [ 0 ] ) ;
td - > td_retval [ 0 ] = 0 ;
}
2009-06-01 20:44:58 +00:00
}
2020-07-01 10:37:08 +00:00
if ( fp ! = NULL )
fdrop ( fp , td ) ;
free ( sa , M_SONAME ) ;
2009-06-01 20:44:58 +00:00
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
{
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
int len , error ;
error = copyin ( PTRIN ( args - > namelen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
2000-08-26 05:12:16 +00:00
2019-05-13 17:48:16 +00:00
error = kern_getsockname ( td , args - > s , & sa , & len ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2003-02-03 17:43:20 +00:00
return ( error ) ;
2019-05-13 17:48:16 +00:00
2020-09-17 12:14:24 +00:00
if ( len ! = 0 )
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > addr ) , len ) ;
2019-05-13 17:48:16 +00:00
free ( sa , M_SONAME ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > namelen ) , sizeof ( len ) ) ;
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_getpeername ( struct thread * td , struct linux_getpeername_args * args )
1995-06-25 17:32:43 +00:00
{
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
int len , error ;
error = copyin ( PTRIN ( args - > namelen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
2019-05-13 18:14:20 +00:00
if ( len < 0 )
return ( EINVAL ) ;
2000-08-26 05:12:16 +00:00
2019-05-13 17:48:16 +00:00
error = kern_getpeername ( td , args - > s , & sa , & len ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2003-02-03 17:43:20 +00:00
return ( error ) ;
2019-05-13 17:48:16 +00:00
2020-09-17 12:14:24 +00:00
if ( len ! = 0 )
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > addr ) , len ) ;
2019-05-13 17:48:16 +00:00
free ( sa , M_SONAME ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > namelen ) , sizeof ( len ) ) ;
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_socketpair ( struct thread * td , struct linux_socketpair_args * args )
1995-06-25 17:32:43 +00:00
{
2020-02-10 13:24:14 +00:00
int domain , error , sv [ 2 ] , type ;
2000-08-26 05:12:16 +00:00
2020-02-10 13:24:14 +00:00
domain = linux_to_bsd_domain ( args - > domain ) ;
if ( domain ! = PF_LOCAL )
2009-05-07 03:23:22 +00:00
return ( EAFNOSUPPORT ) ;
2020-02-10 13:24:14 +00:00
type = args - > type & LINUX_SOCK_TYPE_MASK ;
if ( type < 0 | | type > LINUX_SOCK_MAX )
2009-05-31 12:16:31 +00:00
return ( EINVAL ) ;
2015-05-24 18:06:12 +00:00
error = linux_set_socket_flags ( args - > type & ~ LINUX_SOCK_TYPE_MASK ,
2020-02-10 13:24:14 +00:00
& type ) ;
2015-05-24 18:06:12 +00:00
if ( error ! = 0 )
return ( error ) ;
2020-02-10 13:24:14 +00:00
if ( args - > protocol ! = 0 & & args - > protocol ! = PF_UNIX ) {
2009-05-07 03:23:22 +00:00
/*
* 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 ) ;
2020-02-10 13:24:14 +00:00
}
error = kern_socketpair ( td , domain , type , 0 , sv ) ;
if ( error ! = 0 )
return ( error ) ;
error = copyout ( sv , PTRIN ( args - > rsv ) , 2 * sizeof ( int ) ) ;
if ( error ! = 0 ) {
( void ) kern_close ( td , sv [ 0 ] ) ;
( void ) kern_close ( td , sv [ 1 ] ) ;
}
return ( error ) ;
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 {
2017-02-18 07:21:50 +00:00
register_t s ;
register_t msg ;
register_t len ;
register_t 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 ;
2019-05-19 09:23:20 +00:00
struct file * fp ;
2022-09-07 15:41:55 +00:00
int error ;
2000-08-26 05:12:16 +00:00
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 ;
2021-02-05 17:24:23 +00:00
bsd_args . flags = linux_to_bsd_msg_flags ( args - > flags ) ;
2004-07-08 10:18:07 +00:00
bsd_args . to = NULL ;
bsd_args . tolen = 0 ;
2019-05-19 09:23:20 +00:00
error = sys_sendto ( td , & bsd_args ) ;
if ( error = = ENOTCONN ) {
/*
* Linux doesn ' t return ENOTCONN for non - blocking sockets .
* Instead it returns the EAGAIN .
*/
2022-09-07 15:41:55 +00:00
error = getsock ( td , args - > s , & cap_send_rights , & fp ) ;
2019-05-19 09:23:20 +00:00
if ( error = = 0 ) {
2022-09-07 15:41:55 +00:00
if ( atomic_load_int ( & fp - > f_flag ) & FNONBLOCK )
2019-05-19 09:23:20 +00:00
error = EAGAIN ;
fdrop ( fp , td ) ;
}
}
return ( error ) ;
1995-06-25 17:32:43 +00:00
}
2006-05-10 20:38:16 +00:00
struct linux_recv_args {
2017-02-18 07:21:50 +00:00
register_t s ;
register_t msg ;
register_t len ;
register_t 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 ;
2022-05-28 20:42:09 +00:00
struct socket * so ;
struct file * fp ;
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
2022-05-28 20:42:09 +00:00
bzero ( & msg , sizeof ( msg ) ) ;
2022-09-07 15:41:55 +00:00
error = getsock ( td , args - > s , & cap_send_connect_rights , & fp ) ;
2022-05-28 20:42:09 +00:00
if ( error ! = 0 )
return ( error ) ;
so = fp - > f_data ;
if ( ( so - > so_state & ( SS_ISCONNECTED | SS_ISCONNECTING ) ) = = 0 ) {
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 ;
2008-09-09 13:01:14 +00:00
aiov . iov_base = PTRIN ( args - > msg ) ;
aiov . iov_len = args - > len ;
2022-05-28 20:42:09 +00:00
fdrop ( fp , td ) ;
2016-03-27 08:10:20 +00:00
return ( linux_sendit ( td , args - > s , & msg , args - > flags , NULL ,
UIO_USERSPACE ) ) ;
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
{
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
2015-05-24 16:26:55 +00:00
struct msghdr msg ;
struct iovec aiov ;
2016-06-26 16:59:59 +00:00
int error , fromlen ;
2000-08-26 05:12:16 +00:00
2015-05-24 16:26:55 +00:00
if ( PTRIN ( args - > fromlen ) ! = NULL ) {
2016-06-26 16:59:59 +00:00
error = copyin ( PTRIN ( args - > fromlen ) , & fromlen ,
sizeof ( fromlen ) ) ;
2015-05-24 16:26:55 +00:00
if ( error ! = 0 )
return ( error ) ;
2016-06-26 16:59:59 +00:00
if ( fromlen < 0 )
return ( EINVAL ) ;
2022-04-11 20:32:28 +00:00
fromlen = min ( fromlen , SOCK_MAXADDRLEN ) ;
2019-05-13 17:48:16 +00:00
sa = malloc ( fromlen , M_SONAME , M_WAITOK ) ;
} else {
fromlen = 0 ;
sa = NULL ;
}
2015-05-24 16:26:55 +00:00
2019-05-13 17:48:16 +00:00
msg . msg_name = sa ;
msg . msg_namelen = fromlen ;
2015-05-24 16:26:55 +00:00
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 ) ;
2019-05-13 17:48:16 +00:00
error = kern_recvit ( td , args - > s , & msg , UIO_SYSSPACE , NULL ) ;
2015-05-24 16:26:55 +00:00
if ( error ! = 0 )
2019-05-21 18:03:58 +00:00
goto out ;
2015-05-24 16:26:55 +00:00
2022-04-11 20:29:45 +00:00
/*
* XXX . Seems that FreeBSD is different from Linux here . Linux
* fill source address if underlying protocol provides it , while
* FreeBSD fill it if underlying protocol is not connection - oriented .
* So , kern_recvit ( ) set msg . msg_namelen to 0 if protocol pr_flags
* does not contains PR_ADDR flag .
*/
if ( PTRIN ( args - > from ) ! = NULL & & msg . msg_namelen ! = 0 )
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > from ) ,
msg . msg_namelen ) ;
2015-05-24 16:26:55 +00:00
2019-05-13 17:48:16 +00:00
if ( error = = 0 & & PTRIN ( args - > fromlen ) ! = NULL )
2015-05-24 16:26:55 +00:00
error = copyout ( & msg . msg_namelen , PTRIN ( args - > fromlen ) ,
sizeof ( msg . msg_namelen ) ) ;
2019-05-21 18:03:58 +00:00
out :
2019-05-13 17:48:16 +00:00
free ( sa , M_SONAME ) ;
2015-05-24 16:26:55 +00:00
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 ;
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 ;
2020-06-12 14:31:19 +00:00
struct l_msghdr linux_msghdr ;
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 ;
2019-05-30 14:21:51 +00:00
struct socket * so ;
2011-03-26 11:05:53 +00:00
sa_family_t sa_family ;
2019-05-30 14:21:51 +00:00
struct file * fp ;
2008-11-29 17:14:06 +00:00
void * data ;
2018-11-19 15:31:54 +00:00
l_size_t len ;
2018-11-20 14:18:57 +00:00
l_size_t clen ;
2022-09-07 15:41:55 +00:00
int error ;
2003-02-03 17:43:20 +00:00
2020-06-12 14:31:19 +00:00
error = copyin ( msghdr , & linux_msghdr , sizeof ( linux_msghdr ) ) ;
2015-05-24 18:04:04 +00:00
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 .
*/
2020-06-12 14:31:19 +00:00
if ( PTRIN ( linux_msghdr . msg_control ) ! = NULL & &
linux_msghdr . msg_controllen = = 0 )
linux_msghdr . msg_control = PTROUT ( NULL ) ;
2011-03-26 11:05:53 +00:00
2020-06-12 14:31:19 +00:00
error = linux_to_bsd_msghdr ( & msg , & linux_msghdr ) ;
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 ;
2019-05-30 14:21:51 +00:00
error = kern_getsockname ( td , s , & sa , & datalen ) ;
if ( error ! = 0 )
goto bad ;
sa_family = sa - > sa_family ;
free ( sa , M_SONAME ) ;
if ( flags & LINUX_MSG_OOB ) {
error = EOPNOTSUPP ;
if ( sa_family = = AF_UNIX )
goto bad ;
2022-09-07 15:41:55 +00:00
error = getsock ( td , s , & cap_send_rights , & fp ) ;
2019-05-30 14:21:51 +00:00
if ( error ! = 0 )
goto bad ;
so = fp - > f_data ;
if ( so - > so_type ! = SOCK_STREAM )
error = EOPNOTSUPP ;
fdrop ( fp , td ) ;
2015-05-24 18:04:04 +00:00
if ( error ! = 0 )
2011-03-26 11:05:53 +00:00
goto bad ;
2019-05-30 14:21:51 +00:00
}
2020-06-12 14:31:19 +00:00
if ( linux_msghdr . msg_controllen > = sizeof ( struct l_cmsghdr ) ) {
2008-11-29 17:14:06 +00:00
error = ENOBUFS ;
2012-12-05 08:04:20 +00:00
control = m_get ( M_WAITOK , MT_CONTROL ) ;
2018-11-19 15:31:54 +00:00
MCLGET ( control , M_WAITOK ) ;
data = mtod ( control , void * ) ;
datalen = 0 ;
2008-11-29 17:14:06 +00:00
2020-06-12 14:31:19 +00:00
ptr_cmsg = PTRIN ( linux_msghdr . msg_control ) ;
clen = linux_msghdr . msg_controllen ;
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 ;
2018-11-20 14:18:57 +00:00
if ( linux_cmsg . cmsg_len < sizeof ( struct l_cmsghdr ) | |
linux_cmsg . cmsg_len > clen )
2008-11-29 17:14:06 +00:00
goto bad ;
2018-11-19 15:31:54 +00:00
if ( datalen + CMSG_HDRSZ > MCLBYTES )
goto bad ;
2008-11-29 17:14:06 +00:00
/*
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
*/
2018-11-19 15:31:54 +00:00
cmsg = data ;
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
2020-06-14 14:38:40 +00:00
| | cmsg - > cmsg_level ! = SOL_SOCKET ) {
linux_msg ( curthread ,
" unsupported sendmsg cmsg level %d type %d " ,
linux_cmsg . cmsg_level , linux_cmsg . cmsg_type ) ;
2011-03-26 11:05:53 +00:00
goto bad ;
2020-06-14 14:38:40 +00:00
}
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 )
2020-08-18 14:17:14 +00:00
goto next ;
2011-03-26 11:05:53 +00:00
2018-11-19 15:31:54 +00:00
if ( cmsg - > cmsg_type = = SCM_CREDS ) {
len = sizeof ( struct cmsgcred ) ;
if ( datalen + CMSG_SPACE ( len ) > MCLBYTES )
goto bad ;
2011-03-26 11:05:53 +00:00
/*
* The lower levels will fill in the structure
*/
2018-11-19 15:31:54 +00:00
memset ( CMSG_DATA ( data ) , 0 , len ) ;
} else {
len = linux_cmsg . cmsg_len - L_CMSG_HDRSZ ;
if ( datalen + CMSG_SPACE ( len ) < datalen | |
datalen + CMSG_SPACE ( len ) > MCLBYTES )
goto bad ;
error = copyin ( LINUX_CMSG_DATA ( ptr_cmsg ) ,
CMSG_DATA ( data ) , len ) ;
if ( error ! = 0 )
goto bad ;
2011-03-26 11:05:53 +00:00
}
2018-11-19 15:31:54 +00:00
cmsg - > cmsg_len = CMSG_LEN ( len ) ;
data = ( char * ) data + CMSG_SPACE ( len ) ;
datalen + = CMSG_SPACE ( len ) ;
2018-11-20 14:18:57 +00:00
2020-08-18 14:17:14 +00:00
next :
2018-11-20 14:18:57 +00:00
if ( clen < = LINUX_CMSG_ALIGN ( linux_cmsg . cmsg_len ) )
break ;
clen - = LINUX_CMSG_ALIGN ( linux_cmsg . cmsg_len ) ;
ptr_cmsg = ( struct l_cmsghdr * ) ( ( char * ) ptr_cmsg +
LINUX_CMSG_ALIGN ( linux_cmsg . cmsg_len ) ) ;
} while ( clen > = sizeof ( struct l_cmsghdr ) ) ;
2011-03-26 11:05:53 +00:00
2018-11-19 15:31:54 +00:00
control - > m_len = datalen ;
if ( datalen = = 0 ) {
2011-03-26 11:05:53 +00:00
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 ) ;
2016-01-17 19:28:13 +00:00
control = NULL ;
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 ) ;
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 ) ;
}
2022-05-28 20:44:02 +00:00
static int
recvmsg_scm_rights ( struct thread * td , l_uint flags , socklen_t * datalen ,
void * * data , void * * udata )
{
int i , fd , fds , * fdp ;
if ( flags & LINUX_MSG_CMSG_CLOEXEC ) {
fds = * datalen / sizeof ( int ) ;
fdp = * data ;
for ( i = 0 ; i < fds ; i + + ) {
fd = * fdp + + ;
( void ) kern_fcntl ( td , fd , F_SETFD , FD_CLOEXEC ) ;
}
}
return ( 0 ) ;
}
2022-05-28 20:46:05 +00:00
2022-05-28 20:44:02 +00:00
static int
recvmsg_scm_creds ( socklen_t * datalen , void * * data , void * * udata )
{
struct cmsgcred * cmcred ;
struct l_ucred lu ;
cmcred = * data ;
lu . pid = cmcred - > cmcred_pid ;
lu . uid = cmcred - > cmcred_uid ;
lu . gid = cmcred - > cmcred_gid ;
memmove ( * data , & lu , sizeof ( lu ) ) ;
* datalen = sizeof ( lu ) ;
return ( 0 ) ;
}
_Static_assert ( sizeof ( struct cmsgcred ) > = sizeof ( struct l_ucred ) ,
" scm_creds sizeof l_ucred " ) ;
static int
recvmsg_scm_creds2 ( socklen_t * datalen , void * * data , void * * udata )
{
struct sockcred2 * scred ;
struct l_ucred lu ;
scred = * data ;
lu . pid = scred - > sc_pid ;
lu . uid = scred - > sc_uid ;
lu . gid = scred - > sc_gid ;
memmove ( * data , & lu , sizeof ( lu ) ) ;
* datalen = sizeof ( lu ) ;
return ( 0 ) ;
}
_Static_assert ( sizeof ( struct sockcred2 ) > = sizeof ( struct l_ucred ) ,
" scm_creds2 sizeof l_ucred " ) ;
2022-05-28 20:45:39 +00:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2022-05-28 20:44:02 +00:00
static int
2022-05-28 20:45:39 +00:00
recvmsg_scm_timestamp ( l_int msg_type , socklen_t * datalen , void * * data ,
void * * udata )
2022-05-28 20:44:02 +00:00
{
2022-05-28 20:45:39 +00:00
l_sock_timeval ltv64 ;
l_timeval ltv ;
struct timeval * tv ;
socklen_t len ;
void * buf ;
2022-05-28 20:44:02 +00:00
if ( * datalen ! = sizeof ( struct timeval ) )
return ( EMSGSIZE ) ;
2022-05-28 20:45:39 +00:00
tv = * data ;
# if defined(COMPAT_LINUX32)
if ( msg_type = = LINUX_SCM_TIMESTAMPO & &
( tv - > tv_sec > INT_MAX | | tv - > tv_sec < INT_MIN ) )
return ( EOVERFLOW ) ;
# endif
if ( msg_type = = LINUX_SCM_TIMESTAMPN )
len = sizeof ( ltv64 ) ;
else
len = sizeof ( ltv ) ;
buf = malloc ( len , M_LINUX , M_WAITOK ) ;
if ( msg_type = = LINUX_SCM_TIMESTAMPN ) {
ltv64 . tv_sec = tv - > tv_sec ;
ltv64 . tv_usec = tv - > tv_usec ;
memmove ( buf , & ltv64 , len ) ;
} else {
ltv . tv_sec = tv - > tv_sec ;
ltv . tv_usec = tv - > tv_usec ;
memmove ( buf , & ltv , len ) ;
}
* data = * udata = buf ;
* datalen = len ;
2022-05-28 20:44:02 +00:00
return ( 0 ) ;
}
2022-05-28 20:45:39 +00:00
# else
_Static_assert ( sizeof ( struct timeval ) = = sizeof ( l_timeval ) ,
" scm_timestamp sizeof l_timeval " ) ;
# endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
2022-05-28 20:44:02 +00:00
2022-05-28 20:46:05 +00:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
static int
recvmsg_scm_timestampns ( l_int msg_type , socklen_t * datalen , void * * data ,
void * * udata )
{
struct l_timespec64 ts64 ;
struct l_timespec ts32 ;
struct timespec ts ;
socklen_t len ;
void * buf ;
if ( msg_type = = LINUX_SCM_TIMESTAMPNSO )
len = sizeof ( ts32 ) ;
else
len = sizeof ( ts64 ) ;
buf = malloc ( len , M_LINUX , M_WAITOK ) ;
bintime2timespec ( * data , & ts ) ;
if ( msg_type = = LINUX_SCM_TIMESTAMPNSO ) {
ts32 . tv_sec = ts . tv_sec ;
ts32 . tv_nsec = ts . tv_nsec ;
memmove ( buf , & ts32 , len ) ;
} else {
ts64 . tv_sec = ts . tv_sec ;
ts64 . tv_nsec = ts . tv_nsec ;
memmove ( buf , & ts64 , len ) ;
}
* data = * udata = buf ;
* datalen = len ;
return ( 0 ) ;
}
# else
static int
recvmsg_scm_timestampns ( l_int msg_type , socklen_t * datalen , void * * data ,
void * * udata )
{
struct timespec ts ;
bintime2timespec ( * data , & ts ) ;
memmove ( * data , & ts , sizeof ( struct timespec ) ) ;
* datalen = sizeof ( struct timespec ) ;
return ( 0 ) ;
}
_Static_assert ( sizeof ( struct bintime ) > = sizeof ( struct timespec ) ,
" scm_timestampns sizeof timespec " ) ;
# endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
2022-05-28 20:47:40 +00:00
static int
recvmsg_scm_ip_origdstaddr ( socklen_t * datalen , void * * data , void * * udata )
{
struct l_sockaddr * lsa ;
int error ;
error = bsd_to_linux_sockaddr ( * data , & lsa , * datalen ) ;
if ( error = = 0 ) {
* data = * udata = lsa ;
* datalen = sizeof ( * lsa ) ;
}
return ( error ) ;
}
2015-05-24 18:04:04 +00:00
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
{
2022-05-28 20:45:39 +00:00
struct proc * p = td - > td_proc ;
2008-11-29 17:14:06 +00:00
struct cmsghdr * cm ;
2022-05-28 20:46:22 +00:00
struct l_cmsghdr * lcm = NULL ;
2018-08-07 16:36:48 +00:00
socklen_t datalen , maxlen , outlen ;
2022-05-28 20:46:22 +00:00
struct l_msghdr l_msghdr ;
2008-11-29 17:14:06 +00:00
struct iovec * iov , * uiov ;
2022-05-28 20:48:45 +00:00
struct mbuf * m , * control = NULL ;
2008-11-29 17:14:06 +00:00
struct mbuf * * controlp ;
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
2008-11-29 17:14:06 +00:00
caddr_t outbuf ;
2022-05-28 20:44:02 +00:00
void * data , * udata ;
int error ;
2000-12-19 00:24:25 +00:00
2022-05-28 20:46:22 +00:00
error = copyin ( msghdr , & l_msghdr , sizeof ( l_msghdr ) ) ;
2015-05-24 18:04:04 +00:00
if ( error ! = 0 )
2008-11-29 17:14:06 +00:00
return ( error ) ;
2004-08-16 07:28:16 +00:00
2022-01-08 13:44:17 +00:00
/*
* Pass user - supplied recvmsg ( ) flags in msg_flags field ,
* following sys_recvmsg ( ) convention .
*/
2022-05-28 20:46:22 +00:00
l_msghdr . msg_flags = flags ;
2022-01-08 13:44:17 +00:00
2022-05-28 20:46:22 +00:00
error = linux_to_bsd_msghdr ( msg , & l_msghdr ) ;
2015-05-24 18:04:04 +00:00
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 ) ;
2020-07-05 10:57:28 +00:00
if ( msg - > msg_name ! = NULL & & msg - > msg_namelen > 0 ) {
msg - > msg_namelen = min ( msg - > msg_namelen , SOCK_MAXADDRLEN ) ;
2019-05-13 17:48:16 +00:00
sa = malloc ( msg - > msg_namelen , M_SONAME , M_WAITOK ) ;
msg - > msg_name = sa ;
2020-07-05 10:57:28 +00:00
} else {
2019-05-21 18:08:19 +00:00
sa = NULL ;
2020-07-05 10:57:28 +00:00
msg - > msg_name = NULL ;
}
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 ;
2019-05-13 17:48:16 +00:00
error = kern_recvit ( td , s , msg , UIO_SYSSPACE , controlp ) ;
2015-05-24 18:04:04 +00:00
msg - > msg_iov = uiov ;
if ( error ! = 0 )
2008-11-29 17:14:06 +00:00
goto bad ;
2020-07-05 10:57:28 +00:00
/*
* Note that kern_recvit ( ) updates msg - > msg_namelen .
*/
if ( msg - > msg_name ! = NULL & & msg - > msg_namelen > 0 ) {
2022-05-28 20:46:22 +00:00
msg - > msg_name = PTRIN ( l_msghdr . msg_name ) ;
2022-04-11 20:32:02 +00:00
error = linux_copyout_sockaddr ( sa , msg - > msg_name ,
msg - > msg_namelen ) ;
2015-05-24 18:04:04 +00:00
if ( error ! = 0 )
2008-11-29 17:14:06 +00:00
goto bad ;
}
2022-05-28 20:46:22 +00:00
error = bsd_to_linux_msghdr ( msg , & l_msghdr ) ;
2019-05-13 17:48:16 +00:00
if ( error ! = 0 )
goto bad ;
2022-05-28 20:46:22 +00:00
maxlen = l_msghdr . msg_controllen ;
l_msghdr . msg_controllen = 0 ;
if ( control = = NULL )
goto out ;
2011-03-26 11:05:53 +00:00
2022-05-28 20:46:22 +00:00
lcm = malloc ( L_CMSG_HDRSZ , M_LINUX , M_WAITOK | M_ZERO ) ;
msg - > msg_control = mtod ( control , struct cmsghdr * ) ;
msg - > msg_controllen = control - > m_len ;
outbuf = PTRIN ( l_msghdr . msg_control ) ;
outlen = 0 ;
2022-05-28 20:48:45 +00:00
for ( m = control ; m ! = NULL ; m = m - > m_next ) {
cm = mtod ( m , struct cmsghdr * ) ;
2022-05-28 20:47:40 +00:00
lcm - > cmsg_type = bsd_to_linux_cmsg_type ( p , cm - > cmsg_type ,
cm - > cmsg_level ) ;
2022-05-28 20:46:22 +00:00
lcm - > cmsg_level = bsd_to_linux_sockopt_level ( cm - > cmsg_level ) ;
2022-05-28 20:47:40 +00:00
data = CMSG_DATA ( cm ) ;
datalen = ( caddr_t ) cm + cm - > cmsg_len - ( caddr_t ) data ;
udata = NULL ;
error = 0 ;
/* Process non SOL_SOCKET types. */
if ( cm - > cmsg_level = = IPPROTO_IP & &
lcm - > cmsg_type = = LINUX_IP_ORIGDSTADDR ) {
error = recvmsg_scm_ip_origdstaddr ( & datalen , & data , & udata ) ;
goto cont ;
}
2022-05-28 20:46:22 +00:00
if ( lcm - > cmsg_type = = - 1 | |
cm - > cmsg_level ! = SOL_SOCKET ) {
2022-05-28 20:48:16 +00:00
LINUX_RATELIMIT_MSG_OPT2 (
2022-05-28 20:46:22 +00:00
" unsupported recvmsg cmsg level %d type %d " ,
cm - > cmsg_level , cm - > cmsg_type ) ;
error = EINVAL ;
goto bad ;
}
2015-05-24 18:13:21 +00:00
2020-11-17 20:01:21 +00:00
2022-05-28 20:46:22 +00:00
switch ( cm - > cmsg_type ) {
case SCM_RIGHTS :
error = recvmsg_scm_rights ( td , flags ,
& datalen , & data , & udata ) ;
break ;
case SCM_CREDS :
error = recvmsg_scm_creds ( & datalen ,
& data , & udata ) ;
break ;
case SCM_CREDS2 :
error = recvmsg_scm_creds2 ( & datalen ,
& data , & udata ) ;
break ;
case SCM_TIMESTAMP :
2022-05-28 20:45:39 +00:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2022-05-28 20:46:22 +00:00
error = recvmsg_scm_timestamp ( lcm - > cmsg_type ,
& datalen , & data , & udata ) ;
2022-05-28 20:45:39 +00:00
# endif
2022-05-28 20:46:22 +00:00
break ;
case SCM_BINTIME :
error = recvmsg_scm_timestampns ( lcm - > cmsg_type ,
& datalen , & data , & udata ) ;
break ;
}
2022-05-28 20:47:40 +00:00
cont :
2022-05-28 20:46:22 +00:00
if ( error ! = 0 )
goto bad ;
2011-03-26 11:05:53 +00:00
2022-05-28 20:46:22 +00:00
if ( outlen + LINUX_CMSG_LEN ( datalen ) > maxlen ) {
if ( outlen = = 0 ) {
error = EMSGSIZE ;
goto err ;
} else {
l_msghdr . msg_flags | = LINUX_MSG_CTRUNC ;
m_dispose_extcontrolm ( control ) ;
free ( udata , M_LINUX ) ;
goto out ;
2008-11-29 17:14:06 +00:00
}
2022-05-28 20:46:22 +00:00
}
2008-11-29 17:14:06 +00:00
2022-05-28 20:46:22 +00:00
lcm - > cmsg_len = LINUX_CMSG_LEN ( datalen ) ;
error = copyout ( lcm , outbuf , L_CMSG_HDRSZ ) ;
if ( error = = 0 ) {
outbuf + = L_CMSG_HDRSZ ;
error = copyout ( data , outbuf , datalen ) ;
2022-05-28 20:44:02 +00:00
if ( error = = 0 ) {
2022-05-28 20:46:22 +00:00
outbuf + = LINUX_CMSG_ALIGN ( datalen ) ;
outlen + = LINUX_CMSG_LEN ( datalen ) ;
2022-05-28 20:44:02 +00:00
}
2008-11-29 17:14:06 +00:00
}
2022-05-28 20:46:22 +00:00
err :
free ( udata , M_LINUX ) ;
if ( error ! = 0 )
goto bad ;
2008-11-29 17:14:06 +00:00
}
2022-05-28 20:46:22 +00:00
l_msghdr . msg_controllen = outlen ;
2008-11-29 17:14:06 +00:00
out :
2022-05-28 20:46:22 +00:00
error = copyout ( & l_msghdr , msghdr , sizeof ( l_msghdr ) ) ;
2008-11-29 17:14:06 +00:00
bad :
2018-08-07 16:36:48 +00:00
if ( control ! = NULL ) {
if ( error ! = 0 )
m_dispose_extcontrolm ( control ) ;
m_freem ( control ) ;
}
2008-11-29 17:14:06 +00:00
free ( iov , M_IOV ) ;
2022-05-28 20:46:22 +00:00
free ( lcm , M_LINUX ) ;
2019-05-21 18:08:19 +00:00
free ( sa , M_SONAME ) ;
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 ;
2022-05-28 20:29:12 +00:00
struct file * fp ;
int error ;
2015-05-24 18:04:04 +00:00
2022-09-07 15:41:55 +00:00
error = getsock ( td , args - > s , & cap_recv_rights , & fp ) ;
2022-05-28 20:29:12 +00:00
if ( error ! = 0 )
return ( error ) ;
fdrop ( fp , td ) ;
2015-05-24 18:04:04 +00:00
return ( linux_recvmsg_common ( td , args - > s , PTRIN ( args - > msg ) ,
args - > flags , & bsd_msg ) ) ;
}
2022-05-04 10:06:53 +00:00
static int
linux_recvmmsg_common ( struct thread * td , l_int s , struct l_mmsghdr * msg ,
l_uint vlen , l_uint flags , struct timespec * tts )
2015-05-24 18:04:04 +00:00
{
struct msghdr bsd_msg ;
2022-05-04 10:06:53 +00:00
struct timespec ts ;
2022-05-28 20:29:12 +00:00
struct file * fp ;
2015-05-24 18:04:04 +00:00
l_uint retval ;
int error , datagrams ;
2022-09-07 15:41:55 +00:00
error = getsock ( td , s , & cap_recv_rights , & fp ) ;
2022-05-28 20:29:12 +00:00
if ( error ! = 0 )
return ( error ) ;
2015-05-24 18:04:04 +00:00
datagrams = 0 ;
2022-05-04 10:06:53 +00:00
while ( datagrams < vlen ) {
error = linux_recvmsg_common ( td , s , & msg - > msg_hdr ,
flags & ~ LINUX_MSG_WAITFORONE , & bsd_msg ) ;
2015-05-24 18:04:04 +00:00
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 .
*/
2022-05-04 10:06:53 +00:00
if ( flags & LINUX_MSG_WAITFORONE )
flags | = LINUX_MSG_DONTWAIT ;
2015-05-24 18:04:04 +00:00
/*
* See BUGS section of recvmmsg ( 2 ) .
*/
2022-05-04 10:06:53 +00:00
if ( tts ) {
2015-05-24 18:04:04 +00:00
getnanotime ( & ts ) ;
2022-05-04 10:06:53 +00:00
timespecsub ( & ts , tts , & ts ) ;
2015-05-24 18:04:04 +00:00
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 ;
2022-05-28 20:29:12 +00:00
fdrop ( fp , td ) ;
2015-05-24 18:04:04 +00:00
return ( error ) ;
}
2022-05-04 10:06:53 +00:00
int
linux_recvmmsg ( struct thread * td , struct linux_recvmmsg_args * args )
{
struct timespec ts , tts , * ptts ;
int error ;
if ( args - > timeout ) {
2022-05-08 13:16:47 +00:00
error = linux_get_timespec ( & ts , args - > timeout ) ;
2022-05-04 10:06:53 +00:00
if ( error ! = 0 )
return ( error ) ;
getnanotime ( & tts ) ;
timespecadd ( & tts , & ts , & tts ) ;
ptts = & tts ;
}
else ptts = NULL ;
return ( linux_recvmmsg_common ( td , args - > s , PTRIN ( args - > msg ) ,
args - > vlen , args - > flags , ptts ) ) ;
}
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_recvmmsg_time64 ( struct thread * td , struct linux_recvmmsg_time64_args * args )
{
struct timespec ts , tts , * ptts ;
int error ;
if ( args - > timeout ) {
2022-05-08 13:16:47 +00:00
error = linux_get_timespec64 ( & ts , args - > timeout ) ;
2022-05-04 10:06:53 +00:00
if ( error ! = 0 )
return ( error ) ;
getnanotime ( & tts ) ;
timespecadd ( & tts , & ts , & tts ) ;
ptts = & tts ;
}
else ptts = NULL ;
return ( linux_recvmmsg_common ( td , args - > s , PTRIN ( args - > msg ) ,
args - > vlen , args - > flags , ptts ) ) ;
}
# endif
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
2017-01-30 12:57:22 +00:00
return ( kern_shutdown ( td , args - > s , args - > how ) ) ;
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
{
2022-05-28 20:45:39 +00:00
struct proc * p = td - > td_proc ;
struct linux_pemuldata * pem ;
2009-05-11 13:50:42 +00:00
l_timeval linux_tv ;
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
2009-05-11 13:50:42 +00:00
struct timeval tv ;
2019-05-13 17:48:16 +00:00
socklen_t len ;
2022-05-28 20:46:38 +00:00
int error , level , name , val ;
2000-08-26 05:12:16 +00:00
2020-01-14 11:33:07 +00:00
level = linux_to_bsd_sockopt_level ( args - > level ) ;
switch ( level ) {
2000-08-26 05:12:16 +00:00
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 ) {
2020-11-03 01:19:13 +00:00
case LOCAL_CREDS_PERSISTENT :
level = SOL_LOCAL ;
break ;
2009-05-11 13:50:42 +00:00
case SO_RCVTIMEO :
/* FALLTHROUGH */
case SO_SNDTIMEO :
error = copyin ( PTRIN ( args - > optval ) , & linux_tv ,
sizeof ( linux_tv ) ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2009-05-11 13:50:42 +00:00
return ( error ) ;
tv . tv_sec = linux_tv . tv_sec ;
tv . tv_usec = linux_tv . tv_usec ;
2020-01-14 11:33:07 +00:00
return ( kern_setsockopt ( td , args - > s , level ,
2009-05-11 13:50:42 +00:00
name , & tv , UIO_SYSSPACE , sizeof ( tv ) ) ) ;
/* NOTREACHED */
2022-05-28 20:45:39 +00:00
case SO_TIMESTAMP :
2022-05-28 20:46:38 +00:00
/* overwrite SO_BINTIME */
val = 0 ;
error = kern_setsockopt ( td , args - > s , level ,
SO_BINTIME , & val , UIO_SYSSPACE , sizeof ( val ) ) ;
if ( error ! = 0 )
return ( error ) ;
2022-05-28 20:45:39 +00:00
pem = pem_find ( p ) ;
pem - > so_timestamp = args - > optname ;
break ;
2022-05-28 20:46:05 +00:00
case SO_BINTIME :
2022-05-28 20:46:38 +00:00
/* overwrite SO_TIMESTAMP */
val = 0 ;
error = kern_setsockopt ( td , args - > s , level ,
SO_TIMESTAMP , & val , UIO_SYSSPACE , sizeof ( val ) ) ;
if ( error ! = 0 )
return ( error ) ;
2022-05-28 20:46:05 +00:00
pem = pem_find ( p ) ;
pem - > so_timestampns = args - > optname ;
break ;
2009-05-11 13:50:42 +00:00
default :
break ;
}
2000-08-26 05:12:16 +00:00
break ;
case IPPROTO_IP :
2020-01-28 13:51:53 +00:00
if ( args - > optname = = LINUX_IP_RECVERR & &
linux_ignore_ip_recverr ) {
/*
* XXX : This is a hack to unbreak DNS resolution
* with glibc 2.30 and above .
*/
return ( 0 ) ;
}
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 ;
2016-03-09 09:12:40 +00:00
case IPPROTO_IPV6 :
name = linux_to_bsd_ip6_sockopt ( args - > optname ) ;
break ;
2000-08-26 05:12:16 +00:00
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 ;
2022-08-26 14:34:15 +00:00
case SOL_NETLINK :
level = SOL_SOCKET ;
name = args - > optname ;
break ;
2000-08-26 05:12:16 +00:00
default :
name = - 1 ;
break ;
}
2020-11-08 09:50:58 +00:00
if ( name < 0 ) {
if ( name = = - 1 )
linux_msg ( curthread ,
" unsupported setsockopt level %d optname %d " ,
args - > level , args - > optname ) ;
2006-09-23 19:06:54 +00:00
return ( ENOPROTOOPT ) ;
2020-02-27 19:40:20 +00:00
}
2006-03-18 18:20:17 +00:00
if ( name = = IPV6_NEXTHOP ) {
2019-05-13 17:48:16 +00:00
len = args - > optlen ;
error = linux_to_bsd_sockaddr ( PTRIN ( args - > optval ) , & sa , & len ) ;
if ( error ! = 0 )
return ( error ) ;
2020-01-14 11:33:07 +00:00
error = kern_setsockopt ( td , args - > s , level ,
2019-05-13 17:48:16 +00:00
name , sa , UIO_SYSSPACE , len ) ;
free ( sa , M_SONAME ) ;
} else {
2020-01-14 11:33:07 +00:00
error = kern_setsockopt ( td , args - > s , level ,
name , PTRIN ( args - > optval ) , UIO_USERSPACE , args - > optlen ) ;
2019-05-13 17:48:16 +00:00
}
2006-03-18 18:20:17 +00:00
return ( error ) ;
1995-06-25 17:32:43 +00:00
}
2022-05-28 20:30:22 +00:00
static int
linux_sockopt_copyout ( struct thread * td , void * val , socklen_t len ,
struct linux_getsockopt_args * args )
{
int error ;
error = copyout ( val , PTRIN ( args - > optval ) , len ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > optlen ) , sizeof ( len ) ) ;
return ( error ) ;
}
2021-02-07 21:29:32 +00:00
static int
linux_getsockopt_so_peergroups ( struct thread * td ,
struct linux_getsockopt_args * args )
{
struct xucred xu ;
socklen_t xulen , len ;
int error , i ;
xulen = sizeof ( xu ) ;
error = kern_getsockopt ( td , args - > s , 0 ,
LOCAL_PEERCRED , & xu , UIO_SYSSPACE , & xulen ) ;
if ( error ! = 0 )
return ( error ) ;
len = xu . cr_ngroups * sizeof ( l_gid_t ) ;
if ( args - > optlen < len ) {
error = copyout ( & len , PTRIN ( args - > optlen ) , sizeof ( len ) ) ;
if ( error = = 0 )
error = ERANGE ;
return ( error ) ;
}
/*
* " - 1 " to skip the primary group .
*/
for ( i = 0 ; i < xu . cr_ngroups - 1 ; i + + ) {
error = copyout ( xu . cr_groups + i + 1 ,
( void * ) ( args - > optval + i * sizeof ( l_gid_t ) ) ,
sizeof ( l_gid_t ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
error = copyout ( & len , PTRIN ( args - > optlen ) , sizeof ( len ) ) ;
return ( error ) ;
}
2021-02-07 20:28:35 +00:00
static int
linux_getsockopt_so_peersec ( struct thread * td ,
struct linux_getsockopt_args * args )
{
socklen_t len ;
int error ;
len = sizeof ( SECURITY_CONTEXT_STRING ) ;
if ( args - > optlen < len ) {
error = copyout ( & len , PTRIN ( args - > optlen ) , sizeof ( len ) ) ;
if ( error = = 0 )
error = ERANGE ;
return ( error ) ;
}
2022-05-28 20:30:22 +00:00
return ( linux_sockopt_copyout ( td , SECURITY_CONTEXT_STRING ,
len , args ) ) ;
2021-02-07 20:28:35 +00:00
}
2022-05-28 20:31:06 +00:00
static int
linux_getsockopt_so_linger ( struct thread * td ,
struct linux_getsockopt_args * args )
{
struct linger ling ;
socklen_t len ;
int error ;
len = sizeof ( ling ) ;
error = kern_getsockopt ( td , args - > s , SOL_SOCKET ,
SO_LINGER , & ling , UIO_SYSSPACE , & len ) ;
if ( error ! = 0 )
return ( error ) ;
ling . l_onoff = ( ( ling . l_onoff & SO_LINGER ) ! = 0 ) ;
return ( linux_sockopt_copyout ( td , & ling , len , args ) ) ;
}
2022-05-28 20:30:22 +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
{
2009-05-11 13:50:42 +00:00
l_timeval linux_tv ;
struct timeval tv ;
2016-05-22 12:49:08 +00:00
socklen_t tv_len , xulen , len ;
2019-05-13 17:48:16 +00:00
struct sockaddr * sa ;
2009-05-16 18:42:18 +00:00
struct xucred xu ;
struct l_ucred lxu ;
2020-01-14 11:30:30 +00:00
int error , level , name , newval ;
2000-08-26 05:12:16 +00:00
2020-01-14 11:30:30 +00:00
level = linux_to_bsd_sockopt_level ( args - > level ) ;
switch ( level ) {
2000-08-26 05:12:16 +00:00
case SOL_SOCKET :
2021-02-07 21:29:32 +00:00
switch ( args - > optname ) {
case LINUX_SO_PEERGROUPS :
return ( linux_getsockopt_so_peergroups ( td , args ) ) ;
case LINUX_SO_PEERSEC :
2021-02-07 20:28:35 +00:00
return ( linux_getsockopt_so_peersec ( td , args ) ) ;
2021-02-07 21:29:32 +00:00
default :
break ;
}
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 ) {
2020-11-03 01:19:13 +00:00
case LOCAL_CREDS_PERSISTENT :
level = SOL_LOCAL ;
break ;
2009-05-11 13:50:42 +00:00
case SO_RCVTIMEO :
/* FALLTHROUGH */
case SO_SNDTIMEO :
tv_len = sizeof ( tv ) ;
2020-01-14 11:30:30 +00:00
error = kern_getsockopt ( td , args - > s , level ,
2009-05-11 13:50:42 +00:00
name , & tv , UIO_SYSSPACE , & tv_len ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2009-05-11 13:50:42 +00:00
return ( error ) ;
linux_tv . tv_sec = tv . tv_sec ;
linux_tv . tv_usec = tv . tv_usec ;
2022-05-28 20:30:22 +00:00
return ( linux_sockopt_copyout ( td , & linux_tv ,
sizeof ( linux_tv ) , args ) ) ;
2009-05-11 13:50:42 +00:00
/* NOTREACHED */
2009-05-16 18:42:18 +00:00
case LOCAL_PEERCRED :
2017-03-18 18:31:04 +00:00
if ( args - > optlen < sizeof ( lxu ) )
2009-05-16 18:42:18 +00:00
return ( EINVAL ) ;
2019-01-08 17:21:59 +00:00
/*
* LOCAL_PEERCRED is not served at the SOL_SOCKET level ,
* but by the Unix socket ' s level 0.
*/
2020-01-14 11:30:30 +00:00
level = 0 ;
2009-05-16 18:42:18 +00:00
xulen = sizeof ( xu ) ;
2020-01-14 11:30:30 +00:00
error = kern_getsockopt ( td , args - > s , level ,
2009-05-16 18:42:18 +00:00
name , & xu , UIO_SYSSPACE , & xulen ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2009-05-16 18:42:18 +00:00
return ( error ) ;
2019-05-30 14:24:26 +00:00
lxu . pid = xu . cr_pid ;
2009-05-16 18:42:18 +00:00
lxu . uid = xu . cr_uid ;
lxu . gid = xu . cr_gid ;
2022-05-28 20:30:22 +00:00
return ( linux_sockopt_copyout ( td , & lxu ,
sizeof ( lxu ) , args ) ) ;
2009-05-16 18:42:18 +00:00
/* NOTREACHED */
2016-05-22 12:49:08 +00:00
case SO_ERROR :
len = sizeof ( newval ) ;
2020-01-14 11:30:30 +00:00
error = kern_getsockopt ( td , args - > s , level ,
2016-05-22 12:49:08 +00:00
name , & newval , UIO_SYSSPACE , & len ) ;
2017-02-18 10:01:17 +00:00
if ( error ! = 0 )
2016-05-22 12:49:08 +00:00
return ( error ) ;
2020-10-27 12:49:40 +00:00
newval = - bsd_to_linux_errno ( newval ) ;
2022-05-28 20:30:22 +00:00
return ( linux_sockopt_copyout ( td , & newval ,
len , args ) ) ;
2016-05-22 12:49:08 +00:00
/* NOTREACHED */
2022-04-11 20:31:28 +00:00
case SO_DOMAIN :
len = sizeof ( newval ) ;
error = kern_getsockopt ( td , args - > s , level ,
name , & newval , UIO_SYSSPACE , & len ) ;
if ( error ! = 0 )
return ( error ) ;
newval = bsd_to_linux_domain ( newval ) ;
if ( newval = = - 1 )
return ( ENOPROTOOPT ) ;
2022-05-28 20:30:22 +00:00
return ( linux_sockopt_copyout ( td , & newval ,
len , args ) ) ;
2022-04-11 20:31:28 +00:00
/* NOTREACHED */
2022-05-28 20:31:06 +00:00
case SO_LINGER :
return ( linux_getsockopt_so_linger ( td , args ) ) ;
/* NOTREACHED */
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 ;
2016-03-09 09:12:40 +00:00
case IPPROTO_IPV6 :
name = linux_to_bsd_ip6_sockopt ( args - > optname ) ;
break ;
2000-08-26 05:12:16 +00:00
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 ;
}
2020-11-08 09:50:58 +00:00
if ( name < 0 ) {
if ( name = = - 1 )
linux_msg ( curthread ,
" unsupported getsockopt level %d optname %d " ,
args - > level , args - > optname ) ;
2000-08-26 05:12:16 +00:00
return ( EINVAL ) ;
2020-02-27 19:40:20 +00:00
}
2000-08-26 05:12:16 +00:00
2006-03-18 18:20:17 +00:00
if ( name = = IPV6_NEXTHOP ) {
2019-05-13 17:48:16 +00:00
error = copyin ( PTRIN ( args - > optlen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
sa = malloc ( len , M_SONAME , M_WAITOK ) ;
2020-01-14 11:30:30 +00:00
error = kern_getsockopt ( td , args - > s , level ,
2019-05-13 17:48:16 +00:00
name , sa , UIO_SYSSPACE , & len ) ;
if ( error ! = 0 )
goto out ;
2020-09-17 12:14:24 +00:00
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > optval ) , len ) ;
2019-05-13 17:48:16 +00:00
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > optlen ) ,
sizeof ( len ) ) ;
out :
free ( sa , M_SONAME ) ;
} else {
2020-01-14 11:30:30 +00:00
if ( args - > optval ) {
error = copyin ( PTRIN ( args - > optlen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
error = kern_getsockopt ( td , args - > s , level ,
name , PTRIN ( args - > optval ) , UIO_USERSPACE , & len ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > optlen ) ,
sizeof ( len ) ) ;
2019-05-13 17:48:16 +00:00
}
2006-03-18 18:20:17 +00:00
return ( error ) ;
1995-06-25 17:32:43 +00:00
}
2020-02-05 16:53:02 +00:00
static int
linux_sendfile_common ( struct thread * td , l_int out , l_int in ,
l_loff_t * offset , l_size_t count )
{
off_t bytes_read ;
int error ;
l_loff_t current_offset ;
struct file * fp ;
AUDIT_ARG_FD ( in ) ;
error = fget_read ( td , in , & cap_pread_rights , & fp ) ;
if ( error ! = 0 )
return ( error ) ;
if ( offset ! = NULL ) {
current_offset = * offset ;
} else {
error = ( fp - > f_ops - > fo_flags & DFLAG_SEEKABLE ) ! = 0 ?
fo_seek ( fp , 0 , SEEK_CUR , td ) : ESPIPE ;
if ( error ! = 0 )
goto drop ;
current_offset = td - > td_uretoff . tdu_off ;
}
bytes_read = 0 ;
/* Linux cannot have 0 count. */
if ( count < = 0 | | current_offset < 0 ) {
error = EINVAL ;
goto drop ;
}
error = fo_sendfile ( fp , out , NULL , NULL , current_offset , count ,
& bytes_read , 0 , td ) ;
if ( error ! = 0 )
goto drop ;
current_offset + = bytes_read ;
if ( offset ! = NULL ) {
* offset = current_offset ;
} else {
error = fo_seek ( fp , current_offset , SEEK_SET , td ) ;
if ( error ! = 0 )
goto drop ;
}
td - > td_retval [ 0 ] = ( ssize_t ) bytes_read ;
drop :
fdrop ( fp , td ) ;
2021-10-23 08:15:37 +00:00
if ( error = = ENOTSOCK )
error = EINVAL ;
2020-02-05 16:53:02 +00:00
return ( error ) ;
}
int
linux_sendfile ( struct thread * td , struct linux_sendfile_args * arg )
{
/*
* Differences between FreeBSD and Linux sendfile :
* - Linux doesn ' t send anything when count is 0 ( FreeBSD uses 0 to
* mean send the whole file . ) In linux_sendfile given fds are still
* checked for validity when the count is 0.
* - Linux can send to any fd whereas FreeBSD only supports sockets .
* The same restriction follows for linux_sendfile .
* - Linux doesn ' t have an equivalent for FreeBSD ' s flags and sf_hdtr .
* - Linux takes an offset pointer and updates it to the read location .
* FreeBSD takes in an offset and a ' bytes read ' parameter which is
* only filled if it isn ' t NULL . We use this parameter to update the
* offset pointer if it exists .
* - Linux sendfile returns bytes read on success while FreeBSD
* returns 0. We use the ' bytes read ' parameter to get this value .
*/
l_loff_t offset64 ;
l_long offset ;
int ret ;
int error ;
if ( arg - > offset ! = NULL ) {
error = copyin ( arg - > offset , & offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
offset64 = ( l_loff_t ) offset ;
}
ret = linux_sendfile_common ( td , arg - > out , arg - > in ,
arg - > offset ! = NULL ? & offset64 : NULL , arg - > count ) ;
if ( arg - > offset ! = NULL ) {
# if defined(__i386__) || defined(__arm__) || \
( defined ( __amd64__ ) & & defined ( COMPAT_LINUX32 ) )
if ( offset64 > INT32_MAX )
return ( EOVERFLOW ) ;
# endif
offset = ( l_long ) offset64 ;
error = copyout ( & offset , arg - > offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
return ( ret ) ;
}
# if defined(__i386__) || defined(__arm__) || \
( defined ( __amd64__ ) & & defined ( COMPAT_LINUX32 ) )
int
linux_sendfile64 ( struct thread * td , struct linux_sendfile64_args * arg )
{
l_loff_t offset ;
int ret ;
int error ;
if ( arg - > offset ! = NULL ) {
error = copyin ( arg - > offset , & offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
ret = linux_sendfile_common ( td , arg - > out , arg - > in ,
arg - > offset ! = NULL ? & offset : NULL , arg - > count ) ;
if ( arg - > offset ! = NULL ) {
error = copyout ( & offset , arg - > offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
return ( ret ) ;
}
2015-05-24 15:43:53 +00:00
2009-05-19 09:10:53 +00:00
/* Argument list sizes for linux_socketcall */
2017-02-12 15:22:50 +00:00
static const unsigned char lxs_args_cnt [ ] = {
0 /* unused*/ , 3 /* socket */ ,
3 /* bind */ , 3 /* connect */ ,
2 /* listen */ , 3 /* accept */ ,
3 /* getsockname */ , 3 /* getpeername */ ,
4 /* socketpair */ , 4 /* send */ ,
4 /* recv */ , 6 /* sendto */ ,
6 /* recvfrom */ , 2 /* shutdown */ ,
5 /* setsockopt */ , 5 /* getsockopt */ ,
3 /* sendmsg */ , 3 /* recvmsg */ ,
4 /* accept4 */ , 5 /* recvmmsg */ ,
2020-02-05 16:53:02 +00:00
4 /* sendmmsg */ , 4 /* sendfile */
2009-05-19 09:10:53 +00:00
} ;
2017-02-12 15:22:50 +00:00
# define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1)
# define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong))
2009-05-19 09:10:53 +00:00
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 ] ;
2017-02-12 15:22:50 +00:00
# if defined(__amd64__) && defined(COMPAT_LINUX32)
register_t l_args [ 6 ] ;
# endif
2009-05-19 09:10:53 +00:00
void * arg ;
int error ;
2017-02-12 15:22:50 +00:00
if ( args - > what < LINUX_SOCKET | | args - > what > LINUX_ARGS_CNT )
2009-05-19 09:10:53 +00:00
return ( EINVAL ) ;
2017-02-12 15:22:50 +00:00
error = copyin ( PTRIN ( args - > args ) , a , LINUX_ARG_SIZE ( args - > what ) ) ;
if ( error ! = 0 )
2009-05-19 09:10:53 +00:00
return ( error ) ;
2000-08-26 05:12:16 +00:00
2017-02-12 15:22:50 +00:00
# if defined(__amd64__) && defined(COMPAT_LINUX32)
for ( int i = 0 ; i < lxs_args_cnt [ args - > what ] ; + + i )
l_args [ i ] = a [ i ] ;
arg = l_args ;
# else
2009-05-19 09:10:53 +00:00
arg = a ;
2017-02-12 15:22:50 +00:00
# endif
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 ) ) ;
2020-02-05 16:53:02 +00:00
case LINUX_SENDFILE :
return ( linux_sendfile ( td , arg ) ) ;
2000-08-26 05:12:16 +00:00
}
1998-12-30 21:20:00 +00:00
2020-06-12 14:31:19 +00:00
linux_msg ( td , " socket type %d not implemented " , args - > what ) ;
2000-08-26 05:12:16 +00:00
return ( ENOSYS ) ;
1995-06-25 17:32:43 +00:00
}
2020-02-05 16:53:02 +00:00
# endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */