1995-06-25 13:32:43 -04:00
/*-
2023-05-10 11:40:58 -04:00
* SPDX - License - Identifier : BSD - 2 - Clause
2017-11-27 10:13:23 -05:00
*
2012-01-15 08:23:18 -05:00
* Copyright ( c ) 1995 Søren Schmidt
1995-06-25 13:32:43 -04: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 10:00:14 -05:00
* notice , this list of conditions and the following disclaimer .
1995-06-25 13:32:43 -04: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 10:00:14 -05: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 13:32:43 -04:00
*/
2003-02-03 12:43:20 -05:00
# include "opt_inet6.h"
1997-12-16 12:40:42 -05:00
1995-06-25 13:32:43 -04:00
# include <sys/param.h>
2014-03-16 06:55:57 -04:00
# include <sys/capsicum.h>
2020-07-01 06:37:08 -04:00
# include <sys/filedesc.h>
2003-04-29 09:36:06 -04:00
# include <sys/limits.h>
2003-02-03 12:43:20 -05:00
# include <sys/malloc.h>
2003-11-09 12:04:04 -05:00
# include <sys/mbuf.h>
2023-02-14 09:46:32 -05:00
# include <sys/proc.h>
2023-08-17 15:57:17 -04:00
# include <sys/protosw.h>
1995-06-25 13:32:43 -04:00
# include <sys/socket.h>
2001-03-01 16:44:40 -05:00
# include <sys/socketvar.h>
2003-02-03 12:43:20 -05:00
# include <sys/syscallsubr.h>
2023-02-14 09:46:32 -05:00
# include <sys/sysproto.h>
2023-08-17 15:57:17 -04:00
# include <sys/vnode.h>
2007-02-01 08:36:19 -05:00
# include <sys/un.h>
2020-02-05 11:53:02 -05:00
# include <sys/unistd.h>
# include <security/audit/audit.h>
1995-11-22 02:43:53 -05:00
2008-12-02 16:37:28 -05:00
# include <net/if.h>
2013-10-26 14:18:50 -04:00
# include <net/vnet.h>
1995-06-25 13:32:43 -04:00
# include <netinet/in.h>
1997-12-13 22:17:54 -05:00
# include <netinet/ip.h>
2013-01-23 16:44:48 -05:00
# include <netinet/tcp.h>
2003-02-03 12:43:20 -05:00
# ifdef INET6
# include <netinet/ip6.h>
# include <netinet6/ip6_var.h>
# endif
1995-06-25 13:32:43 -04:00
2005-01-13 23:44:56 -05:00
# ifdef COMPAT_LINUX32
2023-08-20 03:36:32 -04:00
# include <compat/freebsd32/freebsd32_util.h>
2004-08-16 03:28:16 -04:00
# include <machine/../linux32/linux.h>
# include <machine/../linux32/linux32_proto.h>
2005-01-13 23:44:56 -05:00
# else
# include <machine/../linux/linux.h>
# include <machine/../linux/linux_proto.h>
2004-08-16 03:28:16 -04:00
# endif
2019-05-13 13:48:16 -04:00
# include <compat/linux/linux_common.h>
2022-05-28 16:45:39 -04:00
# include <compat/linux/linux_emul.h>
2015-05-24 12:31:44 -04:00
# include <compat/linux/linux_file.h>
2020-01-28 08:51:53 -05:00
# include <compat/linux/linux_mib.h>
2000-12-18 19:24:25 -05:00
# include <compat/linux/linux_socket.h>
2023-02-14 09:46:33 -05:00
# include <compat/linux/linux_time.h>
2000-08-21 21:51:54 -04:00
# include <compat/linux/linux_util.h>
1995-06-25 13:32:43 -04:00
2023-03-04 04:11:38 -05:00
_Static_assert ( offsetof ( struct l_ifreq , ifr_ifru ) = =
offsetof ( struct ifreq , ifr_ifru ) ,
" Linux ifreq members names should be equal to FreeeBSD " ) ;
_Static_assert ( offsetof ( struct l_ifreq , ifr_index ) = =
offsetof ( struct ifreq , ifr_index ) ,
" Linux ifreq members names should be equal to FreeeBSD " ) ;
_Static_assert ( offsetof ( struct l_ifreq , ifr_name ) = =
offsetof ( struct ifreq , ifr_name ) ,
" Linux ifreq members names should be equal to FreeeBSD " ) ;
2021-02-07 15:28:35 -05:00
# define SECURITY_CONTEXT_STRING "unconfined"
2015-05-24 14:04:04 -04: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 14:06:12 -04:00
static int linux_set_socket_flags ( int , int * ) ;
2003-02-03 12:43:20 -05:00
2022-08-26 10:34:15 -04:00
# define SOL_NETLINK 270
1995-06-25 13:32:43 -04:00
static int
linux_to_bsd_sockopt_level ( int level )
{
2000-08-26 01:12:16 -04:00
2020-06-12 10:23:10 -04:00
if ( level = = LINUX_SOL_SOCKET )
2000-08-26 01:12:16 -04:00
return ( SOL_SOCKET ) ;
2020-06-12 10:23:10 -04:00
/* Remaining values are RFC-defined protocol numbers. */
2000-08-26 01:12:16 -04:00
return ( level ) ;
1995-06-25 13:32:43 -04:00
}
2003-10-11 11:08:32 -04:00
static int
bsd_to_linux_sockopt_level ( int level )
{
2020-06-12 10:23:10 -04:00
if ( level = = SOL_SOCKET )
2003-10-11 11:08:32 -04:00
return ( LINUX_SOL_SOCKET ) ;
return ( level ) ;
}
2000-08-26 01:12:16 -04:00
static int
linux_to_bsd_ip_sockopt ( int opt )
1995-06-25 13:32:43 -04:00
{
2000-08-26 01:12:16 -04:00
switch ( opt ) {
2020-11-08 04:50:58 -05:00
/* known and translated sockopts */
2000-08-26 01:12:16 -04:00
case LINUX_IP_TOS :
return ( IP_TOS ) ;
case LINUX_IP_TTL :
return ( IP_TTL ) ;
2020-11-08 04:50:58 -05:00
case LINUX_IP_HDRINCL :
return ( IP_HDRINCL ) ;
2000-08-26 01:12:16 -04:00
case LINUX_IP_OPTIONS :
return ( IP_OPTIONS ) ;
2020-11-08 04:50:58 -05: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 01:12:16 -04: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 04:50:58 -05: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 16:47:40 -04:00
case LINUX_IP_RECVORIGDSTADDR :
return ( IP_RECVORIGDSTADDR ) ;
2020-11-08 04:50:58 -05: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 01:12:16 -04:00
}
1995-06-25 13:32:43 -04:00
}
2016-03-09 04:12:40 -05:00
static int
linux_to_bsd_ip6_sockopt ( int opt )
{
switch ( opt ) {
2020-11-08 04:50:58 -05: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 04:12:40 -05: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 04:50:58 -05: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 04:12:40 -05:00
case LINUX_IPV6_RECVPKTINFO :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVPKTINFO " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVPKTINFO ) ;
case LINUX_IPV6_PKTINFO :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_PKTINFO " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_PKTINFO ) ;
case LINUX_IPV6_RECVHOPLIMIT :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVHOPLIMIT " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVHOPLIMIT ) ;
case LINUX_IPV6_HOPLIMIT :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_HOPLIMIT " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_HOPLIMIT ) ;
case LINUX_IPV6_RECVHOPOPTS :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVHOPOPTS " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVHOPOPTS ) ;
case LINUX_IPV6_HOPOPTS :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_HOPOPTS " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_HOPOPTS ) ;
case LINUX_IPV6_RTHDRDSTOPTS :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RTHDRDSTOPTS " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RTHDRDSTOPTS ) ;
case LINUX_IPV6_RECVRTHDR :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVRTHDR " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVRTHDR ) ;
case LINUX_IPV6_RTHDR :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RTHDR " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RTHDR ) ;
case LINUX_IPV6_RECVDSTOPTS :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVDSTOPTS " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVDSTOPTS ) ;
case LINUX_IPV6_DSTOPTS :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_DSTOPTS " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_DSTOPTS ) ;
case LINUX_IPV6_RECVPATHMTU :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_RECVPATHMTU " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_RECVPATHMTU ) ;
case LINUX_IPV6_PATHMTU :
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_NOTTESTED ( " IPv6 socket option IPV6_PATHMTU " ) ;
2016-03-09 04:12:40 -05:00
return ( IPV6_PATHMTU ) ;
2020-11-08 04:50:58 -05: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 04:12:40 -05:00
}
}
1995-06-25 13:32:43 -04:00
static int
linux_to_bsd_so_sockopt ( int opt )
{
2000-08-26 01:12:16 -04: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 14:43:43 -04:00
case LINUX_SO_SNDBUFFORCE :
2000-08-26 01:12:16 -04:00
return ( SO_SNDBUF ) ;
case LINUX_SO_RCVBUF :
2020-06-10 14:43:43 -04:00
case LINUX_SO_RCVBUFFORCE :
2000-08-26 01:12:16 -04: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 08:25:49 -04:00
case LINUX_SO_REUSEPORT :
return ( SO_REUSEPORT_LB ) ;
2020-11-02 20:19:13 -05:00
case LINUX_SO_PASSCRED :
return ( LOCAL_CREDS_PERSISTENT ) ;
2007-02-01 08:36:19 -05: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 16:45:39 -04:00
case LINUX_SO_TIMESTAMPO :
case LINUX_SO_TIMESTAMPN :
2007-02-01 08:36:19 -05:00
return ( SO_TIMESTAMP ) ;
2022-05-28 16:46:05 -04:00
case LINUX_SO_TIMESTAMPNSO :
case LINUX_SO_TIMESTAMPNSN :
return ( SO_BINTIME ) ;
2007-02-01 08:36:19 -05:00
case LINUX_SO_ACCEPTCONN :
return ( SO_ACCEPTCONN ) ;
2020-06-28 14:56:32 -04:00
case LINUX_SO_PROTOCOL :
return ( SO_PROTOCOL ) ;
2022-04-11 16:31:28 -04:00
case LINUX_SO_DOMAIN :
return ( SO_DOMAIN ) ;
2000-08-26 01:12:16 -04:00
}
return ( - 1 ) ;
1995-06-25 13:32:43 -04:00
}
2013-01-23 16:44:48 -05: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 08:57:24 -05:00
case LINUX_TCP_CORK :
return ( TCP_NOPUSH ) ;
2013-01-23 16:44:48 -05: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 08:19:05 -04:00
case LINUX_TCP_INFO :
LINUX_RATELIMIT_MSG_OPT1 (
" unsupported TCP socket option TCP_INFO (%d) " , opt ) ;
return ( - 2 ) ;
2013-01-23 16:44:48 -05:00
case LINUX_TCP_MD5SIG :
return ( TCP_MD5SIG ) ;
}
return ( - 1 ) ;
}
2000-12-18 19:24:25 -05: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 11:11:41 -05:00
if ( flags & LINUX_MSG_NOSIGNAL )
ret_flags | = MSG_NOSIGNAL ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_PROXY )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_PROXY (%d) not handled " ,
LINUX_MSG_PROXY ) ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_FIN )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_FIN (%d) not handled " ,
LINUX_MSG_FIN ) ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_SYN )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_SYN (%d) not handled " ,
LINUX_MSG_SYN ) ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_CONFIRM )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_CONFIRM (%d) not handled " ,
LINUX_MSG_CONFIRM ) ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_RST )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_RST (%d) not handled " ,
LINUX_MSG_RST ) ;
2000-12-18 19:24:25 -05:00
if ( flags & LINUX_MSG_ERRQUEUE )
2020-11-08 04:50:58 -05:00
LINUX_RATELIMIT_MSG_OPT1 ( " socket message flag MSG_ERRQUEUE (%d) not handled " ,
LINUX_MSG_ERRQUEUE ) ;
2016-03-27 04:10:20 -04:00
return ( ret_flags ) ;
2000-12-18 19:24:25 -05:00
}
2008-11-29 12:14:06 -05:00
static int
linux_to_bsd_cmsg_type ( int cmsg_type )
{
switch ( cmsg_type ) {
case LINUX_SCM_RIGHTS :
return ( SCM_RIGHTS ) ;
2011-03-26 07:05:53 -04:00
case LINUX_SCM_CREDENTIALS :
return ( SCM_CREDS ) ;
2008-11-29 12:14:06 -05:00
}
return ( - 1 ) ;
}
static int
2022-05-28 16:47:40 -04: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 12:14:06 -05:00
{
2022-05-28 16:45:39 -04:00
struct linux_pemuldata * pem ;
2022-05-28 16:47:40 -04: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 16:45:39 -04:00
pem = pem_find ( p ) ;
2008-11-29 12:14:06 -05:00
switch ( cmsg_type ) {
case SCM_RIGHTS :
return ( LINUX_SCM_RIGHTS ) ;
2011-03-26 07:05:53 -04:00
case SCM_CREDS :
return ( LINUX_SCM_CREDENTIALS ) ;
2020-11-17 15:01:21 -05:00
case SCM_CREDS2 :
return ( LINUX_SCM_CREDENTIALS ) ;
2015-05-24 14:13:21 -04:00
case SCM_TIMESTAMP :
2022-05-28 16:45:39 -04:00
return ( pem - > so_timestamp ) ;
2022-05-28 16:46:05 -04:00
case SCM_BINTIME :
return ( pem - > so_timestampns ) ;
2008-11-29 12:14:06 -05: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 07:05:53 -04: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 12:14:06 -05: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 07:05:53 -04: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 12:14:06 -05:00
/* msg_flags skipped */
return ( 0 ) ;
}
2009-05-31 08:04:01 -04:00
static int
2015-05-24 14:06:12 -04:00
linux_set_socket_flags ( int lflags , int * flags )
2009-05-31 08:04:01 -04:00
{
2015-05-24 14:06:12 -04: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 08:04:01 -04:00
return ( 0 ) ;
}
2020-09-17 08:14:24 -04: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 14:23:12 -04:00
2020-09-17 08:14:24 -04:00
error = copyout ( lsa , uaddr , len ) ;
2022-05-28 16:44:48 -04:00
free ( lsa , M_LINUX ) ;
2020-09-17 08:14:24 -04:00
return ( error ) ;
}
2003-11-09 12:04:04 -05:00
static int
2005-01-30 02:20:36 -05:00
linux_sendit ( struct thread * td , int s , struct msghdr * mp , int flags ,
2008-11-29 12:14:06 -05:00
struct mbuf * control , enum uio_seg segflg )
2003-11-09 12:04:04 -05:00
{
struct sockaddr * to ;
2019-05-13 13:48:16 -04:00
int error , len ;
2003-11-09 12:04:04 -05:00
if ( mp - > msg_name ! = NULL ) {
2019-05-13 13:48:16 -04:00
len = mp - > msg_namelen ;
error = linux_to_bsd_sockaddr ( mp - > msg_name , & to , & len ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2003-11-09 12:04:04 -05:00
return ( error ) ;
mp - > msg_name = to ;
} else
to = NULL ;
2005-01-30 02:20:36 -05:00
error = kern_sendit ( td , s , mp , linux_to_bsd_msg_flags ( flags ) , control ,
segflg ) ;
2003-11-09 12:04:04 -05:00
if ( to )
2008-10-23 11:53:51 -04:00
free ( to , M_SONAME ) ;
2003-11-09 12:04:04 -05:00
return ( error ) ;
}
2000-08-26 01:12:16 -04:00
/* Return 0 if IP_HDRINCL is set for the given socket. */
1997-12-13 22:17:54 -05:00
static int
2004-07-17 17:06:36 -04:00
linux_check_hdrincl ( struct thread * td , int s )
1997-12-13 22:17:54 -05:00
{
2015-01-01 15:53:38 -05:00
int error , optval ;
socklen_t size_val ;
2000-08-26 01:12:16 -04:00
2004-07-17 17:06:36 -04:00
size_val = sizeof ( optval ) ;
error = kern_getsockopt ( td , s , IPPROTO_IP , IP_HDRINCL ,
& optval , UIO_SYSSPACE , & size_val ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2000-08-26 01:12:16 -04:00
return ( error ) ;
return ( optval = = 0 ) ;
1997-12-13 22:17:54 -05:00
}
/*
* Updated sendto ( ) when IP_HDRINCL is set :
* tweak endian - dependent fields in the IP packet .
*/
static int
2004-07-18 00:09:40 -04:00
linux_sendto_hdrincl ( struct thread * td , struct linux_sendto_args * linux_args )
1997-12-13 22:17:54 -05: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 02:20:36 -05:00
* It should include all the fields we modify ( ip_len and ip_off ) .
1997-12-13 22:17:54 -05:00
*/
# define linux_ip_copysize 8
2000-08-26 01:12:16 -04:00
struct ip * packet ;
2003-11-09 12:04:04 -05:00
struct msghdr msg ;
2005-01-30 02:20:36 -05:00
struct iovec aiov [ 1 ] ;
2000-08-26 01:12:16 -04:00
int error ;
2005-03-23 03:28:00 -05: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 01:12:16 -04:00
return ( EINVAL ) ;
2015-05-24 12:14:41 -04:00
packet = ( struct ip * ) malloc ( linux_args - > len , M_LINUX , M_WAITOK ) ;
2000-08-26 01:12:16 -04:00
2005-01-30 02:20:36 -05:00
/* Make kernel copy of the packet to be sent */
2004-08-16 03:28:16 -04:00
if ( ( error = copyin ( PTRIN ( linux_args - > msg ) , packet ,
2005-01-30 02:20:36 -05:00
linux_args - > len ) ) )
goto goout ;
2000-08-26 01:12:16 -04:00
/* Convert fields from Linux to BSD raw IP socket format */
2003-11-09 12:04:04 -05:00
packet - > ip_len = linux_args - > len ;
2000-08-26 01:12:16 -04:00
packet - > ip_off = ntohs ( packet - > ip_off ) ;
/* Prepare the msghdr and iovec structures describing the new packet */
2004-08-16 03:28:16 -04:00
msg . msg_name = PTRIN ( linux_args - > to ) ;
2003-11-09 12:04:04 -05:00
msg . msg_namelen = linux_args - > tolen ;
msg . msg_iov = aiov ;
2005-01-30 02:20:36 -05:00
msg . msg_iovlen = 1 ;
2003-11-09 12:04:04 -05:00
msg . msg_control = NULL ;
msg . msg_flags = 0 ;
aiov [ 0 ] . iov_base = ( char * ) packet ;
2005-01-30 02:20:36 -05:00
aiov [ 0 ] . iov_len = linux_args - > len ;
error = linux_sendit ( td , linux_args - > s , & msg , linux_args - > flags ,
2008-11-29 12:14:06 -05:00
NULL , UIO_SYSSPACE ) ;
2005-01-30 02:20:36 -05:00
goout :
2015-05-24 12:14:41 -04:00
free ( packet , M_LINUX ) ;
2003-11-09 12:04:04 -05:00
return ( error ) ;
1997-12-13 22:17:54 -05:00
}
2020-11-03 14:50:42 -05: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 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_socket ( struct thread * td , struct linux_socket_args * args )
1995-06-25 13:32:43 -04:00
{
2017-01-30 07:57:22 -05:00
int domain , retval_socket , type ;
2000-08-26 01:12:16 -04:00
2017-01-30 07:57:22 -05:00
type = args - > type & LINUX_SOCK_TYPE_MASK ;
if ( type < 0 | | type > LINUX_SOCK_MAX )
2009-05-16 14:46:51 -04:00
return ( EINVAL ) ;
2015-05-24 14:06:12 -04:00
retval_socket = linux_set_socket_flags ( args - > type & ~ LINUX_SOCK_TYPE_MASK ,
2017-01-30 07:57:22 -05:00
& type ) ;
2015-05-24 14:06:12 -04:00
if ( retval_socket ! = 0 )
return ( retval_socket ) ;
2017-01-30 07:57:22 -05:00
domain = linux_to_bsd_domain ( args - > domain ) ;
2020-10-21 14:45:48 -04:00
if ( domain = = - 1 ) {
2020-11-03 14:50:42 -05:00
/* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */
type = args - > type & LINUX_SOCK_TYPE_MASK ;
2021-01-12 13:00:18 -05: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 14:50:42 -05: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 10:25:38 -04:00
}
2009-05-07 05:34:02 -04:00
return ( EAFNOSUPPORT ) ;
2020-10-21 14:45:48 -04:00
}
2000-08-26 01:12:16 -04:00
2017-01-30 07:57:22 -05:00
retval_socket = kern_socket ( td , domain , type , args - > protocol ) ;
2009-05-16 14:44:56 -04:00
if ( retval_socket )
return ( retval_socket ) ;
2017-01-30 07:57:22 -05:00
if ( type = = SOCK_RAW
& & ( args - > protocol = = IPPROTO_RAW | | args - > protocol = = 0 )
& & domain = = PF_INET ) {
2000-08-26 01:12:16 -04:00
/* It's a raw IP socket: set the IP_HDRINCL option. */
2004-07-17 17:06:36 -04: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 01:12:16 -04:00
}
2003-02-03 12:43:20 -05:00
# ifdef INET6
/*
2009-10-25 05:58:56 -04: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 12:43:20 -05:00
*/
2017-01-30 07:57:22 -05:00
if ( domain = = PF_INET6 ) {
2004-07-17 17:06:36 -04:00
int v6only ;
v6only = 0 ;
2003-02-03 12:43:20 -05:00
/* We ignore any error returned by setsockopt() */
2004-07-17 17:06:36 -04:00
kern_setsockopt ( td , td - > td_retval [ 0 ] , IPPROTO_IPV6 , IPV6_V6ONLY ,
& v6only , UIO_SYSSPACE , sizeof ( v6only ) ) ;
2003-02-03 12:43:20 -05:00
}
# endif
1997-12-13 22:17:54 -05:00
2000-08-26 01:12:16 -04:00
return ( retval_socket ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_bind ( struct thread * td , struct linux_bind_args * args )
1995-06-25 13:32:43 -04:00
{
2003-02-03 12:43:20 -05:00
struct sockaddr * sa ;
2000-08-26 01:12:16 -04:00
int error ;
2019-05-13 13:48:16 -04:00
error = linux_to_bsd_sockaddr ( PTRIN ( args - > name ) , & sa ,
& args - > namelen ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2014-11-13 13:01:51 -05:00
error = kern_bindat ( td , AT_FDCWD , args - > s , sa ) ;
2006-07-19 14:28:52 -04:00
free ( sa , M_SONAME ) ;
2019-05-13 13:48:16 -04:00
/* XXX */
2008-09-09 09:01:14 -04:00
if ( error = = EADDRNOTAVAIL & & args - > namelen ! = sizeof ( struct sockaddr_in ) )
2018-02-05 12:29:12 -05:00
return ( EINVAL ) ;
2006-07-19 14:28:52 -04:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2000-11-15 20:05:53 -05:00
int
2001-09-12 04:38:13 -04:00
linux_connect ( struct thread * td , struct linux_connect_args * args )
1995-06-25 13:32:43 -04:00
{
2001-03-01 16:44:40 -05:00
struct socket * so ;
2003-02-03 12:43:20 -05:00
struct sockaddr * sa ;
2017-01-05 23:38:38 -05:00
struct file * fp ;
2000-08-26 01:12:16 -04:00
int error ;
2019-05-13 13:48:16 -04:00
error = linux_to_bsd_sockaddr ( PTRIN ( args - > name ) , & sa ,
& args - > namelen ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2014-11-13 13:01:51 -05:00
error = kern_connectat ( td , AT_FDCWD , args - > s , sa ) ;
2006-07-19 14:28:52 -04:00
free ( sa , M_SONAME ) ;
2001-03-01 16:44:40 -05:00
if ( error ! = EISCONN )
return ( error ) ;
2000-08-26 01:12:16 -04:00
2001-03-01 16:44:40 -05: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 11:41:55 -04:00
error = getsock ( td , args - > s , & cap_connect_rights , & fp ) ;
2017-01-05 23:38:38 -05:00
if ( error ! = 0 )
return ( error ) ;
error = EISCONN ;
so = fp - > f_data ;
2022-09-07 11:41:55 -04:00
if ( atomic_load_int ( & fp - > f_flag ) & FNONBLOCK ) {
2017-01-05 23:38:38 -05:00
SOCK_LOCK ( so ) ;
if ( so - > so_emuldata = = 0 )
error = so - > so_error ;
so - > so_emuldata = ( void * ) 1 ;
SOCK_UNLOCK ( so ) ;
1998-02-06 21:13:27 -05:00
}
2017-01-05 23:38:38 -05:00
fdrop ( fp , td ) ;
2000-08-26 01:12:16 -04:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_listen ( struct thread * td , struct linux_listen_args * args )
1995-06-25 13:32:43 -04:00
{
2000-08-26 01:12:16 -04:00
2017-01-30 07:57:22 -05:00
return ( kern_listen ( td , args - > s , args - > backlog ) ) ;
1995-06-25 13:32:43 -04:00
}
2006-05-10 16:38:16 -04:00
static int
2009-06-01 16:42:27 -04:00
linux_accept_common ( struct thread * td , int s , l_uintptr_t addr ,
2009-06-01 16:54:41 -04:00
l_uintptr_t namelen , int flags )
1995-06-25 13:32:43 -04:00
{
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
2020-07-01 06:37:08 -04:00
struct file * fp , * fp1 ;
2019-05-13 13:48:16 -04:00
int bflags , len ;
struct socket * so ;
2016-03-08 10:15:34 -05:00
int error , error1 ;
2009-06-01 16:44:58 -04:00
2019-05-13 13:48:16 -04:00
bflags = 0 ;
2020-07-01 06:37:08 -04:00
fp = NULL ;
sa = NULL ;
2019-05-13 13:48:16 -04:00
error = linux_set_socket_flags ( flags , & bflags ) ;
2015-05-24 14:06:12 -04:00
if ( error ! = 0 )
return ( error ) ;
2019-05-13 13:48:16 -04: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 06:37:08 -04:00
/*
* Translate errno values into ones used by Linux .
*/
2017-02-18 05:01:17 -05:00
if ( error ! = 0 ) {
2019-05-13 13:48:16 -04:00
/*
* XXX . This is wrong , different sockaddr structures
* have different sizes .
*/
2020-07-01 06:37:08 -04:00
switch ( error ) {
case EFAULT :
if ( namelen ! = sizeof ( struct sockaddr_in ) )
error = EINVAL ;
break ;
case EINVAL :
2022-09-07 11:41:55 -04:00
error1 = getsock ( td , s , & cap_accept_rights , & fp1 ) ;
2019-05-13 13:48:16 -04:00
if ( error1 ! = 0 ) {
error = error1 ;
2020-07-01 06:37:08 -04:00
break ;
2016-03-08 10:55:43 -05:00
}
2020-07-01 06:37:08 -04:00
so = fp1 - > f_data ;
2019-05-13 13:48:16 -04:00
if ( so - > so_type = = SOCK_DGRAM )
error = EOPNOTSUPP ;
2020-07-01 06:37:08 -04:00
fdrop ( fp1 , td ) ;
break ;
2016-03-08 10:15:34 -05:00
}
2020-07-01 06:37:08 -04:00
return ( error ) ;
2019-05-13 13:48:16 -04:00
}
2020-07-01 06:37:08 -04:00
if ( len ! = 0 ) {
2020-09-17 08:14:24 -04:00
error = linux_copyout_sockaddr ( sa , PTRIN ( addr ) , len ) ;
2022-04-11 16:33:27 -04:00
if ( error = = 0 )
error = copyout ( & len , PTRIN ( namelen ) ,
sizeof ( len ) ) ;
2020-07-01 06:37:08 -04:00
if ( error ! = 0 ) {
fdclose ( td , fp , td - > td_retval [ 0 ] ) ;
td - > td_retval [ 0 ] = 0 ;
}
2009-06-01 16:44:58 -04:00
}
2020-07-01 06:37:08 -04:00
if ( fp ! = NULL )
fdrop ( fp , td ) ;
free ( sa , M_SONAME ) ;
2009-06-01 16:44:58 -04:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2009-06-01 16:42:27 -04:00
linux_accept ( struct thread * td , struct linux_accept_args * args )
{
return ( linux_accept_common ( td , args - > s , args - > addr ,
2009-06-01 16:54:41 -04:00
args - > namelen , 0 ) ) ;
2009-06-01 16:42:27 -04:00
}
2015-05-24 11:41:27 -04:00
int
2009-06-01 16:48:39 -04: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 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_getsockname ( struct thread * td , struct linux_getsockname_args * args )
1995-06-25 13:32:43 -04:00
{
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
int len , error ;
error = copyin ( PTRIN ( args - > namelen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
2000-08-26 01:12:16 -04:00
2019-05-13 13:48:16 -04:00
error = kern_getsockname ( td , args - > s , & sa , & len ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2019-05-13 13:48:16 -04:00
2020-09-17 08:14:24 -04:00
if ( len ! = 0 )
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > addr ) , len ) ;
2019-05-13 13:48:16 -04:00
free ( sa , M_SONAME ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > namelen ) , sizeof ( len ) ) ;
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_getpeername ( struct thread * td , struct linux_getpeername_args * args )
1995-06-25 13:32:43 -04:00
{
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
int len , error ;
error = copyin ( PTRIN ( args - > namelen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
2019-05-13 14:14:20 -04:00
if ( len < 0 )
return ( EINVAL ) ;
2000-08-26 01:12:16 -04:00
2019-05-13 13:48:16 -04:00
error = kern_getpeername ( td , args - > s , & sa , & len ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2019-05-13 13:48:16 -04:00
2020-09-17 08:14:24 -04:00
if ( len ! = 0 )
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > addr ) , len ) ;
2019-05-13 13:48:16 -04:00
free ( sa , M_SONAME ) ;
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > namelen ) , sizeof ( len ) ) ;
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_socketpair ( struct thread * td , struct linux_socketpair_args * args )
1995-06-25 13:32:43 -04:00
{
2020-02-10 08:24:14 -05:00
int domain , error , sv [ 2 ] , type ;
2000-08-26 01:12:16 -04:00
2020-02-10 08:24:14 -05:00
domain = linux_to_bsd_domain ( args - > domain ) ;
if ( domain ! = PF_LOCAL )
2009-05-06 23:23:22 -04:00
return ( EAFNOSUPPORT ) ;
2020-02-10 08:24:14 -05:00
type = args - > type & LINUX_SOCK_TYPE_MASK ;
if ( type < 0 | | type > LINUX_SOCK_MAX )
2009-05-31 08:16:31 -04:00
return ( EINVAL ) ;
2015-05-24 14:06:12 -04:00
error = linux_set_socket_flags ( args - > type & ~ LINUX_SOCK_TYPE_MASK ,
2020-02-10 08:24:14 -05:00
& type ) ;
2015-05-24 14:06:12 -04:00
if ( error ! = 0 )
return ( error ) ;
2020-02-10 08:24:14 -05:00
if ( args - > protocol ! = 0 & & args - > protocol ! = PF_UNIX ) {
2009-05-06 23:23:22 -04: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 08:24:14 -05: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 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2006-05-10 16:38:16 -04:00
struct linux_send_args {
2017-02-18 02:21:50 -05:00
register_t s ;
register_t msg ;
register_t len ;
register_t flags ;
1995-06-25 13:32:43 -04:00
} ;
2006-05-10 16:38:16 -04:00
static int
2001-09-12 04:38:13 -04:00
linux_send ( struct thread * td , struct linux_send_args * args )
1995-06-25 13:32:43 -04:00
{
2004-07-08 06:18:07 -04:00
struct sendto_args /* {
2002-09-24 03:03:01 -04:00
int s ;
2000-08-26 01:12:16 -04:00
caddr_t buf ;
2002-09-24 03:03:01 -04:00
int len ;
2000-08-26 01:12:16 -04:00
int flags ;
2004-07-08 06:18:07 -04:00
caddr_t to ;
int tolen ;
2000-08-26 01:12:16 -04:00
} */ bsd_args ;
2019-05-19 05:23:20 -04:00
struct file * fp ;
2022-09-07 11:41:55 -04:00
int error ;
2000-08-26 01:12:16 -04:00
2008-09-09 09:01:14 -04:00
bsd_args . s = args - > s ;
bsd_args . buf = ( caddr_t ) PTRIN ( args - > msg ) ;
bsd_args . len = args - > len ;
2021-02-05 12:24:23 -05:00
bsd_args . flags = linux_to_bsd_msg_flags ( args - > flags ) ;
2004-07-08 06:18:07 -04:00
bsd_args . to = NULL ;
bsd_args . tolen = 0 ;
2019-05-19 05:23:20 -04: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 11:41:55 -04:00
error = getsock ( td , args - > s , & cap_send_rights , & fp ) ;
2019-05-19 05:23:20 -04:00
if ( error = = 0 ) {
2022-09-07 11:41:55 -04:00
if ( atomic_load_int ( & fp - > f_flag ) & FNONBLOCK )
2019-05-19 05:23:20 -04:00
error = EAGAIN ;
fdrop ( fp , td ) ;
}
}
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2006-05-10 16:38:16 -04:00
struct linux_recv_args {
2017-02-18 02:21:50 -05:00
register_t s ;
register_t msg ;
register_t len ;
register_t flags ;
1995-06-25 13:32:43 -04:00
} ;
2006-05-10 16:38:16 -04:00
static int
2001-09-12 04:38:13 -04:00
linux_recv ( struct thread * td , struct linux_recv_args * args )
1995-06-25 13:32:43 -04:00
{
2004-07-08 06:18:07 -04:00
struct recvfrom_args /* {
2000-08-26 01:12:16 -04:00
int s ;
caddr_t buf ;
int len ;
int flags ;
2004-07-08 06:18:07 -04:00
struct sockaddr * from ;
socklen_t fromlenaddr ;
2000-08-26 01:12:16 -04:00
} */ bsd_args ;
2008-09-09 09:01:14 -04:00
bsd_args . s = args - > s ;
bsd_args . buf = ( caddr_t ) PTRIN ( args - > msg ) ;
bsd_args . len = args - > len ;
2009-05-11 09:42:40 -04:00
bsd_args . flags = linux_to_bsd_msg_flags ( args - > flags ) ;
2004-07-08 06:18:07 -04:00
bsd_args . from = NULL ;
bsd_args . fromlenaddr = 0 ;
2011-09-16 09:58:51 -04:00
return ( sys_recvfrom ( td , & bsd_args ) ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
# endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1995-06-25 13:32:43 -04:00
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_sendto ( struct thread * td , struct linux_sendto_args * args )
1995-06-25 13:32:43 -04:00
{
2003-11-09 12:04:04 -05:00
struct msghdr msg ;
struct iovec aiov ;
2022-05-28 16:42:09 -04:00
struct socket * so ;
struct file * fp ;
int error ;
2000-08-26 01:12:16 -04:00
2008-09-09 09:01:14 -04:00
if ( linux_check_hdrincl ( td , args - > s ) = = 0 )
2000-08-26 01:12:16 -04:00
/* IP_HDRINCL set, tweak the packet before sending */
2008-09-09 09:01:14 -04:00
return ( linux_sendto_hdrincl ( td , args ) ) ;
2003-11-09 12:04:04 -05:00
2022-05-28 16:42:09 -04:00
bzero ( & msg , sizeof ( msg ) ) ;
2022-09-07 11:41:55 -04:00
error = getsock ( td , args - > s , & cap_send_connect_rights , & fp ) ;
2022-05-28 16:42:09 -04: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 12:04:04 -05:00
msg . msg_iov = & aiov ;
msg . msg_iovlen = 1 ;
2008-09-09 09:01:14 -04:00
aiov . iov_base = PTRIN ( args - > msg ) ;
aiov . iov_len = args - > len ;
2022-05-28 16:42:09 -04:00
fdrop ( fp , td ) ;
2016-03-27 04:10:20 -04:00
return ( linux_sendit ( td , args - > s , & msg , args - > flags , NULL ,
UIO_USERSPACE ) ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_recvfrom ( struct thread * td , struct linux_recvfrom_args * args )
1995-06-25 13:32:43 -04:00
{
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
2015-05-24 12:26:55 -04:00
struct msghdr msg ;
struct iovec aiov ;
2016-06-26 12:59:59 -04:00
int error , fromlen ;
2000-08-26 01:12:16 -04:00
2015-05-24 12:26:55 -04:00
if ( PTRIN ( args - > fromlen ) ! = NULL ) {
2016-06-26 12:59:59 -04:00
error = copyin ( PTRIN ( args - > fromlen ) , & fromlen ,
sizeof ( fromlen ) ) ;
2015-05-24 12:26:55 -04:00
if ( error ! = 0 )
return ( error ) ;
2016-06-26 12:59:59 -04:00
if ( fromlen < 0 )
return ( EINVAL ) ;
2022-04-11 16:32:28 -04:00
fromlen = min ( fromlen , SOCK_MAXADDRLEN ) ;
2019-05-13 13:48:16 -04:00
sa = malloc ( fromlen , M_SONAME , M_WAITOK ) ;
} else {
fromlen = 0 ;
sa = NULL ;
}
2015-05-24 12:26:55 -04:00
2019-05-13 13:48:16 -04:00
msg . msg_name = sa ;
msg . msg_namelen = fromlen ;
2015-05-24 12:26:55 -04: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 13:48:16 -04:00
error = kern_recvit ( td , args - > s , & msg , UIO_SYSSPACE , NULL ) ;
2015-05-24 12:26:55 -04:00
if ( error ! = 0 )
2019-05-21 14:03:58 -04:00
goto out ;
2015-05-24 12:26:55 -04:00
2022-04-11 16:29:45 -04: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 12:26:55 -04:00
2019-05-13 13:48:16 -04:00
if ( error = = 0 & & PTRIN ( args - > fromlen ) ! = NULL )
2015-05-24 12:26:55 -04:00
error = copyout ( & msg . msg_namelen , PTRIN ( args - > fromlen ) ,
sizeof ( msg . msg_namelen ) ) ;
2019-05-21 14:03:58 -04:00
out :
2019-05-13 13:48:16 -04:00
free ( sa , M_SONAME ) ;
2015-05-24 12:26:55 -04:00
return ( error ) ;
2003-02-03 12:43:20 -05:00
}
2015-05-24 14:04:04 -04:00
static int
linux_sendmsg_common ( struct thread * td , l_int s , struct l_msghdr * msghdr ,
l_uint flags )
2003-02-03 12:43:20 -05:00
{
2008-11-29 12:14:06 -05:00
struct cmsghdr * cmsg ;
struct mbuf * control ;
2003-02-03 12:43:20 -05:00
struct msghdr msg ;
2008-11-29 12:14:06 -05:00
struct l_cmsghdr linux_cmsg ;
struct l_cmsghdr * ptr_cmsg ;
2020-06-12 10:31:19 -04:00
struct l_msghdr linux_msghdr ;
2004-07-10 11:42:16 -04:00
struct iovec * iov ;
2008-11-29 12:14:06 -05:00
socklen_t datalen ;
2011-03-26 07:05:53 -04:00
struct sockaddr * sa ;
2019-05-30 10:21:51 -04:00
struct socket * so ;
2011-03-26 07:05:53 -04:00
sa_family_t sa_family ;
2019-05-30 10:21:51 -04:00
struct file * fp ;
2008-11-29 12:14:06 -05:00
void * data ;
2018-11-19 10:31:54 -05:00
l_size_t len ;
2018-11-20 09:18:57 -05:00
l_size_t clen ;
2022-09-07 11:41:55 -04:00
int error ;
2003-02-03 12:43:20 -05:00
2020-06-12 10:31:19 -04:00
error = copyin ( msghdr , & linux_msghdr , sizeof ( linux_msghdr ) ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2007-04-14 06:35:09 -04: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 10:31:19 -04:00
if ( PTRIN ( linux_msghdr . msg_control ) ! = NULL & &
linux_msghdr . msg_controllen = = 0 )
linux_msghdr . msg_control = PTROUT ( NULL ) ;
2011-03-26 07:05:53 -04:00
2020-06-12 10:31:19 -04:00
error = linux_to_bsd_msghdr ( & msg , & linux_msghdr ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2011-03-26 07:05:53 -04:00
return ( error ) ;
2008-11-29 12:14:06 -05:00
# ifdef COMPAT_LINUX32
2023-08-20 03:36:32 -04:00
error = freebsd32_copyiniov ( PTRIN ( msg . msg_iov ) , msg . msg_iovlen ,
2008-11-29 12:14:06 -05:00
& iov , EMSGSIZE ) ;
# else
2004-07-10 11:42:16 -04:00
error = copyiniov ( msg . msg_iov , msg . msg_iovlen , & iov , EMSGSIZE ) ;
2008-11-29 12:14:06 -05:00
# endif
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2004-07-10 11:42:16 -04:00
return ( error ) ;
2008-11-29 12:14:06 -05:00
2011-03-26 07:05:53 -04:00
control = NULL ;
2019-05-30 10:21:51 -04: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 11:41:55 -04:00
error = getsock ( td , s , & cap_send_rights , & fp ) ;
2019-05-30 10:21:51 -04:00
if ( error ! = 0 )
goto bad ;
so = fp - > f_data ;
if ( so - > so_type ! = SOCK_STREAM )
error = EOPNOTSUPP ;
fdrop ( fp , td ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2011-03-26 07:05:53 -04:00
goto bad ;
2019-05-30 10:21:51 -04:00
}
2020-06-12 10:31:19 -04:00
if ( linux_msghdr . msg_controllen > = sizeof ( struct l_cmsghdr ) ) {
2008-11-29 12:14:06 -05:00
error = ENOBUFS ;
2012-12-05 03:04:20 -05:00
control = m_get ( M_WAITOK , MT_CONTROL ) ;
2018-11-19 10:31:54 -05:00
MCLGET ( control , M_WAITOK ) ;
data = mtod ( control , void * ) ;
datalen = 0 ;
2008-11-29 12:14:06 -05:00
2020-06-12 10:31:19 -04:00
ptr_cmsg = PTRIN ( linux_msghdr . msg_control ) ;
clen = linux_msghdr . msg_controllen ;
2008-11-29 12:14:06 -05:00
do {
error = copyin ( ptr_cmsg , & linux_cmsg ,
sizeof ( struct l_cmsghdr ) ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2008-11-29 12:14:06 -05:00
goto bad ;
error = EINVAL ;
2018-11-20 09:18:57 -05:00
if ( linux_cmsg . cmsg_len < sizeof ( struct l_cmsghdr ) | |
linux_cmsg . cmsg_len > clen )
2008-11-29 12:14:06 -05:00
goto bad ;
2018-11-19 10:31:54 -05:00
if ( datalen + CMSG_HDRSZ > MCLBYTES )
goto bad ;
2008-11-29 12:14:06 -05:00
/*
2011-03-26 07:05:53 -04:00
* Now we support only SCM_RIGHTS and SCM_CRED ,
* so return EINVAL in any other cmsg_type
2008-11-29 12:14:06 -05:00
*/
2018-11-19 10:31:54 -05:00
cmsg = data ;
2011-03-26 07:05:53 -04:00
cmsg - > cmsg_type =
linux_to_bsd_cmsg_type ( linux_cmsg . cmsg_type ) ;
2008-11-29 12:14:06 -05:00
cmsg - > cmsg_level =
linux_to_bsd_sockopt_level ( linux_cmsg . cmsg_level ) ;
2011-03-26 07:05:53 -04:00
if ( cmsg - > cmsg_type = = - 1
2020-06-14 10:38:40 -04: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 07:05:53 -04:00
goto bad ;
2020-06-14 10:38:40 -04:00
}
2008-11-29 12:14:06 -05:00
2011-03-26 07:05:53 -04: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 10:17:14 -04:00
goto next ;
2011-03-26 07:05:53 -04:00
2018-11-19 10:31:54 -05:00
if ( cmsg - > cmsg_type = = SCM_CREDS ) {
len = sizeof ( struct cmsgcred ) ;
if ( datalen + CMSG_SPACE ( len ) > MCLBYTES )
goto bad ;
2011-03-26 07:05:53 -04:00
/*
* The lower levels will fill in the structure
*/
2018-11-19 10:31:54 -05: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 07:05:53 -04:00
}
2018-11-19 10:31:54 -05:00
cmsg - > cmsg_len = CMSG_LEN ( len ) ;
data = ( char * ) data + CMSG_SPACE ( len ) ;
datalen + = CMSG_SPACE ( len ) ;
2018-11-20 09:18:57 -05:00
2020-08-18 10:17:14 -04:00
next :
2018-11-20 09:18:57 -05: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 07:05:53 -04:00
2018-11-19 10:31:54 -05:00
control - > m_len = datalen ;
if ( datalen = = 0 ) {
2011-03-26 07:05:53 -04:00
m_freem ( control ) ;
control = NULL ;
}
2008-11-29 12:14:06 -05:00
}
2003-11-09 12:04:04 -05:00
msg . msg_iov = iov ;
msg . msg_flags = 0 ;
2015-05-24 14:04:04 -04:00
error = linux_sendit ( td , s , & msg , flags , control , UIO_USERSPACE ) ;
2016-01-17 14:28:13 -05:00
control = NULL ;
2008-11-29 12:14:06 -05:00
bad :
2015-05-24 14:10:07 -04:00
m_freem ( control ) ;
2004-07-10 11:42:16 -04:00
free ( iov , M_IOV ) ;
2003-11-09 12:04:04 -05:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2015-05-24 14:04:04 -04: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 16:44:02 -04: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 16:46:05 -04:00
2022-05-28 16:44:02 -04: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 16:45:39 -04:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2022-05-28 16:44:02 -04:00
static int
2022-05-28 16:45:39 -04:00
recvmsg_scm_timestamp ( l_int msg_type , socklen_t * datalen , void * * data ,
void * * udata )
2022-05-28 16:44:02 -04:00
{
2022-05-28 16:45:39 -04:00
l_sock_timeval ltv64 ;
l_timeval ltv ;
struct timeval * tv ;
socklen_t len ;
void * buf ;
2022-05-28 16:44:02 -04:00
if ( * datalen ! = sizeof ( struct timeval ) )
return ( EMSGSIZE ) ;
2022-05-28 16:45:39 -04: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 16:44:02 -04:00
return ( 0 ) ;
}
2022-05-28 16:45:39 -04:00
# else
_Static_assert ( sizeof ( struct timeval ) = = sizeof ( l_timeval ) ,
" scm_timestamp sizeof l_timeval " ) ;
# endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
2022-05-28 16:44:02 -04:00
2022-05-28 16:46:05 -04: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) */
2023-08-14 08:46:12 -04:00
static int
recvmsg_scm_sol_socket ( struct thread * td , l_int msg_type , l_int lmsg_type ,
l_uint flags , socklen_t * datalen , void * * data , void * * udata )
{
int error ;
error = 0 ;
switch ( msg_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 :
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
error = recvmsg_scm_timestamp ( lmsg_type , datalen ,
data , udata ) ;
# endif
break ;
case SCM_BINTIME :
error = recvmsg_scm_timestampns ( lmsg_type , datalen ,
data , udata ) ;
break ;
}
return ( error ) ;
}
2022-05-28 16:47:40 -04: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 ) ;
}
2023-08-14 08:46:12 -04:00
static int
recvmsg_scm_ipproto_ip ( l_int msg_type , l_int lmsg_type , socklen_t * datalen ,
void * * data , void * * udata )
{
int error ;
error = 0 ;
switch ( msg_type ) {
case IP_ORIGDSTADDR :
error = recvmsg_scm_ip_origdstaddr ( datalen , data ,
udata ) ;
break ;
}
return ( error ) ;
}
2015-05-24 14:04:04 -04:00
static int
linux_recvmsg_common ( struct thread * td , l_int s , struct l_msghdr * msghdr ,
l_uint flags , struct msghdr * msg )
2000-12-18 19:24:25 -05:00
{
2022-05-28 16:45:39 -04:00
struct proc * p = td - > td_proc ;
2008-11-29 12:14:06 -05:00
struct cmsghdr * cm ;
2022-05-28 16:46:22 -04:00
struct l_cmsghdr * lcm = NULL ;
2018-08-07 12:36:48 -04:00
socklen_t datalen , maxlen , outlen ;
2022-05-28 16:46:22 -04:00
struct l_msghdr l_msghdr ;
2008-11-29 12:14:06 -05:00
struct iovec * iov , * uiov ;
2022-05-28 16:48:45 -04:00
struct mbuf * m , * control = NULL ;
2008-11-29 12:14:06 -05:00
struct mbuf * * controlp ;
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
2008-11-29 12:14:06 -05:00
caddr_t outbuf ;
2022-05-28 16:44:02 -04:00
void * data , * udata ;
2023-08-14 08:46:12 -04:00
int error , skiped ;
2000-12-18 19:24:25 -05:00
2022-05-28 16:46:22 -04:00
error = copyin ( msghdr , & l_msghdr , sizeof ( l_msghdr ) ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2008-11-29 12:14:06 -05:00
return ( error ) ;
2004-08-16 03:28:16 -04:00
2022-01-08 08:44:17 -05:00
/*
* Pass user - supplied recvmsg ( ) flags in msg_flags field ,
* following sys_recvmsg ( ) convention .
*/
2022-05-28 16:46:22 -04:00
l_msghdr . msg_flags = flags ;
2022-01-08 08:44:17 -05:00
2022-05-28 16:46:22 -04:00
error = linux_to_bsd_msghdr ( msg , & l_msghdr ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2007-02-01 08:36:19 -05:00
return ( error ) ;
2008-11-29 12:14:06 -05:00
# ifdef COMPAT_LINUX32
2023-08-20 03:36:32 -04:00
error = freebsd32_copyiniov ( PTRIN ( msg - > msg_iov ) , msg - > msg_iovlen ,
2008-11-29 12:14:06 -05:00
& iov , EMSGSIZE ) ;
# else
2015-05-24 14:04:04 -04:00
error = copyiniov ( msg - > msg_iov , msg - > msg_iovlen , & iov , EMSGSIZE ) ;
2008-11-29 12:14:06 -05:00
# endif
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2003-02-03 12:43:20 -05:00
return ( error ) ;
2020-07-05 06:57:28 -04:00
if ( msg - > msg_name ! = NULL & & msg - > msg_namelen > 0 ) {
msg - > msg_namelen = min ( msg - > msg_namelen , SOCK_MAXADDRLEN ) ;
2019-05-13 13:48:16 -04:00
sa = malloc ( msg - > msg_namelen , M_SONAME , M_WAITOK ) ;
msg - > msg_name = sa ;
2020-07-05 06:57:28 -04:00
} else {
2019-05-21 14:08:19 -04:00
sa = NULL ;
2020-07-05 06:57:28 -04:00
msg - > msg_name = NULL ;
}
2003-10-11 11:08:32 -04:00
2015-05-24 14:04:04 -04:00
uiov = msg - > msg_iov ;
msg - > msg_iov = iov ;
controlp = ( msg - > msg_control ! = NULL ) ? & control : NULL ;
2019-05-13 13:48:16 -04:00
error = kern_recvit ( td , s , msg , UIO_SYSSPACE , controlp ) ;
2015-05-24 14:04:04 -04:00
msg - > msg_iov = uiov ;
if ( error ! = 0 )
2008-11-29 12:14:06 -05:00
goto bad ;
2020-07-05 06:57:28 -04:00
/*
* Note that kern_recvit ( ) updates msg - > msg_namelen .
*/
if ( msg - > msg_name ! = NULL & & msg - > msg_namelen > 0 ) {
2022-05-28 16:46:22 -04:00
msg - > msg_name = PTRIN ( l_msghdr . msg_name ) ;
2022-04-11 16:32:02 -04:00
error = linux_copyout_sockaddr ( sa , msg - > msg_name ,
msg - > msg_namelen ) ;
2015-05-24 14:04:04 -04:00
if ( error ! = 0 )
2008-11-29 12:14:06 -05:00
goto bad ;
}
2022-05-28 16:46:22 -04:00
error = bsd_to_linux_msghdr ( msg , & l_msghdr ) ;
2019-05-13 13:48:16 -04:00
if ( error ! = 0 )
goto bad ;
2023-08-14 08:46:12 -04:00
skiped = outlen = 0 ;
2022-05-28 16:46:22 -04:00
maxlen = l_msghdr . msg_controllen ;
if ( control = = NULL )
goto out ;
2011-03-26 07:05:53 -04:00
2022-05-28 16:46:22 -04: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 ) ;
2022-05-28 16:48:45 -04:00
for ( m = control ; m ! = NULL ; m = m - > m_next ) {
cm = mtod ( m , struct cmsghdr * ) ;
2022-05-28 16:47:40 -04:00
lcm - > cmsg_type = bsd_to_linux_cmsg_type ( p , cm - > cmsg_type ,
cm - > cmsg_level ) ;
2022-05-28 16:46:22 -04:00
lcm - > cmsg_level = bsd_to_linux_sockopt_level ( cm - > cmsg_level ) ;
2022-05-28 16:47:40 -04:00
2022-05-28 16:46:22 -04:00
if ( lcm - > cmsg_type = = - 1 | |
2023-08-14 08:46:12 -04:00
cm - > cmsg_level = = - 1 ) {
2022-05-28 16:48:16 -04:00
LINUX_RATELIMIT_MSG_OPT2 (
2022-05-28 16:46:22 -04:00
" unsupported recvmsg cmsg level %d type %d " ,
cm - > cmsg_level , cm - > cmsg_type ) ;
2023-08-14 08:46:12 -04:00
/* Skip unsupported messages */
skiped + + ;
continue ;
2022-05-28 16:46:22 -04:00
}
2023-08-14 08:46:12 -04:00
data = CMSG_DATA ( cm ) ;
datalen = ( caddr_t ) cm + cm - > cmsg_len - ( caddr_t ) data ;
udata = NULL ;
error = 0 ;
2015-05-24 14:13:21 -04:00
2023-08-14 08:46:12 -04:00
switch ( cm - > cmsg_level ) {
case IPPROTO_IP :
error = recvmsg_scm_ipproto_ip ( cm - > cmsg_type ,
lcm - > cmsg_type , & datalen , & data , & udata ) ;
break ;
case SOL_SOCKET :
error = recvmsg_scm_sol_socket ( td , cm - > cmsg_type ,
lcm - > cmsg_type , flags , & datalen , & data , & udata ) ;
break ;
}
2022-05-28 16:47:40 -04:00
2023-08-14 08:46:12 -04:00
/* The recvmsg_scm_ is responsible to free udata on error. */
2022-05-28 16:46:22 -04:00
if ( error ! = 0 )
goto bad ;
2011-03-26 07:05:53 -04:00
2023-08-14 08:46:11 -04:00
if ( outlen + LINUX_CMSG_LEN ( datalen ) > maxlen ) {
2022-05-28 16:46:22 -04:00
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 12:14:06 -05:00
}
2022-05-28 16:46:22 -04:00
}
2008-11-29 12:14:06 -05:00
2022-05-28 16:46:22 -04:00
lcm - > cmsg_len = LINUX_CMSG_LEN ( datalen ) ;
error = copyout ( lcm , outbuf , L_CMSG_HDRSZ ) ;
if ( error = = 0 ) {
2023-08-14 08:46:12 -04:00
error = copyout ( data , LINUX_CMSG_DATA ( outbuf ) , datalen ) ;
2022-05-28 16:44:02 -04:00
if ( error = = 0 ) {
2023-08-14 08:46:12 -04:00
outbuf + = LINUX_CMSG_SPACE ( datalen ) ;
2023-07-29 04:21:35 -04:00
outlen + = LINUX_CMSG_SPACE ( datalen ) ;
2022-05-28 16:44:02 -04:00
}
2008-11-29 12:14:06 -05:00
}
2022-05-28 16:46:22 -04:00
err :
free ( udata , M_LINUX ) ;
if ( error ! = 0 )
goto bad ;
2008-11-29 12:14:06 -05:00
}
2023-08-14 08:46:12 -04:00
if ( outlen = = 0 & & skiped > 0 ) {
error = EINVAL ;
goto bad ;
}
2008-11-29 12:14:06 -05:00
out :
2023-08-14 08:46:12 -04:00
l_msghdr . msg_controllen = outlen ;
2022-05-28 16:46:22 -04:00
error = copyout ( & l_msghdr , msghdr , sizeof ( l_msghdr ) ) ;
2008-11-29 12:14:06 -05:00
bad :
2018-08-07 12:36:48 -04:00
if ( control ! = NULL ) {
if ( error ! = 0 )
m_dispose_extcontrolm ( control ) ;
m_freem ( control ) ;
}
2008-11-29 12:14:06 -05:00
free ( iov , M_IOV ) ;
2022-05-28 16:46:22 -04:00
free ( lcm , M_LINUX ) ;
2019-05-21 14:08:19 -04:00
free ( sa , M_SONAME ) ;
2008-11-29 12:14:06 -05:00
2003-02-03 12:43:20 -05:00
return ( error ) ;
2000-12-18 19:24:25 -05:00
}
2015-05-24 14:04:04 -04:00
int
linux_recvmsg ( struct thread * td , struct linux_recvmsg_args * args )
{
struct msghdr bsd_msg ;
2022-05-28 16:29:12 -04:00
struct file * fp ;
int error ;
2015-05-24 14:04:04 -04:00
2022-09-07 11:41:55 -04:00
error = getsock ( td , args - > s , & cap_recv_rights , & fp ) ;
2022-05-28 16:29:12 -04:00
if ( error ! = 0 )
return ( error ) ;
fdrop ( fp , td ) ;
2015-05-24 14:04:04 -04:00
return ( linux_recvmsg_common ( td , args - > s , PTRIN ( args - > msg ) ,
args - > flags , & bsd_msg ) ) ;
}
2022-05-04 06:06:53 -04: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 14:04:04 -04:00
{
struct msghdr bsd_msg ;
2022-05-04 06:06:53 -04:00
struct timespec ts ;
2022-05-28 16:29:12 -04:00
struct file * fp ;
2015-05-24 14:04:04 -04:00
l_uint retval ;
int error , datagrams ;
2022-09-07 11:41:55 -04:00
error = getsock ( td , s , & cap_recv_rights , & fp ) ;
2022-05-28 16:29:12 -04:00
if ( error ! = 0 )
return ( error ) ;
2015-05-24 14:04:04 -04:00
datagrams = 0 ;
2022-05-04 06:06:53 -04:00
while ( datagrams < vlen ) {
error = linux_recvmsg_common ( td , s , & msg - > msg_hdr ,
flags & ~ LINUX_MSG_WAITFORONE , & bsd_msg ) ;
2015-05-24 14:04:04 -04: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 06:06:53 -04:00
if ( flags & LINUX_MSG_WAITFORONE )
flags | = LINUX_MSG_DONTWAIT ;
2015-05-24 14:04:04 -04:00
/*
* See BUGS section of recvmmsg ( 2 ) .
*/
2022-05-04 06:06:53 -04:00
if ( tts ) {
2015-05-24 14:04:04 -04:00
getnanotime ( & ts ) ;
2022-05-04 06:06:53 -04:00
timespecsub ( & ts , tts , & ts ) ;
2015-05-24 14:04:04 -04: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 16:29:12 -04:00
fdrop ( fp , td ) ;
2015-05-24 14:04:04 -04:00
return ( error ) ;
}
2022-05-04 06:06:53 -04: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 09:16:47 -04:00
error = linux_get_timespec ( & ts , args - > timeout ) ;
2022-05-04 06:06:53 -04: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 09:16:47 -04:00
error = linux_get_timespec64 ( & ts , args - > timeout ) ;
2022-05-04 06:06:53 -04: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 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_shutdown ( struct thread * td , struct linux_shutdown_args * args )
1995-06-25 13:32:43 -04:00
{
2000-08-26 01:12:16 -04:00
2017-01-30 07:57:22 -05:00
return ( kern_shutdown ( td , args - > s , args - > how ) ) ;
1995-06-25 13:32:43 -04:00
}
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_setsockopt ( struct thread * td , struct linux_setsockopt_args * args )
1995-06-25 13:32:43 -04:00
{
2022-05-28 16:45:39 -04:00
struct proc * p = td - > td_proc ;
struct linux_pemuldata * pem ;
2009-05-11 09:50:42 -04:00
l_timeval linux_tv ;
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
2009-05-11 09:50:42 -04:00
struct timeval tv ;
2019-05-13 13:48:16 -04:00
socklen_t len ;
2022-05-28 16:46:38 -04:00
int error , level , name , val ;
2000-08-26 01:12:16 -04:00
2020-01-14 06:33:07 -05:00
level = linux_to_bsd_sockopt_level ( args - > level ) ;
switch ( level ) {
2000-08-26 01:12:16 -04:00
case SOL_SOCKET :
2008-09-09 09:01:14 -04:00
name = linux_to_bsd_so_sockopt ( args - > optname ) ;
2009-05-11 09:50:42 -04:00
switch ( name ) {
2020-11-02 20:19:13 -05:00
case LOCAL_CREDS_PERSISTENT :
level = SOL_LOCAL ;
break ;
2009-05-11 09:50:42 -04:00
case SO_RCVTIMEO :
/* FALLTHROUGH */
case SO_SNDTIMEO :
error = copyin ( PTRIN ( args - > optval ) , & linux_tv ,
sizeof ( linux_tv ) ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2009-05-11 09:50:42 -04:00
return ( error ) ;
tv . tv_sec = linux_tv . tv_sec ;
tv . tv_usec = linux_tv . tv_usec ;
2020-01-14 06:33:07 -05:00
return ( kern_setsockopt ( td , args - > s , level ,
2009-05-11 09:50:42 -04:00
name , & tv , UIO_SYSSPACE , sizeof ( tv ) ) ) ;
/* NOTREACHED */
2022-05-28 16:45:39 -04:00
case SO_TIMESTAMP :
2022-05-28 16:46:38 -04: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 16:45:39 -04:00
pem = pem_find ( p ) ;
pem - > so_timestamp = args - > optname ;
break ;
2022-05-28 16:46:05 -04:00
case SO_BINTIME :
2022-05-28 16:46:38 -04: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 16:46:05 -04:00
pem = pem_find ( p ) ;
pem - > so_timestampns = args - > optname ;
break ;
2009-05-11 09:50:42 -04:00
default :
break ;
}
2000-08-26 01:12:16 -04:00
break ;
case IPPROTO_IP :
2020-01-28 08:51:53 -05: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 09:01:14 -04:00
name = linux_to_bsd_ip_sockopt ( args - > optname ) ;
2000-08-26 01:12:16 -04:00
break ;
2016-03-09 04:12:40 -05:00
case IPPROTO_IPV6 :
name = linux_to_bsd_ip6_sockopt ( args - > optname ) ;
break ;
2000-08-26 01:12:16 -04:00
case IPPROTO_TCP :
2013-01-23 16:44:48 -05:00
name = linux_to_bsd_tcp_sockopt ( args - > optname ) ;
2000-08-26 01:12:16 -04:00
break ;
2022-08-26 10:34:15 -04:00
case SOL_NETLINK :
level = SOL_SOCKET ;
name = args - > optname ;
break ;
2000-08-26 01:12:16 -04:00
default :
name = - 1 ;
break ;
}
2020-11-08 04:50:58 -05:00
if ( name < 0 ) {
if ( name = = - 1 )
linux_msg ( curthread ,
" unsupported setsockopt level %d optname %d " ,
args - > level , args - > optname ) ;
2006-09-23 15:06:54 -04:00
return ( ENOPROTOOPT ) ;
2020-02-27 14:40:20 -05:00
}
2006-03-18 13:20:17 -05:00
if ( name = = IPV6_NEXTHOP ) {
2019-05-13 13:48:16 -04:00
len = args - > optlen ;
error = linux_to_bsd_sockaddr ( PTRIN ( args - > optval ) , & sa , & len ) ;
if ( error ! = 0 )
return ( error ) ;
2020-01-14 06:33:07 -05:00
error = kern_setsockopt ( td , args - > s , level ,
2019-05-13 13:48:16 -04:00
name , sa , UIO_SYSSPACE , len ) ;
free ( sa , M_SONAME ) ;
} else {
2020-01-14 06:33:07 -05:00
error = kern_setsockopt ( td , args - > s , level ,
name , PTRIN ( args - > optval ) , UIO_USERSPACE , args - > optlen ) ;
2019-05-13 13:48:16 -04:00
}
2006-03-18 13:20:17 -05:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2022-05-28 16:30:22 -04: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 16:29:32 -05: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 15:28:35 -05: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 16:30:22 -04:00
return ( linux_sockopt_copyout ( td , SECURITY_CONTEXT_STRING ,
len , args ) ) ;
2021-02-07 15:28:35 -05:00
}
2022-05-28 16:31:06 -04: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 16:30:22 -04:00
2015-05-24 11:41:27 -04:00
int
2001-09-12 04:38:13 -04:00
linux_getsockopt ( struct thread * td , struct linux_getsockopt_args * args )
1995-06-25 13:32:43 -04:00
{
2009-05-11 09:50:42 -04:00
l_timeval linux_tv ;
struct timeval tv ;
2016-05-22 08:49:08 -04:00
socklen_t tv_len , xulen , len ;
2019-05-13 13:48:16 -04:00
struct sockaddr * sa ;
2009-05-16 14:42:18 -04:00
struct xucred xu ;
struct l_ucred lxu ;
2020-01-14 06:30:30 -05:00
int error , level , name , newval ;
2000-08-26 01:12:16 -04:00
2020-01-14 06:30:30 -05:00
level = linux_to_bsd_sockopt_level ( args - > level ) ;
switch ( level ) {
2000-08-26 01:12:16 -04:00
case SOL_SOCKET :
2021-02-07 16:29:32 -05:00
switch ( args - > optname ) {
case LINUX_SO_PEERGROUPS :
return ( linux_getsockopt_so_peergroups ( td , args ) ) ;
case LINUX_SO_PEERSEC :
2021-02-07 15:28:35 -05:00
return ( linux_getsockopt_so_peersec ( td , args ) ) ;
2021-02-07 16:29:32 -05:00
default :
break ;
}
2008-09-09 09:01:14 -04:00
name = linux_to_bsd_so_sockopt ( args - > optname ) ;
2009-05-11 09:50:42 -04:00
switch ( name ) {
2020-11-02 20:19:13 -05:00
case LOCAL_CREDS_PERSISTENT :
level = SOL_LOCAL ;
break ;
2009-05-11 09:50:42 -04:00
case SO_RCVTIMEO :
/* FALLTHROUGH */
case SO_SNDTIMEO :
tv_len = sizeof ( tv ) ;
2020-01-14 06:30:30 -05:00
error = kern_getsockopt ( td , args - > s , level ,
2009-05-11 09:50:42 -04:00
name , & tv , UIO_SYSSPACE , & tv_len ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2009-05-11 09:50:42 -04:00
return ( error ) ;
linux_tv . tv_sec = tv . tv_sec ;
linux_tv . tv_usec = tv . tv_usec ;
2022-05-28 16:30:22 -04:00
return ( linux_sockopt_copyout ( td , & linux_tv ,
sizeof ( linux_tv ) , args ) ) ;
2009-05-11 09:50:42 -04:00
/* NOTREACHED */
2009-05-16 14:42:18 -04:00
case LOCAL_PEERCRED :
2017-03-18 14:31:04 -04:00
if ( args - > optlen < sizeof ( lxu ) )
2009-05-16 14:42:18 -04:00
return ( EINVAL ) ;
2019-01-08 12:21:59 -05:00
/*
* LOCAL_PEERCRED is not served at the SOL_SOCKET level ,
* but by the Unix socket ' s level 0.
*/
2020-01-14 06:30:30 -05:00
level = 0 ;
2009-05-16 14:42:18 -04:00
xulen = sizeof ( xu ) ;
2020-01-14 06:30:30 -05:00
error = kern_getsockopt ( td , args - > s , level ,
2009-05-16 14:42:18 -04:00
name , & xu , UIO_SYSSPACE , & xulen ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2009-05-16 14:42:18 -04:00
return ( error ) ;
2019-05-30 10:24:26 -04:00
lxu . pid = xu . cr_pid ;
2009-05-16 14:42:18 -04:00
lxu . uid = xu . cr_uid ;
lxu . gid = xu . cr_gid ;
2022-05-28 16:30:22 -04:00
return ( linux_sockopt_copyout ( td , & lxu ,
sizeof ( lxu ) , args ) ) ;
2009-05-16 14:42:18 -04:00
/* NOTREACHED */
2016-05-22 08:49:08 -04:00
case SO_ERROR :
len = sizeof ( newval ) ;
2020-01-14 06:30:30 -05:00
error = kern_getsockopt ( td , args - > s , level ,
2016-05-22 08:49:08 -04:00
name , & newval , UIO_SYSSPACE , & len ) ;
2017-02-18 05:01:17 -05:00
if ( error ! = 0 )
2016-05-22 08:49:08 -04:00
return ( error ) ;
2020-10-27 08:49:40 -04:00
newval = - bsd_to_linux_errno ( newval ) ;
2022-05-28 16:30:22 -04:00
return ( linux_sockopt_copyout ( td , & newval ,
len , args ) ) ;
2016-05-22 08:49:08 -04:00
/* NOTREACHED */
2022-04-11 16:31:28 -04: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 16:30:22 -04:00
return ( linux_sockopt_copyout ( td , & newval ,
len , args ) ) ;
2022-04-11 16:31:28 -04:00
/* NOTREACHED */
2022-05-28 16:31:06 -04:00
case SO_LINGER :
return ( linux_getsockopt_so_linger ( td , args ) ) ;
/* NOTREACHED */
2009-05-11 09:50:42 -04:00
default :
break ;
}
2000-08-26 01:12:16 -04:00
break ;
case IPPROTO_IP :
2008-09-09 09:01:14 -04:00
name = linux_to_bsd_ip_sockopt ( args - > optname ) ;
2000-08-26 01:12:16 -04:00
break ;
2016-03-09 04:12:40 -05:00
case IPPROTO_IPV6 :
name = linux_to_bsd_ip6_sockopt ( args - > optname ) ;
break ;
2000-08-26 01:12:16 -04:00
case IPPROTO_TCP :
2013-01-23 16:44:48 -05:00
name = linux_to_bsd_tcp_sockopt ( args - > optname ) ;
2000-08-26 01:12:16 -04:00
break ;
default :
name = - 1 ;
break ;
}
2020-11-08 04:50:58 -05:00
if ( name < 0 ) {
if ( name = = - 1 )
linux_msg ( curthread ,
" unsupported getsockopt level %d optname %d " ,
args - > level , args - > optname ) ;
2000-08-26 01:12:16 -04:00
return ( EINVAL ) ;
2020-02-27 14:40:20 -05:00
}
2000-08-26 01:12:16 -04:00
2006-03-18 13:20:17 -05:00
if ( name = = IPV6_NEXTHOP ) {
2019-05-13 13:48:16 -04:00
error = copyin ( PTRIN ( args - > optlen ) , & len , sizeof ( len ) ) ;
if ( error ! = 0 )
return ( error ) ;
sa = malloc ( len , M_SONAME , M_WAITOK ) ;
2020-01-14 06:30:30 -05:00
error = kern_getsockopt ( td , args - > s , level ,
2019-05-13 13:48:16 -04:00
name , sa , UIO_SYSSPACE , & len ) ;
if ( error ! = 0 )
goto out ;
2020-09-17 08:14:24 -04:00
error = linux_copyout_sockaddr ( sa , PTRIN ( args - > optval ) , len ) ;
2019-05-13 13:48:16 -04:00
if ( error = = 0 )
error = copyout ( & len , PTRIN ( args - > optlen ) ,
sizeof ( len ) ) ;
out :
free ( sa , M_SONAME ) ;
} else {
2020-01-14 06:30:30 -05: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 13:48:16 -04:00
}
2006-03-18 13:20:17 -05:00
return ( error ) ;
1995-06-25 13:32:43 -04:00
}
2023-08-17 15:57:17 -04:00
/*
* Based on sendfile_getsock from kern_sendfile . c
* Determines whether an fd is a stream socket that can be used
* with FreeBSD sendfile .
*/
static bool
2023-08-19 14:55:23 -04:00
is_sendfile ( struct file * fp , struct file * ofp )
2023-08-17 15:57:17 -04:00
{
struct socket * so ;
2023-08-19 14:55:23 -04:00
/*
* FreeBSD sendfile ( ) system call sends a regular file or
* shared memory object out a stream socket .
*/
if ( ( fp - > f_type ! = DTYPE_SHM & & fp - > f_type ! = DTYPE_VNODE ) | |
( fp - > f_type = = DTYPE_VNODE & &
( fp - > f_vnode = = NULL | | fp - > f_vnode - > v_type ! = VREG ) ) )
return ( false ) ;
2023-08-17 15:57:17 -04:00
/*
* The socket must be a stream socket and connected .
*/
2023-08-19 14:55:23 -04:00
if ( ofp - > f_type ! = DTYPE_SOCKET )
2023-08-17 15:57:17 -04:00
return ( false ) ;
2023-08-19 14:55:23 -04:00
so = ofp - > f_data ;
2023-08-17 15:57:17 -04:00
if ( so - > so_type ! = SOCK_STREAM )
return ( false ) ;
/*
* SCTP one - to - one style sockets currently don ' t work with
* sendfile ( ) .
*/
if ( so - > so_proto - > pr_protocol = = IPPROTO_SCTP )
return ( false ) ;
return ( ! SOLISTENING ( so ) ) ;
}
static bool
is_regular_file ( struct file * fp )
{
return ( fp - > f_type = = DTYPE_VNODE & & fp - > f_vnode ! = NULL & &
fp - > f_vnode - > v_type = = VREG ) ;
}
2020-02-05 11:53:02 -05:00
static int
2023-08-17 15:57:17 -04:00
sendfile_fallback ( struct thread * td , struct file * fp , l_int out ,
off_t * offset , l_size_t count , off_t * sbytes )
2020-02-05 11:53:02 -05:00
{
2023-08-17 15:57:17 -04:00
off_t current_offset , out_offset , to_send ;
l_size_t bytes_sent , n_read ;
struct file * ofp ;
struct iovec aiov ;
struct uio auio ;
bool seekable ;
size_t bufsz ;
void * buf ;
int flags , error ;
2020-02-05 11:53:02 -05:00
2023-08-17 15:57:17 -04:00
if ( offset = = NULL ) {
if ( ( error = fo_seek ( fp , 0 , SEEK_CUR , td ) ) ! = 0 )
return ( error ) ;
current_offset = td - > td_uretoff . tdu_off ;
} else {
if ( ( fp - > f_ops - > fo_flags & DFLAG_SEEKABLE ) = = 0 )
return ( ESPIPE ) ;
current_offset = * offset ;
}
error = fget_write ( td , out , & cap_pwrite_rights , & ofp ) ;
2020-02-05 11:53:02 -05:00
if ( error ! = 0 )
return ( error ) ;
2023-08-17 15:57:17 -04:00
seekable = ( ofp - > f_ops - > fo_flags & DFLAG_SEEKABLE ) ! = 0 ;
if ( seekable ) {
if ( ( error = fo_seek ( ofp , 0 , SEEK_CUR , td ) ) ! = 0 )
2020-02-05 11:53:02 -05:00
goto drop ;
2023-08-17 15:57:17 -04:00
out_offset = td - > td_uretoff . tdu_off ;
} else
out_offset = 0 ;
flags = FOF_OFFSET | FOF_NOUPDATE ;
bufsz = min ( count , MAXPHYS ) ;
buf = malloc ( bufsz , M_LINUX , M_WAITOK ) ;
bytes_sent = 0 ;
while ( bytes_sent < count ) {
to_send = min ( count - bytes_sent , bufsz ) ;
aiov . iov_base = buf ;
aiov . iov_len = bufsz ;
auio . uio_iov = & aiov ;
auio . uio_iovcnt = 1 ;
auio . uio_segflg = UIO_SYSSPACE ;
auio . uio_td = td ;
auio . uio_rw = UIO_READ ;
auio . uio_offset = current_offset ;
auio . uio_resid = to_send ;
error = fo_read ( fp , & auio , fp - > f_cred , flags , td ) ;
if ( error ! = 0 )
break ;
n_read = to_send - auio . uio_resid ;
if ( n_read = = 0 )
break ;
aiov . iov_base = buf ;
aiov . iov_len = bufsz ;
auio . uio_iov = & aiov ;
auio . uio_iovcnt = 1 ;
auio . uio_segflg = UIO_SYSSPACE ;
auio . uio_td = td ;
auio . uio_rw = UIO_WRITE ;
auio . uio_offset = ( seekable ) ? out_offset : 0 ;
auio . uio_resid = n_read ;
error = fo_write ( ofp , & auio , ofp - > f_cred , flags , td ) ;
if ( error ! = 0 )
break ;
bytes_sent + = n_read ;
current_offset + = n_read ;
out_offset + = n_read ;
}
free ( buf , M_LINUX ) ;
if ( error = = 0 ) {
* sbytes = bytes_sent ;
if ( offset ! = NULL )
* offset = current_offset ;
else
error = fo_seek ( fp , current_offset , SEEK_SET , td ) ;
}
if ( error = = 0 & & seekable )
error = fo_seek ( ofp , out_offset , SEEK_SET , td ) ;
drop :
fdrop ( ofp , td ) ;
return ( error ) ;
}
static int
sendfile_sendfile ( struct thread * td , struct file * fp , l_int out ,
off_t * offset , l_size_t count , off_t * sbytes )
{
off_t current_offset ;
int error ;
if ( offset = = NULL ) {
if ( ( fp - > f_ops - > fo_flags & DFLAG_SEEKABLE ) = = 0 )
return ( ESPIPE ) ;
if ( ( error = fo_seek ( fp , 0 , SEEK_CUR , td ) ) ! = 0 )
return ( error ) ;
2020-02-05 11:53:02 -05:00
current_offset = td - > td_uretoff . tdu_off ;
2023-08-17 15:57:17 -04:00
} else
current_offset = * offset ;
error = fo_sendfile ( fp , out , NULL , NULL , current_offset , count ,
sbytes , 0 , td ) ;
if ( error = = 0 ) {
current_offset + = * sbytes ;
if ( offset ! = NULL )
* offset = current_offset ;
else
error = fo_seek ( fp , current_offset , SEEK_SET , td ) ;
2020-02-05 11:53:02 -05:00
}
2023-08-17 15:57:17 -04:00
return ( error ) ;
}
2020-02-05 11:53:02 -05:00
2023-08-17 15:57:17 -04:00
static int
linux_sendfile_common ( struct thread * td , l_int out , l_int in ,
off_t * offset , l_size_t count )
{
struct file * fp , * ofp ;
off_t sbytes ;
int error ;
2020-02-05 11:53:02 -05:00
/* Linux cannot have 0 count. */
2023-08-17 15:57:17 -04:00
if ( count < = 0 | | ( offset ! = NULL & & * offset < 0 ) )
return ( EINVAL ) ;
AUDIT_ARG_FD ( in ) ;
error = fget_read ( td , in , & cap_pread_rights , & fp ) ;
if ( error ! = 0 )
return ( error ) ;
if ( ( fp - > f_type ! = DTYPE_SHM & & fp - > f_type ! = DTYPE_VNODE ) | |
( fp - > f_type = = DTYPE_VNODE & &
( fp - > f_vnode = = NULL | | fp - > f_vnode - > v_type ! = VREG ) ) ) {
2020-02-05 11:53:02 -05:00
error = EINVAL ;
goto drop ;
}
2023-08-17 15:57:17 -04:00
error = fget_unlocked ( td , out , & cap_no_rights , & ofp ) ;
2020-02-05 11:53:02 -05:00
if ( error ! = 0 )
goto drop ;
2023-08-17 15:57:17 -04:00
if ( is_regular_file ( fp ) & & is_regular_file ( ofp ) ) {
error = kern_copy_file_range ( td , in , offset , out , NULL , count ,
0 ) ;
2020-02-05 11:53:02 -05:00
} else {
2023-08-17 15:57:17 -04:00
sbytes = 0 ;
2023-08-19 14:55:23 -04:00
if ( is_sendfile ( fp , ofp ) )
2023-08-17 15:57:17 -04:00
error = sendfile_sendfile ( td , fp , out , offset , count ,
& sbytes ) ;
else
error = sendfile_fallback ( td , fp , out , offset , count ,
& sbytes ) ;
2023-08-19 14:55:23 -04:00
if ( error = = ENOBUFS & & ( ofp - > f_flag & FNONBLOCK ) ! = 0 )
error = EAGAIN ;
2023-08-17 15:57:17 -04:00
if ( error = = 0 )
td - > td_retval [ 0 ] = sbytes ;
2020-02-05 11:53:02 -05:00
}
2023-08-17 15:57:17 -04:00
fdrop ( ofp , td ) ;
2020-02-05 11:53:02 -05:00
drop :
fdrop ( fp , td ) ;
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
2023-08-17 15:57:17 -04:00
* mean send the whole file ) .
2020-02-05 11:53:02 -05:00
* - Linux can send to any fd whereas FreeBSD only supports sockets .
2023-08-17 15:57:17 -04:00
* We therefore use FreeBSD sendfile where possible for performance ,
* but fall back on a manual copy ( sendfile_fallback ) .
2020-02-05 11:53:02 -05:00
* - 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 .
*/
2023-08-17 15:57:17 -04:00
off_t offset64 ;
l_off_t offset ;
2020-02-05 11:53:02 -05:00
int error ;
if ( arg - > offset ! = NULL ) {
error = copyin ( arg - > offset , & offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
2023-08-17 15:57:17 -04:00
offset64 = offset ;
2020-02-05 11:53:02 -05:00
}
2023-08-17 15:57:17 -04:00
error = linux_sendfile_common ( td , arg - > out , arg - > in ,
2020-02-05 11:53:02 -05:00
arg - > offset ! = NULL ? & offset64 : NULL , arg - > count ) ;
2023-08-17 15:57:17 -04:00
if ( error = = 0 & & arg - > offset ! = NULL ) {
2023-08-17 15:57:17 -04:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2020-02-05 11:53:02 -05:00
if ( offset64 > INT32_MAX )
return ( EOVERFLOW ) ;
# endif
2023-08-17 15:57:17 -04:00
offset = ( l_off_t ) offset64 ;
2020-02-05 11:53:02 -05:00
error = copyout ( & offset , arg - > offset , sizeof ( offset ) ) ;
}
2023-08-17 15:57:17 -04:00
return ( error ) ;
2020-02-05 11:53:02 -05:00
}
2023-08-17 15:57:17 -04:00
# if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
2020-02-05 11:53:02 -05:00
int
linux_sendfile64 ( struct thread * td , struct linux_sendfile64_args * arg )
{
2023-08-17 15:57:17 -04:00
off_t offset ;
2020-02-05 11:53:02 -05:00
int error ;
if ( arg - > offset ! = NULL ) {
error = copyin ( arg - > offset , & offset , sizeof ( offset ) ) ;
if ( error ! = 0 )
return ( error ) ;
}
2023-08-17 15:57:17 -04:00
error = linux_sendfile_common ( td , arg - > out , arg - > in ,
2020-02-05 11:53:02 -05:00
arg - > offset ! = NULL ? & offset : NULL , arg - > count ) ;
2023-08-17 15:57:17 -04:00
if ( error = = 0 & & arg - > offset ! = NULL )
2020-02-05 11:53:02 -05:00
error = copyout ( & offset , arg - > offset , sizeof ( offset ) ) ;
2023-08-17 15:57:17 -04:00
return ( error ) ;
2020-02-05 11:53:02 -05:00
}
2015-05-24 11:43:53 -04:00
2009-05-19 05:10:53 -04:00
/* Argument list sizes for linux_socketcall */
2017-02-12 10:22:50 -05: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 11:53:02 -05:00
4 /* sendmmsg */ , 4 /* sendfile */
2009-05-19 05:10:53 -04:00
} ;
2017-02-12 10:22:50 -05: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 05:10:53 -04:00
1995-06-25 13:32:43 -04:00
int
2001-09-12 04:38:13 -04:00
linux_socketcall ( struct thread * td , struct linux_socketcall_args * args )
1995-06-25 13:32:43 -04:00
{
2009-05-19 05:10:53 -04:00
l_ulong a [ 6 ] ;
2017-02-12 10:22:50 -05:00
# if defined(__amd64__) && defined(COMPAT_LINUX32)
register_t l_args [ 6 ] ;
# endif
2009-05-19 05:10:53 -04:00
void * arg ;
int error ;
2017-02-12 10:22:50 -05:00
if ( args - > what < LINUX_SOCKET | | args - > what > LINUX_ARGS_CNT )
2009-05-19 05:10:53 -04:00
return ( EINVAL ) ;
2017-02-12 10:22:50 -05:00
error = copyin ( PTRIN ( args - > args ) , a , LINUX_ARG_SIZE ( args - > what ) ) ;
if ( error ! = 0 )
2009-05-19 05:10:53 -04:00
return ( error ) ;
2000-08-26 01:12:16 -04:00
2017-02-12 10:22:50 -05: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 05:10:53 -04:00
arg = a ;
2017-02-12 10:22:50 -05:00
# endif
2000-08-26 01:12:16 -04:00
switch ( args - > what ) {
case LINUX_SOCKET :
2001-09-12 04:38:13 -04:00
return ( linux_socket ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_BIND :
2001-09-12 04:38:13 -04:00
return ( linux_bind ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_CONNECT :
2001-09-12 04:38:13 -04:00
return ( linux_connect ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_LISTEN :
2001-09-12 04:38:13 -04:00
return ( linux_listen ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_ACCEPT :
2001-09-12 04:38:13 -04:00
return ( linux_accept ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_GETSOCKNAME :
2001-09-12 04:38:13 -04:00
return ( linux_getsockname ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_GETPEERNAME :
2001-09-12 04:38:13 -04:00
return ( linux_getpeername ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SOCKETPAIR :
2001-09-12 04:38:13 -04:00
return ( linux_socketpair ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SEND :
2001-09-12 04:38:13 -04:00
return ( linux_send ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_RECV :
2001-09-12 04:38:13 -04:00
return ( linux_recv ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SENDTO :
2001-09-12 04:38:13 -04:00
return ( linux_sendto ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_RECVFROM :
2001-09-12 04:38:13 -04:00
return ( linux_recvfrom ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SHUTDOWN :
2001-09-12 04:38:13 -04:00
return ( linux_shutdown ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SETSOCKOPT :
2001-09-12 04:38:13 -04:00
return ( linux_setsockopt ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_GETSOCKOPT :
2001-09-12 04:38:13 -04:00
return ( linux_getsockopt ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_SENDMSG :
2003-02-03 12:43:20 -05:00
return ( linux_sendmsg ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
case LINUX_RECVMSG :
2001-09-12 04:38:13 -04:00
return ( linux_recvmsg ( td , arg ) ) ;
2009-06-01 16:48:39 -04:00
case LINUX_ACCEPT4 :
return ( linux_accept4 ( td , arg ) ) ;
2015-05-24 14:04:04 -04:00
case LINUX_RECVMMSG :
return ( linux_recvmmsg ( td , arg ) ) ;
case LINUX_SENDMMSG :
return ( linux_sendmmsg ( td , arg ) ) ;
2020-02-05 11:53:02 -05:00
case LINUX_SENDFILE :
return ( linux_sendfile ( td , arg ) ) ;
2000-08-26 01:12:16 -04:00
}
1998-12-30 16:20:00 -05:00
2020-06-12 10:31:19 -04:00
linux_msg ( td , " socket type %d not implemented " , args - > what ) ;
2000-08-26 01:12:16 -04:00
return ( ENOSYS ) ;
1995-06-25 13:32:43 -04:00
}
2023-08-17 15:57:17 -04:00
# endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */