1c21dee17SSøren Schmidt /*- 20ba1b365SEd Maste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 37f2d13d6SPedro F. Giffuni * 49a14aa01SUlrich Spörlein * Copyright (c) 1995 Søren Schmidt 5c21dee17SSøren Schmidt * All rights reserved. 6c21dee17SSøren Schmidt * 7c21dee17SSøren Schmidt * Redistribution and use in source and binary forms, with or without 8c21dee17SSøren Schmidt * modification, are permitted provided that the following conditions 9c21dee17SSøren Schmidt * are met: 10c21dee17SSøren Schmidt * 1. Redistributions of source code must retain the above copyright 110ba1b365SEd Maste * notice, this list of conditions and the following disclaimer. 12c21dee17SSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 13c21dee17SSøren Schmidt * notice, this list of conditions and the following disclaimer in the 14c21dee17SSøren Schmidt * documentation and/or other materials provided with the distribution. 15c21dee17SSøren Schmidt * 160ba1b365SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170ba1b365SEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180ba1b365SEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190ba1b365SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 200ba1b365SEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210ba1b365SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220ba1b365SEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230ba1b365SEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240ba1b365SEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250ba1b365SEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260ba1b365SEd Maste * SUCH DAMAGE. 27c21dee17SSøren Schmidt */ 28c21dee17SSøren Schmidt 2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h> 3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3116dbc7f2SDavid E. O'Brien 321f3dad5aSBruce Evans /* XXX we use functions that might not exist. */ 33aefce619SRuslan Ermilov #include "opt_compat.h" 34ca26842eSHajimu UMEMOTO #include "opt_inet6.h" 355591b823SEivind Eklund 36c21dee17SSøren Schmidt #include <sys/param.h> 37f2477ae1SMike Smith #include <sys/proc.h> 38c21dee17SSøren Schmidt #include <sys/systm.h> 391f3dad5aSBruce Evans #include <sys/sysproto.h> 404a144410SRobert Watson #include <sys/capsicum.h> 41dad3b88aSMike Smith #include <sys/fcntl.h> 420bf301c0SJonathan Lemon #include <sys/file.h> 43104a9b7eSAlexander Kabaev #include <sys/limits.h> 444641373fSJohn Baldwin #include <sys/lock.h> 45ca26842eSHajimu UMEMOTO #include <sys/malloc.h> 464641373fSJohn Baldwin #include <sys/mutex.h> 475a8a13e0SDavid Malone #include <sys/mbuf.h> 48c21dee17SSøren Schmidt #include <sys/socket.h> 490bf301c0SJonathan Lemon #include <sys/socketvar.h> 50ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h> 5108637435SBruce Evans #include <sys/uio.h> 52*fc7510aeSEd Maste #include <sys/stat.h> 53ca26842eSHajimu UMEMOTO #include <sys/syslog.h> 54d0b2365eSKonstantin Belousov #include <sys/un.h> 55*fc7510aeSEd Maste #include <sys/unistd.h> 56*fc7510aeSEd Maste 57*fc7510aeSEd Maste #include <security/audit/audit.h> 581f3dad5aSBruce Evans 594b79449eSBjoern A. Zeeb #include <net/if.h> 60eedc7fd9SGleb Smirnoff #include <net/vnet.h> 61c21dee17SSøren Schmidt #include <netinet/in.h> 62f2477ae1SMike Smith #include <netinet/in_systm.h> 63f2477ae1SMike Smith #include <netinet/ip.h> 64fb709557SJohn Baldwin #include <netinet/tcp.h> 65ca26842eSHajimu UMEMOTO #ifdef INET6 66ca26842eSHajimu UMEMOTO #include <netinet/ip6.h> 67ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h> 68ca26842eSHajimu UMEMOTO #endif 69c21dee17SSøren Schmidt 701997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32 714af27623STim J. Robbins #include <machine/../linux32/linux.h> 724af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h> 731997c537SDavid E. O'Brien #else 741997c537SDavid E. O'Brien #include <machine/../linux/linux.h> 751997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h> 764af27623STim J. Robbins #endif 77d5368bf3SDmitry Chagin #include <compat/linux/linux_common.h> 784d0f380dSDmitry Chagin #include <compat/linux/linux_file.h> 79da6d8ae6SEdward Tomasz Napierala #include <compat/linux/linux_mib.h> 8040dbba57SAssar Westerlund #include <compat/linux/linux_socket.h> 81e1ff74c0SDmitry Chagin #include <compat/linux/linux_timer.h> 82ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h> 83c21dee17SSøren Schmidt 84e1ff74c0SDmitry Chagin static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *, 85e1ff74c0SDmitry Chagin l_uint); 86e1ff74c0SDmitry Chagin static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *, 87e1ff74c0SDmitry Chagin l_uint, struct msghdr *); 884cf10e29SDmitry Chagin static int linux_set_socket_flags(int, int *); 89ca26842eSHajimu UMEMOTO 90ca26842eSHajimu UMEMOTO 91c21dee17SSøren Schmidt static int 92c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level) 93c21dee17SSøren Schmidt { 943f3a4815SMarcel Moolenaar 95c21dee17SSøren Schmidt switch (level) { 96c21dee17SSøren Schmidt case LINUX_SOL_SOCKET: 973f3a4815SMarcel Moolenaar return (SOL_SOCKET); 98c21dee17SSøren Schmidt } 993f3a4815SMarcel Moolenaar return (level); 100c21dee17SSøren Schmidt } 101c21dee17SSøren Schmidt 1023f3a4815SMarcel Moolenaar static int 10384b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level) 10484b11cd8SMitsuru IWASAKI { 10584b11cd8SMitsuru IWASAKI 10684b11cd8SMitsuru IWASAKI switch (level) { 10784b11cd8SMitsuru IWASAKI case SOL_SOCKET: 10884b11cd8SMitsuru IWASAKI return (LINUX_SOL_SOCKET); 10984b11cd8SMitsuru IWASAKI } 11084b11cd8SMitsuru IWASAKI return (level); 11184b11cd8SMitsuru IWASAKI } 11284b11cd8SMitsuru IWASAKI 11384b11cd8SMitsuru IWASAKI static int 1143f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt) 115c21dee17SSøren Schmidt { 1163f3a4815SMarcel Moolenaar 117c21dee17SSøren Schmidt switch (opt) { 118c21dee17SSøren Schmidt case LINUX_IP_TOS: 1193f3a4815SMarcel Moolenaar return (IP_TOS); 120c21dee17SSøren Schmidt case LINUX_IP_TTL: 1213f3a4815SMarcel Moolenaar return (IP_TTL); 12266ff6a3cSBill Fenner case LINUX_IP_OPTIONS: 1233f3a4815SMarcel Moolenaar return (IP_OPTIONS); 12466ff6a3cSBill Fenner case LINUX_IP_MULTICAST_IF: 1253f3a4815SMarcel Moolenaar return (IP_MULTICAST_IF); 12666ff6a3cSBill Fenner case LINUX_IP_MULTICAST_TTL: 1273f3a4815SMarcel Moolenaar return (IP_MULTICAST_TTL); 12866ff6a3cSBill Fenner case LINUX_IP_MULTICAST_LOOP: 1293f3a4815SMarcel Moolenaar return (IP_MULTICAST_LOOP); 13066ff6a3cSBill Fenner case LINUX_IP_ADD_MEMBERSHIP: 1313f3a4815SMarcel Moolenaar return (IP_ADD_MEMBERSHIP); 13266ff6a3cSBill Fenner case LINUX_IP_DROP_MEMBERSHIP: 1333f3a4815SMarcel Moolenaar return (IP_DROP_MEMBERSHIP); 13466ff6a3cSBill Fenner case LINUX_IP_HDRINCL: 1353f3a4815SMarcel Moolenaar return (IP_HDRINCL); 136c21dee17SSøren Schmidt } 1373f3a4815SMarcel Moolenaar return (-1); 138c21dee17SSøren Schmidt } 139c21dee17SSøren Schmidt 140c21dee17SSøren Schmidt static int 14186a9058bSAndrey V. Elsukov linux_to_bsd_ip6_sockopt(int opt) 14286a9058bSAndrey V. Elsukov { 14386a9058bSAndrey V. Elsukov 14486a9058bSAndrey V. Elsukov switch (opt) { 14586a9058bSAndrey V. Elsukov case LINUX_IPV6_NEXTHOP: 14686a9058bSAndrey V. Elsukov return (IPV6_NEXTHOP); 14786a9058bSAndrey V. Elsukov case LINUX_IPV6_UNICAST_HOPS: 14886a9058bSAndrey V. Elsukov return (IPV6_UNICAST_HOPS); 14986a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_IF: 15086a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_IF); 15186a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_HOPS: 15286a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_HOPS); 15386a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_LOOP: 15486a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_LOOP); 15586a9058bSAndrey V. Elsukov case LINUX_IPV6_ADD_MEMBERSHIP: 15686a9058bSAndrey V. Elsukov return (IPV6_JOIN_GROUP); 15786a9058bSAndrey V. Elsukov case LINUX_IPV6_DROP_MEMBERSHIP: 15886a9058bSAndrey V. Elsukov return (IPV6_LEAVE_GROUP); 15986a9058bSAndrey V. Elsukov case LINUX_IPV6_V6ONLY: 16086a9058bSAndrey V. Elsukov return (IPV6_V6ONLY); 16186a9058bSAndrey V. Elsukov case LINUX_IPV6_DONTFRAG: 16286a9058bSAndrey V. Elsukov return (IPV6_DONTFRAG); 16386a9058bSAndrey V. Elsukov #if 0 16486a9058bSAndrey V. Elsukov case LINUX_IPV6_CHECKSUM: 16586a9058bSAndrey V. Elsukov return (IPV6_CHECKSUM); 16686a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPKTINFO: 16786a9058bSAndrey V. Elsukov return (IPV6_RECVPKTINFO); 16886a9058bSAndrey V. Elsukov case LINUX_IPV6_PKTINFO: 16986a9058bSAndrey V. Elsukov return (IPV6_PKTINFO); 17086a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPLIMIT: 17186a9058bSAndrey V. Elsukov return (IPV6_RECVHOPLIMIT); 17286a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPLIMIT: 17386a9058bSAndrey V. Elsukov return (IPV6_HOPLIMIT); 17486a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPOPTS: 17586a9058bSAndrey V. Elsukov return (IPV6_RECVHOPOPTS); 17686a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPOPTS: 17786a9058bSAndrey V. Elsukov return (IPV6_HOPOPTS); 17886a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDRDSTOPTS: 17986a9058bSAndrey V. Elsukov return (IPV6_RTHDRDSTOPTS); 18086a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVRTHDR: 18186a9058bSAndrey V. Elsukov return (IPV6_RECVRTHDR); 18286a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDR: 18386a9058bSAndrey V. Elsukov return (IPV6_RTHDR); 18486a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVDSTOPTS: 18586a9058bSAndrey V. Elsukov return (IPV6_RECVDSTOPTS); 18686a9058bSAndrey V. Elsukov case LINUX_IPV6_DSTOPTS: 18786a9058bSAndrey V. Elsukov return (IPV6_DSTOPTS); 18886a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPATHMTU: 18986a9058bSAndrey V. Elsukov return (IPV6_RECVPATHMTU); 19086a9058bSAndrey V. Elsukov case LINUX_IPV6_PATHMTU: 19186a9058bSAndrey V. Elsukov return (IPV6_PATHMTU); 19286a9058bSAndrey V. Elsukov #endif 19386a9058bSAndrey V. Elsukov } 19486a9058bSAndrey V. Elsukov return (-1); 19586a9058bSAndrey V. Elsukov } 19686a9058bSAndrey V. Elsukov 19786a9058bSAndrey V. Elsukov static int 198c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt) 199c21dee17SSøren Schmidt { 2003f3a4815SMarcel Moolenaar 201c21dee17SSøren Schmidt switch (opt) { 202c21dee17SSøren Schmidt case LINUX_SO_DEBUG: 2033f3a4815SMarcel Moolenaar return (SO_DEBUG); 204c21dee17SSøren Schmidt case LINUX_SO_REUSEADDR: 2053f3a4815SMarcel Moolenaar return (SO_REUSEADDR); 206c21dee17SSøren Schmidt case LINUX_SO_TYPE: 2073f3a4815SMarcel Moolenaar return (SO_TYPE); 208c21dee17SSøren Schmidt case LINUX_SO_ERROR: 2093f3a4815SMarcel Moolenaar return (SO_ERROR); 210c21dee17SSøren Schmidt case LINUX_SO_DONTROUTE: 2113f3a4815SMarcel Moolenaar return (SO_DONTROUTE); 212c21dee17SSøren Schmidt case LINUX_SO_BROADCAST: 2133f3a4815SMarcel Moolenaar return (SO_BROADCAST); 214c21dee17SSøren Schmidt case LINUX_SO_SNDBUF: 2153f3a4815SMarcel Moolenaar return (SO_SNDBUF); 216c21dee17SSøren Schmidt case LINUX_SO_RCVBUF: 2173f3a4815SMarcel Moolenaar return (SO_RCVBUF); 218c21dee17SSøren Schmidt case LINUX_SO_KEEPALIVE: 2193f3a4815SMarcel Moolenaar return (SO_KEEPALIVE); 220c21dee17SSøren Schmidt case LINUX_SO_OOBINLINE: 2213f3a4815SMarcel Moolenaar return (SO_OOBINLINE); 222c21dee17SSøren Schmidt case LINUX_SO_LINGER: 2233f3a4815SMarcel Moolenaar return (SO_LINGER); 224d0b2365eSKonstantin Belousov case LINUX_SO_PEERCRED: 225d0b2365eSKonstantin Belousov return (LOCAL_PEERCRED); 226d0b2365eSKonstantin Belousov case LINUX_SO_RCVLOWAT: 227d0b2365eSKonstantin Belousov return (SO_RCVLOWAT); 228d0b2365eSKonstantin Belousov case LINUX_SO_SNDLOWAT: 229d0b2365eSKonstantin Belousov return (SO_SNDLOWAT); 230d0b2365eSKonstantin Belousov case LINUX_SO_RCVTIMEO: 231d0b2365eSKonstantin Belousov return (SO_RCVTIMEO); 232d0b2365eSKonstantin Belousov case LINUX_SO_SNDTIMEO: 233d0b2365eSKonstantin Belousov return (SO_SNDTIMEO); 234d0b2365eSKonstantin Belousov case LINUX_SO_TIMESTAMP: 235d0b2365eSKonstantin Belousov return (SO_TIMESTAMP); 236d0b2365eSKonstantin Belousov case LINUX_SO_ACCEPTCONN: 237d0b2365eSKonstantin Belousov return (SO_ACCEPTCONN); 238c21dee17SSøren Schmidt } 2393f3a4815SMarcel Moolenaar return (-1); 240c21dee17SSøren Schmidt } 241c21dee17SSøren Schmidt 24240dbba57SAssar Westerlund static int 243fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt) 244fb709557SJohn Baldwin { 245fb709557SJohn Baldwin 246fb709557SJohn Baldwin switch (opt) { 247fb709557SJohn Baldwin case LINUX_TCP_NODELAY: 248fb709557SJohn Baldwin return (TCP_NODELAY); 249fb709557SJohn Baldwin case LINUX_TCP_MAXSEG: 250fb709557SJohn Baldwin return (TCP_MAXSEG); 251c2d47457SEdward Tomasz Napierala case LINUX_TCP_CORK: 252c2d47457SEdward Tomasz Napierala return (TCP_NOPUSH); 253fb709557SJohn Baldwin case LINUX_TCP_KEEPIDLE: 254fb709557SJohn Baldwin return (TCP_KEEPIDLE); 255fb709557SJohn Baldwin case LINUX_TCP_KEEPINTVL: 256fb709557SJohn Baldwin return (TCP_KEEPINTVL); 257fb709557SJohn Baldwin case LINUX_TCP_KEEPCNT: 258fb709557SJohn Baldwin return (TCP_KEEPCNT); 259fb709557SJohn Baldwin case LINUX_TCP_MD5SIG: 260fb709557SJohn Baldwin return (TCP_MD5SIG); 261fb709557SJohn Baldwin } 262fb709557SJohn Baldwin return (-1); 263fb709557SJohn Baldwin } 264fb709557SJohn Baldwin 265fb709557SJohn Baldwin static int 26640dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags) 26740dbba57SAssar Westerlund { 26840dbba57SAssar Westerlund int ret_flags = 0; 26940dbba57SAssar Westerlund 27040dbba57SAssar Westerlund if (flags & LINUX_MSG_OOB) 27140dbba57SAssar Westerlund ret_flags |= MSG_OOB; 27240dbba57SAssar Westerlund if (flags & LINUX_MSG_PEEK) 27340dbba57SAssar Westerlund ret_flags |= MSG_PEEK; 27440dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTROUTE) 27540dbba57SAssar Westerlund ret_flags |= MSG_DONTROUTE; 27640dbba57SAssar Westerlund if (flags & LINUX_MSG_CTRUNC) 27740dbba57SAssar Westerlund ret_flags |= MSG_CTRUNC; 27840dbba57SAssar Westerlund if (flags & LINUX_MSG_TRUNC) 27940dbba57SAssar Westerlund ret_flags |= MSG_TRUNC; 28040dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTWAIT) 28140dbba57SAssar Westerlund ret_flags |= MSG_DONTWAIT; 28240dbba57SAssar Westerlund if (flags & LINUX_MSG_EOR) 28340dbba57SAssar Westerlund ret_flags |= MSG_EOR; 28440dbba57SAssar Westerlund if (flags & LINUX_MSG_WAITALL) 28540dbba57SAssar Westerlund ret_flags |= MSG_WAITALL; 2868d6e40c3SMaxim Sobolev if (flags & LINUX_MSG_NOSIGNAL) 2878d6e40c3SMaxim Sobolev ret_flags |= MSG_NOSIGNAL; 28840dbba57SAssar Westerlund #if 0 /* not handled */ 28940dbba57SAssar Westerlund if (flags & LINUX_MSG_PROXY) 29040dbba57SAssar Westerlund ; 29140dbba57SAssar Westerlund if (flags & LINUX_MSG_FIN) 29240dbba57SAssar Westerlund ; 29340dbba57SAssar Westerlund if (flags & LINUX_MSG_SYN) 29440dbba57SAssar Westerlund ; 29540dbba57SAssar Westerlund if (flags & LINUX_MSG_CONFIRM) 29640dbba57SAssar Westerlund ; 29740dbba57SAssar Westerlund if (flags & LINUX_MSG_RST) 29840dbba57SAssar Westerlund ; 29940dbba57SAssar Westerlund if (flags & LINUX_MSG_ERRQUEUE) 30040dbba57SAssar Westerlund ; 30140dbba57SAssar Westerlund #endif 302e667ee63SDmitry Chagin return (ret_flags); 30340dbba57SAssar Westerlund } 30440dbba57SAssar Westerlund 3055a8a13e0SDavid Malone static int 30674f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type) 3075a8a13e0SDavid Malone { 30874f5d680SKonstantin Belousov 30974f5d680SKonstantin Belousov switch (cmsg_type) { 31074f5d680SKonstantin Belousov case LINUX_SCM_RIGHTS: 31174f5d680SKonstantin Belousov return (SCM_RIGHTS); 312605da56bSAndriy Gapon case LINUX_SCM_CREDENTIALS: 313605da56bSAndriy Gapon return (SCM_CREDS); 31474f5d680SKonstantin Belousov } 31574f5d680SKonstantin Belousov return (-1); 31674f5d680SKonstantin Belousov } 31774f5d680SKonstantin Belousov 31874f5d680SKonstantin Belousov static int 31974f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type) 32074f5d680SKonstantin Belousov { 32174f5d680SKonstantin Belousov 32274f5d680SKonstantin Belousov switch (cmsg_type) { 32374f5d680SKonstantin Belousov case SCM_RIGHTS: 32474f5d680SKonstantin Belousov return (LINUX_SCM_RIGHTS); 325605da56bSAndriy Gapon case SCM_CREDS: 326605da56bSAndriy Gapon return (LINUX_SCM_CREDENTIALS); 327bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 328bbf392d5SDmitry Chagin return (LINUX_SCM_TIMESTAMP); 32974f5d680SKonstantin Belousov } 33074f5d680SKonstantin Belousov return (-1); 33174f5d680SKonstantin Belousov } 33274f5d680SKonstantin Belousov 33374f5d680SKonstantin Belousov static int 33474f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 33574f5d680SKonstantin Belousov { 33674f5d680SKonstantin Belousov if (lhdr->msg_controllen > INT_MAX) 33774f5d680SKonstantin Belousov return (ENOBUFS); 33874f5d680SKonstantin Belousov 33974f5d680SKonstantin Belousov bhdr->msg_name = PTRIN(lhdr->msg_name); 34074f5d680SKonstantin Belousov bhdr->msg_namelen = lhdr->msg_namelen; 34174f5d680SKonstantin Belousov bhdr->msg_iov = PTRIN(lhdr->msg_iov); 34274f5d680SKonstantin Belousov bhdr->msg_iovlen = lhdr->msg_iovlen; 34374f5d680SKonstantin Belousov bhdr->msg_control = PTRIN(lhdr->msg_control); 344605da56bSAndriy Gapon 345605da56bSAndriy Gapon /* 346605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 347605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 348605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 349605da56bSAndriy Gapon * 350605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 351605da56bSAndriy Gapon * control messages. 352605da56bSAndriy Gapon */ 353605da56bSAndriy Gapon 35474f5d680SKonstantin Belousov bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 35574f5d680SKonstantin Belousov return (0); 35674f5d680SKonstantin Belousov } 35774f5d680SKonstantin Belousov 35874f5d680SKonstantin Belousov static int 35974f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 36074f5d680SKonstantin Belousov { 36174f5d680SKonstantin Belousov lhdr->msg_name = PTROUT(bhdr->msg_name); 36274f5d680SKonstantin Belousov lhdr->msg_namelen = bhdr->msg_namelen; 36374f5d680SKonstantin Belousov lhdr->msg_iov = PTROUT(bhdr->msg_iov); 36474f5d680SKonstantin Belousov lhdr->msg_iovlen = bhdr->msg_iovlen; 36574f5d680SKonstantin Belousov lhdr->msg_control = PTROUT(bhdr->msg_control); 366605da56bSAndriy Gapon 367605da56bSAndriy Gapon /* 368605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 369605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 370605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 371605da56bSAndriy Gapon * 372605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 373605da56bSAndriy Gapon * control messages. 374605da56bSAndriy Gapon */ 375605da56bSAndriy Gapon 37674f5d680SKonstantin Belousov /* msg_flags skipped */ 37774f5d680SKonstantin Belousov return (0); 37874f5d680SKonstantin Belousov } 37974f5d680SKonstantin Belousov 38074f5d680SKonstantin Belousov static int 3814cf10e29SDmitry Chagin linux_set_socket_flags(int lflags, int *flags) 38238a18e97SDmitry Chagin { 38338a18e97SDmitry Chagin 3844cf10e29SDmitry Chagin if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 3854cf10e29SDmitry Chagin return (EINVAL); 3864cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_NONBLOCK) 3874cf10e29SDmitry Chagin *flags |= SOCK_NONBLOCK; 3884cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_CLOEXEC) 3894cf10e29SDmitry Chagin *flags |= SOCK_CLOEXEC; 39038a18e97SDmitry Chagin return (0); 39138a18e97SDmitry Chagin } 39238a18e97SDmitry Chagin 39338a18e97SDmitry Chagin static int 39474f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 39574f5d680SKonstantin Belousov struct mbuf *control, enum uio_seg segflg) 39674f5d680SKonstantin Belousov { 3975a8a13e0SDavid Malone struct sockaddr *to; 398d5368bf3SDmitry Chagin int error, len; 3995a8a13e0SDavid Malone 4005a8a13e0SDavid Malone if (mp->msg_name != NULL) { 401d5368bf3SDmitry Chagin len = mp->msg_namelen; 402d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len); 403dddb7e7fSDmitry Chagin if (error != 0) 4045a8a13e0SDavid Malone return (error); 4055a8a13e0SDavid Malone mp->msg_name = to; 4065a8a13e0SDavid Malone } else 4075a8a13e0SDavid Malone to = NULL; 4085a8a13e0SDavid Malone 409a6886ef1SMaxim Sobolev error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 410a6886ef1SMaxim Sobolev segflg); 4115a8a13e0SDavid Malone 4125a8a13e0SDavid Malone if (to) 4131ede983cSDag-Erling Smørgrav free(to, M_SONAME); 4145a8a13e0SDavid Malone return (error); 4155a8a13e0SDavid Malone } 4165a8a13e0SDavid Malone 4173f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */ 418f2477ae1SMike Smith static int 419e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s) 420f2477ae1SMike Smith { 421857ad5a3SDmitry Chagin int error, optval; 422857ad5a3SDmitry Chagin socklen_t size_val; 423f2477ae1SMike Smith 424e140eb43SDavid Malone size_val = sizeof(optval); 425e140eb43SDavid Malone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 426e140eb43SDavid Malone &optval, UIO_SYSSPACE, &size_val); 427dddb7e7fSDmitry Chagin if (error != 0) 4283f3a4815SMarcel Moolenaar return (error); 4293f3a4815SMarcel Moolenaar 4303f3a4815SMarcel Moolenaar return (optval == 0); 431f2477ae1SMike Smith } 432f2477ae1SMike Smith 433f2477ae1SMike Smith /* 434f2477ae1SMike Smith * Updated sendto() when IP_HDRINCL is set: 435f2477ae1SMike Smith * tweak endian-dependent fields in the IP packet. 436f2477ae1SMike Smith */ 437f2477ae1SMike Smith static int 43838da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 439f2477ae1SMike Smith { 440f2477ae1SMike Smith /* 441f2477ae1SMike Smith * linux_ip_copysize defines how many bytes we should copy 442f2477ae1SMike Smith * from the beginning of the IP packet before we customize it for BSD. 443a6886ef1SMaxim Sobolev * It should include all the fields we modify (ip_len and ip_off). 444f2477ae1SMike Smith */ 445f2477ae1SMike Smith #define linux_ip_copysize 8 446f2477ae1SMike Smith 447f2477ae1SMike Smith struct ip *packet; 4485a8a13e0SDavid Malone struct msghdr msg; 449a6886ef1SMaxim Sobolev struct iovec aiov[1]; 450f2477ae1SMike Smith int error; 451f2477ae1SMike Smith 452aa675b57SDavid Schultz /* Check that the packet isn't too big or too small. */ 453aa675b57SDavid Schultz if (linux_args->len < linux_ip_copysize || 454aa675b57SDavid Schultz linux_args->len > IP_MAXPACKET) 4553f3a4815SMarcel Moolenaar return (EINVAL); 456f2477ae1SMike Smith 457e0d3ea8cSDmitry Chagin packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); 458f2477ae1SMike Smith 459a6886ef1SMaxim Sobolev /* Make kernel copy of the packet to be sent */ 4604af27623STim J. Robbins if ((error = copyin(PTRIN(linux_args->msg), packet, 461a6886ef1SMaxim Sobolev linux_args->len))) 462a6886ef1SMaxim Sobolev goto goout; 463f2477ae1SMike Smith 464f2477ae1SMike Smith /* Convert fields from Linux to BSD raw IP socket format */ 4655a8a13e0SDavid Malone packet->ip_len = linux_args->len; 466f2477ae1SMike Smith packet->ip_off = ntohs(packet->ip_off); 467f2477ae1SMike Smith 468f2477ae1SMike Smith /* Prepare the msghdr and iovec structures describing the new packet */ 4694af27623STim J. Robbins msg.msg_name = PTRIN(linux_args->to); 4705a8a13e0SDavid Malone msg.msg_namelen = linux_args->tolen; 4715a8a13e0SDavid Malone msg.msg_iov = aiov; 472a6886ef1SMaxim Sobolev msg.msg_iovlen = 1; 4735a8a13e0SDavid Malone msg.msg_control = NULL; 4745a8a13e0SDavid Malone msg.msg_flags = 0; 4755a8a13e0SDavid Malone aiov[0].iov_base = (char *)packet; 476a6886ef1SMaxim Sobolev aiov[0].iov_len = linux_args->len; 477a6886ef1SMaxim Sobolev error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 47874f5d680SKonstantin Belousov NULL, UIO_SYSSPACE); 479a6886ef1SMaxim Sobolev goout: 480e0d3ea8cSDmitry Chagin free(packet, M_LINUX); 4815a8a13e0SDavid Malone return (error); 482f2477ae1SMike Smith } 483f2477ae1SMike Smith 484a12b9b3dSDmitry Chagin int 485b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args) 486c21dee17SSøren Schmidt { 487d293f35cSEdward Tomasz Napierala int domain, retval_socket, type; 488c21dee17SSøren Schmidt 489d293f35cSEdward Tomasz Napierala type = args->type & LINUX_SOCK_TYPE_MASK; 490d293f35cSEdward Tomasz Napierala if (type < 0 || type > LINUX_SOCK_MAX) 491eeb63e51SDmitry Chagin return (EINVAL); 4924cf10e29SDmitry Chagin retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 493d293f35cSEdward Tomasz Napierala &type); 4944cf10e29SDmitry Chagin if (retval_socket != 0) 4954cf10e29SDmitry Chagin return (retval_socket); 496d293f35cSEdward Tomasz Napierala domain = linux_to_bsd_domain(args->domain); 497d293f35cSEdward Tomasz Napierala if (domain == -1) 498d9b063ccSDmitry Chagin return (EAFNOSUPPORT); 499f2477ae1SMike Smith 500d293f35cSEdward Tomasz Napierala retval_socket = kern_socket(td, domain, type, args->protocol); 5016994ea54SDmitry Chagin if (retval_socket) 5026994ea54SDmitry Chagin return (retval_socket); 5036994ea54SDmitry Chagin 504d293f35cSEdward Tomasz Napierala if (type == SOCK_RAW 505d293f35cSEdward Tomasz Napierala && (args->protocol == IPPROTO_RAW || args->protocol == 0) 506d293f35cSEdward Tomasz Napierala && domain == PF_INET) { 507f2477ae1SMike Smith /* It's a raw IP socket: set the IP_HDRINCL option. */ 508e140eb43SDavid Malone int hdrincl; 509f2477ae1SMike Smith 510e140eb43SDavid Malone hdrincl = 1; 511e140eb43SDavid Malone /* We ignore any error returned by kern_setsockopt() */ 512e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 513e140eb43SDavid Malone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 514f2477ae1SMike Smith } 515ca26842eSHajimu UMEMOTO #ifdef INET6 516ca26842eSHajimu UMEMOTO /* 517d97bee3eSBjoern A. Zeeb * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default 518d97bee3eSBjoern A. Zeeb * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. 519d97bee3eSBjoern A. Zeeb * For simplicity we do this unconditionally of the net.inet6.ip6.v6only 520d97bee3eSBjoern A. Zeeb * sysctl value. 521ca26842eSHajimu UMEMOTO */ 522d293f35cSEdward Tomasz Napierala if (domain == PF_INET6) { 523e140eb43SDavid Malone int v6only; 524ca26842eSHajimu UMEMOTO 525e140eb43SDavid Malone v6only = 0; 526ca26842eSHajimu UMEMOTO /* We ignore any error returned by setsockopt() */ 527e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 528e140eb43SDavid Malone &v6only, UIO_SYSSPACE, sizeof(v6only)); 529ca26842eSHajimu UMEMOTO } 530ca26842eSHajimu UMEMOTO #endif 5313f3a4815SMarcel Moolenaar 5323f3a4815SMarcel Moolenaar return (retval_socket); 533c21dee17SSøren Schmidt } 534c21dee17SSøren Schmidt 535a12b9b3dSDmitry Chagin int 536b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args) 537c21dee17SSøren Schmidt { 538ca26842eSHajimu UMEMOTO struct sockaddr *sa; 539c21dee17SSøren Schmidt int error; 540c21dee17SSøren Schmidt 541d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, 542d5368bf3SDmitry Chagin &args->namelen); 543dddb7e7fSDmitry Chagin if (error != 0) 544ca26842eSHajimu UMEMOTO return (error); 545ca26842eSHajimu UMEMOTO 5466e646651SKonstantin Belousov error = kern_bindat(td, AT_FDCWD, args->s, sa); 547b33887eaSJohn Baldwin free(sa, M_SONAME); 548d5368bf3SDmitry Chagin 549d5368bf3SDmitry Chagin /* XXX */ 550745aaef5SKonstantin Belousov if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 551d4b7423fSAlexander Leidinger return (EINVAL); 552b33887eaSJohn Baldwin return (error); 553c21dee17SSøren Schmidt } 554c21dee17SSøren Schmidt 555930a65feSAndrew Gallatin int 556b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args) 557c21dee17SSøren Schmidt { 5580bf301c0SJonathan Lemon struct socket *so; 559ca26842eSHajimu UMEMOTO struct sockaddr *sa; 56095653579SGleb Smirnoff struct file *fp; 56139c95b83SMatthew Dillon u_int fflag; 562c21dee17SSøren Schmidt int error; 563c21dee17SSøren Schmidt 564d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, 565d5368bf3SDmitry Chagin &args->namelen); 566dddb7e7fSDmitry Chagin if (error != 0) 567ca26842eSHajimu UMEMOTO return (error); 568ca26842eSHajimu UMEMOTO 5696e646651SKonstantin Belousov error = kern_connectat(td, AT_FDCWD, args->s, sa); 570b33887eaSJohn Baldwin free(sa, M_SONAME); 5710bf301c0SJonathan Lemon if (error != EISCONN) 5720bf301c0SJonathan Lemon return (error); 5730bf301c0SJonathan Lemon 574dad3b88aSMike Smith /* 575dad3b88aSMike Smith * Linux doesn't return EISCONN the first time it occurs, 576dad3b88aSMike Smith * when on a non-blocking socket. Instead it returns the 577dad3b88aSMike Smith * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 578dad3b88aSMike Smith */ 579cbd92ce6SMatt Macy error = getsock_cap(td, args->s, &cap_connect_rights, 58095653579SGleb Smirnoff &fp, &fflag, NULL); 58195653579SGleb Smirnoff if (error != 0) 58295653579SGleb Smirnoff return (error); 58395653579SGleb Smirnoff 5840bf301c0SJonathan Lemon error = EISCONN; 58595653579SGleb Smirnoff so = fp->f_data; 58639c95b83SMatthew Dillon if (fflag & FNONBLOCK) { 5874641373fSJohn Baldwin SOCK_LOCK(so); 5885002a60fSMarcel Moolenaar if (so->so_emuldata == 0) 5890bf301c0SJonathan Lemon error = so->so_error; 5900bf301c0SJonathan Lemon so->so_emuldata = (void *)1; 5914641373fSJohn Baldwin SOCK_UNLOCK(so); 592dad3b88aSMike Smith } 59395653579SGleb Smirnoff fdrop(fp, td); 59495653579SGleb Smirnoff 5953f3a4815SMarcel Moolenaar return (error); 596c21dee17SSøren Schmidt } 597c21dee17SSøren Schmidt 598a12b9b3dSDmitry Chagin int 599b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args) 600c21dee17SSøren Schmidt { 601c21dee17SSøren Schmidt 602d293f35cSEdward Tomasz Napierala return (kern_listen(td, args->s, args->backlog)); 603c21dee17SSøren Schmidt } 604c21dee17SSøren Schmidt 60501e0ffbaSAlexander Leidinger static int 606c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr, 607f83427b8SDmitry Chagin l_uintptr_t namelen, int flags) 608c21dee17SSøren Schmidt { 609d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 610d5368bf3SDmitry Chagin struct sockaddr *sa; 611fc4b98fbSDmitry Chagin struct file *fp; 612d5368bf3SDmitry Chagin int bflags, len; 613d5368bf3SDmitry Chagin struct socket *so; 614fc4b98fbSDmitry Chagin int error, error1; 61593e694c9SDmitry Chagin 616d5368bf3SDmitry Chagin bflags = 0; 617d5368bf3SDmitry Chagin error = linux_set_socket_flags(flags, &bflags); 6184cf10e29SDmitry Chagin if (error != 0) 6194cf10e29SDmitry Chagin return (error); 620d5368bf3SDmitry Chagin 621d5368bf3SDmitry Chagin sa = NULL; 622d5368bf3SDmitry Chagin if (PTRIN(addr) == NULL) { 623d5368bf3SDmitry Chagin len = 0; 624d5368bf3SDmitry Chagin error = kern_accept4(td, s, NULL, NULL, bflags, NULL); 625d5368bf3SDmitry Chagin } else { 626d5368bf3SDmitry Chagin error = copyin(PTRIN(namelen), &len, sizeof(len)); 627d5368bf3SDmitry Chagin if (error != 0) 628d5368bf3SDmitry Chagin return (error); 629d5368bf3SDmitry Chagin if (len < 0) 630d4b7423fSAlexander Leidinger return (EINVAL); 631d5368bf3SDmitry Chagin error = kern_accept4(td, s, &sa, &len, bflags, &fp); 632d5368bf3SDmitry Chagin if (error == 0) 633d5368bf3SDmitry Chagin fdrop(fp, td); 634d5368bf3SDmitry Chagin } 635d5368bf3SDmitry Chagin 636d5368bf3SDmitry Chagin if (error != 0) { 637d5368bf3SDmitry Chagin /* 638d5368bf3SDmitry Chagin * XXX. This is wrong, different sockaddr structures 639d5368bf3SDmitry Chagin * have different sizes. 640d5368bf3SDmitry Chagin */ 641d5368bf3SDmitry Chagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 642d5368bf3SDmitry Chagin { 643d5368bf3SDmitry Chagin error = EINVAL; 644d5368bf3SDmitry Chagin goto out; 645d5368bf3SDmitry Chagin } 646fc4b98fbSDmitry Chagin if (error == EINVAL) { 647cbd92ce6SMatt Macy error1 = getsock_cap(td, s, &cap_accept_rights, &fp, NULL, NULL); 648d5368bf3SDmitry Chagin if (error1 != 0) { 649d5368bf3SDmitry Chagin error = error1; 650d5368bf3SDmitry Chagin goto out; 651d5368bf3SDmitry Chagin } 65291f514e4SDmitry Chagin so = fp->f_data; 653d5368bf3SDmitry Chagin if (so->so_type == SOCK_DGRAM) 654d5368bf3SDmitry Chagin error = EOPNOTSUPP; 65591f514e4SDmitry Chagin fdrop(fp, td); 65691f514e4SDmitry Chagin } 657d5368bf3SDmitry Chagin goto out; 658d4b7423fSAlexander Leidinger } 659d5368bf3SDmitry Chagin 660d5368bf3SDmitry Chagin if (len != 0 && error == 0) { 661d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 662d5368bf3SDmitry Chagin if (error == 0) 663d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(addr), len); 664d5368bf3SDmitry Chagin free(lsa, M_SONAME); 665d5368bf3SDmitry Chagin } 666d5368bf3SDmitry Chagin 667d5368bf3SDmitry Chagin free(sa, M_SONAME); 668d5368bf3SDmitry Chagin 669d5368bf3SDmitry Chagin out: 670dddb7e7fSDmitry Chagin if (error != 0) { 67193e694c9SDmitry Chagin (void)kern_close(td, td->td_retval[0]); 67293e694c9SDmitry Chagin td->td_retval[0] = 0; 67393e694c9SDmitry Chagin } 67493e694c9SDmitry Chagin return (error); 675c21dee17SSøren Schmidt } 676c21dee17SSøren Schmidt 677a12b9b3dSDmitry Chagin int 678c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args) 679c8f37d61SDmitry Chagin { 680c8f37d61SDmitry Chagin 681c8f37d61SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 682f83427b8SDmitry Chagin args->namelen, 0)); 683c8f37d61SDmitry Chagin } 684c8f37d61SDmitry Chagin 685a12b9b3dSDmitry Chagin int 686f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args) 687f8cd0af2SDmitry Chagin { 688f8cd0af2SDmitry Chagin 689f8cd0af2SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 690f8cd0af2SDmitry Chagin args->namelen, args->flags)); 691f8cd0af2SDmitry Chagin } 692f8cd0af2SDmitry Chagin 693a12b9b3dSDmitry Chagin int 694b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 695c21dee17SSøren Schmidt { 696d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 697d5368bf3SDmitry Chagin struct sockaddr *sa; 698d5368bf3SDmitry Chagin int len, error; 699c21dee17SSøren Schmidt 700d5368bf3SDmitry Chagin error = copyin(PTRIN(args->namelen), &len, sizeof(len)); 701dddb7e7fSDmitry Chagin if (error != 0) 702ca26842eSHajimu UMEMOTO return (error); 703d5368bf3SDmitry Chagin 704d5368bf3SDmitry Chagin error = kern_getsockname(td, args->s, &sa, &len); 705d5368bf3SDmitry Chagin if (error != 0) 706d5368bf3SDmitry Chagin return (error); 707d5368bf3SDmitry Chagin 708d5368bf3SDmitry Chagin if (len != 0) { 709d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 710d5368bf3SDmitry Chagin if (error == 0) 711d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->addr), 712d5368bf3SDmitry Chagin len); 713d5368bf3SDmitry Chagin free(lsa, M_SONAME); 714d5368bf3SDmitry Chagin } 715d5368bf3SDmitry Chagin 716d5368bf3SDmitry Chagin free(sa, M_SONAME); 717d5368bf3SDmitry Chagin if (error == 0) 718d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->namelen), sizeof(len)); 719d5368bf3SDmitry Chagin return (error); 720c21dee17SSøren Schmidt } 721c21dee17SSøren Schmidt 722a12b9b3dSDmitry Chagin int 723b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 724c21dee17SSøren Schmidt { 725d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 726d5368bf3SDmitry Chagin struct sockaddr *sa; 727d5368bf3SDmitry Chagin int len, error; 728c21dee17SSøren Schmidt 729d5368bf3SDmitry Chagin error = copyin(PTRIN(args->namelen), &len, sizeof(len)); 730dddb7e7fSDmitry Chagin if (error != 0) 731ca26842eSHajimu UMEMOTO return (error); 732caaad873SDmitry Chagin if (len < 0) 733caaad873SDmitry Chagin return (EINVAL); 734d5368bf3SDmitry Chagin 735d5368bf3SDmitry Chagin error = kern_getpeername(td, args->s, &sa, &len); 736d5368bf3SDmitry Chagin if (error != 0) 737d5368bf3SDmitry Chagin return (error); 738d5368bf3SDmitry Chagin 739d5368bf3SDmitry Chagin if (len != 0) { 740d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 741d5368bf3SDmitry Chagin if (error == 0) 742d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->addr), 743d5368bf3SDmitry Chagin len); 744d5368bf3SDmitry Chagin free(lsa, M_SONAME); 745d5368bf3SDmitry Chagin } 746d5368bf3SDmitry Chagin 747d5368bf3SDmitry Chagin free(sa, M_SONAME); 748d5368bf3SDmitry Chagin if (error == 0) 749d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->namelen), sizeof(len)); 750d5368bf3SDmitry Chagin return (error); 751c21dee17SSøren Schmidt } 752c21dee17SSøren Schmidt 753a12b9b3dSDmitry Chagin int 754b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 755c21dee17SSøren Schmidt { 756ef04503dSPeter Wemm struct socketpair_args /* { 757c21dee17SSøren Schmidt int domain; 758c21dee17SSøren Schmidt int type; 759c21dee17SSøren Schmidt int protocol; 760c21dee17SSøren Schmidt int *rsv; 761ef04503dSPeter Wemm } */ bsd_args; 7624cf10e29SDmitry Chagin int error; 763c21dee17SSøren Schmidt 764745aaef5SKonstantin Belousov bsd_args.domain = linux_to_bsd_domain(args->domain); 7651a52a4abSDmitry Chagin if (bsd_args.domain != PF_LOCAL) 7661a52a4abSDmitry Chagin return (EAFNOSUPPORT); 76739253cf9SDmitry Chagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 76839253cf9SDmitry Chagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 76939253cf9SDmitry Chagin return (EINVAL); 7704cf10e29SDmitry Chagin error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 7714cf10e29SDmitry Chagin &bsd_args.type); 7724cf10e29SDmitry Chagin if (error != 0) 7734cf10e29SDmitry Chagin return (error); 7741a52a4abSDmitry Chagin if (args->protocol != 0 && args->protocol != PF_UNIX) 7751a52a4abSDmitry Chagin 7761a52a4abSDmitry Chagin /* 7771a52a4abSDmitry Chagin * Use of PF_UNIX as protocol argument is not right, 7781a52a4abSDmitry Chagin * but Linux does it. 7791a52a4abSDmitry Chagin * Do not map PF_UNIX as its Linux value is identical 7801a52a4abSDmitry Chagin * to FreeBSD one. 7811a52a4abSDmitry Chagin */ 7821a52a4abSDmitry Chagin return (EPROTONOSUPPORT); 78340092d93SDmitry Chagin else 7841a52a4abSDmitry Chagin bsd_args.protocol = 0; 785745aaef5SKonstantin Belousov bsd_args.rsv = (int *)PTRIN(args->rsv); 7864cf10e29SDmitry Chagin return (sys_socketpair(td, &bsd_args)); 787c21dee17SSøren Schmidt } 788c21dee17SSøren Schmidt 789a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 79001e0ffbaSAlexander Leidinger struct linux_send_args { 79156fba8e6SDmitry Chagin register_t s; 79256fba8e6SDmitry Chagin register_t msg; 79356fba8e6SDmitry Chagin register_t len; 79456fba8e6SDmitry Chagin register_t flags; 795c21dee17SSøren Schmidt }; 796c21dee17SSøren Schmidt 79701e0ffbaSAlexander Leidinger static int 798b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args) 799c21dee17SSøren Schmidt { 80087d72a8fSPoul-Henning Kamp struct sendto_args /* { 801c21dee17SSøren Schmidt int s; 802c21dee17SSøren Schmidt caddr_t buf; 803044af7c3SJonathan Mini int len; 804c21dee17SSøren Schmidt int flags; 80587d72a8fSPoul-Henning Kamp caddr_t to; 80687d72a8fSPoul-Henning Kamp int tolen; 807ef04503dSPeter Wemm } */ bsd_args; 808aa288712SDmitry Chagin struct file *fp; 809aa288712SDmitry Chagin int error, fflag; 810c21dee17SSøren Schmidt 811745aaef5SKonstantin Belousov bsd_args.s = args->s; 812745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 813745aaef5SKonstantin Belousov bsd_args.len = args->len; 814745aaef5SKonstantin Belousov bsd_args.flags = args->flags; 81587d72a8fSPoul-Henning Kamp bsd_args.to = NULL; 81687d72a8fSPoul-Henning Kamp bsd_args.tolen = 0; 817aa288712SDmitry Chagin error = sys_sendto(td, &bsd_args); 818aa288712SDmitry Chagin if (error == ENOTCONN) { 819aa288712SDmitry Chagin /* 820aa288712SDmitry Chagin * Linux doesn't return ENOTCONN for non-blocking sockets. 821aa288712SDmitry Chagin * Instead it returns the EAGAIN. 822aa288712SDmitry Chagin */ 823aa288712SDmitry Chagin error = getsock_cap(td, args->s, &cap_send_rights, &fp, 824aa288712SDmitry Chagin &fflag, NULL); 825aa288712SDmitry Chagin if (error == 0) { 826aa288712SDmitry Chagin if (fflag & FNONBLOCK) 827aa288712SDmitry Chagin error = EAGAIN; 828aa288712SDmitry Chagin fdrop(fp, td); 829aa288712SDmitry Chagin } 830aa288712SDmitry Chagin } 831aa288712SDmitry Chagin return (error); 832c21dee17SSøren Schmidt } 833c21dee17SSøren Schmidt 83401e0ffbaSAlexander Leidinger struct linux_recv_args { 83556fba8e6SDmitry Chagin register_t s; 83656fba8e6SDmitry Chagin register_t msg; 83756fba8e6SDmitry Chagin register_t len; 83856fba8e6SDmitry Chagin register_t flags; 839c21dee17SSøren Schmidt }; 840c21dee17SSøren Schmidt 84101e0ffbaSAlexander Leidinger static int 842b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args) 843c21dee17SSøren Schmidt { 84487d72a8fSPoul-Henning Kamp struct recvfrom_args /* { 845c21dee17SSøren Schmidt int s; 846c21dee17SSøren Schmidt caddr_t buf; 847c21dee17SSøren Schmidt int len; 848c21dee17SSøren Schmidt int flags; 84987d72a8fSPoul-Henning Kamp struct sockaddr *from; 85087d72a8fSPoul-Henning Kamp socklen_t fromlenaddr; 851ef04503dSPeter Wemm } */ bsd_args; 852c21dee17SSøren Schmidt 853745aaef5SKonstantin Belousov bsd_args.s = args->s; 854745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 855745aaef5SKonstantin Belousov bsd_args.len = args->len; 8563980a435SDmitry Chagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 85787d72a8fSPoul-Henning Kamp bsd_args.from = NULL; 85887d72a8fSPoul-Henning Kamp bsd_args.fromlenaddr = 0; 8598451d0ddSKip Macy return (sys_recvfrom(td, &bsd_args)); 860c21dee17SSøren Schmidt } 861a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 862c21dee17SSøren Schmidt 863a12b9b3dSDmitry Chagin int 864b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args) 865c21dee17SSøren Schmidt { 8665a8a13e0SDavid Malone struct msghdr msg; 8675a8a13e0SDavid Malone struct iovec aiov; 868c21dee17SSøren Schmidt 869745aaef5SKonstantin Belousov if (linux_check_hdrincl(td, args->s) == 0) 870f2477ae1SMike Smith /* IP_HDRINCL set, tweak the packet before sending */ 871745aaef5SKonstantin Belousov return (linux_sendto_hdrincl(td, args)); 872f2477ae1SMike Smith 873745aaef5SKonstantin Belousov msg.msg_name = PTRIN(args->to); 874745aaef5SKonstantin Belousov msg.msg_namelen = args->tolen; 8755a8a13e0SDavid Malone msg.msg_iov = &aiov; 8765a8a13e0SDavid Malone msg.msg_iovlen = 1; 8775a8a13e0SDavid Malone msg.msg_control = NULL; 8785a8a13e0SDavid Malone msg.msg_flags = 0; 879745aaef5SKonstantin Belousov aiov.iov_base = PTRIN(args->msg); 880745aaef5SKonstantin Belousov aiov.iov_len = args->len; 881e667ee63SDmitry Chagin return (linux_sendit(td, args->s, &msg, args->flags, NULL, 882e667ee63SDmitry Chagin UIO_USERSPACE)); 883c21dee17SSøren Schmidt } 884c21dee17SSøren Schmidt 885a12b9b3dSDmitry Chagin int 886b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 887c21dee17SSøren Schmidt { 888d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 889d5368bf3SDmitry Chagin struct sockaddr *sa; 8909599b0ecSDmitry Chagin struct msghdr msg; 8919599b0ecSDmitry Chagin struct iovec aiov; 8923a49978fSDmitry Chagin int error, fromlen; 893c21dee17SSøren Schmidt 8949599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL) { 8953a49978fSDmitry Chagin error = copyin(PTRIN(args->fromlen), &fromlen, 8963a49978fSDmitry Chagin sizeof(fromlen)); 8979599b0ecSDmitry Chagin if (error != 0) 8983f3a4815SMarcel Moolenaar return (error); 8993a49978fSDmitry Chagin if (fromlen < 0) 9003a49978fSDmitry Chagin return (EINVAL); 901d5368bf3SDmitry Chagin sa = malloc(fromlen, M_SONAME, M_WAITOK); 902d5368bf3SDmitry Chagin } else { 903d5368bf3SDmitry Chagin fromlen = 0; 904d5368bf3SDmitry Chagin sa = NULL; 905d5368bf3SDmitry Chagin } 9069599b0ecSDmitry Chagin 907d5368bf3SDmitry Chagin msg.msg_name = sa; 908d5368bf3SDmitry Chagin msg.msg_namelen = fromlen; 9099599b0ecSDmitry Chagin msg.msg_iov = &aiov; 9109599b0ecSDmitry Chagin msg.msg_iovlen = 1; 9119599b0ecSDmitry Chagin aiov.iov_base = PTRIN(args->buf); 9129599b0ecSDmitry Chagin aiov.iov_len = args->len; 9139599b0ecSDmitry Chagin msg.msg_control = 0; 9149599b0ecSDmitry Chagin msg.msg_flags = linux_to_bsd_msg_flags(args->flags); 9159599b0ecSDmitry Chagin 916d5368bf3SDmitry Chagin error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL); 9179599b0ecSDmitry Chagin if (error != 0) 918dcd62418SDmitry Chagin goto out; 9199599b0ecSDmitry Chagin 9209599b0ecSDmitry Chagin if (PTRIN(args->from) != NULL) { 921d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, msg.msg_namelen); 922d5368bf3SDmitry Chagin if (error == 0) 923d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->from), 924d5368bf3SDmitry Chagin msg.msg_namelen); 925d5368bf3SDmitry Chagin free(lsa, M_SONAME); 926ca26842eSHajimu UMEMOTO } 9279599b0ecSDmitry Chagin 928d5368bf3SDmitry Chagin if (error == 0 && PTRIN(args->fromlen) != NULL) 9299599b0ecSDmitry Chagin error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), 9309599b0ecSDmitry Chagin sizeof(msg.msg_namelen)); 931dcd62418SDmitry Chagin out: 932d5368bf3SDmitry Chagin free(sa, M_SONAME); 9339599b0ecSDmitry Chagin return (error); 934ca26842eSHajimu UMEMOTO } 935ca26842eSHajimu UMEMOTO 936e1ff74c0SDmitry Chagin static int 937e1ff74c0SDmitry Chagin linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 938e1ff74c0SDmitry Chagin l_uint flags) 939ca26842eSHajimu UMEMOTO { 94074f5d680SKonstantin Belousov struct cmsghdr *cmsg; 94174f5d680SKonstantin Belousov struct mbuf *control; 942ca26842eSHajimu UMEMOTO struct msghdr msg; 94374f5d680SKonstantin Belousov struct l_cmsghdr linux_cmsg; 94474f5d680SKonstantin Belousov struct l_cmsghdr *ptr_cmsg; 94574f5d680SKonstantin Belousov struct l_msghdr linux_msg; 946552afd9cSPoul-Henning Kamp struct iovec *iov; 94774f5d680SKonstantin Belousov socklen_t datalen; 948605da56bSAndriy Gapon struct sockaddr *sa; 9491410bfe1SDmitry Chagin struct socket *so; 950605da56bSAndriy Gapon sa_family_t sa_family; 9511410bfe1SDmitry Chagin struct file *fp; 95274f5d680SKonstantin Belousov void *data; 953e3b385fcSTijl Coosemans l_size_t len; 9547df0e7beSTijl Coosemans l_size_t clen; 9551410bfe1SDmitry Chagin int error, fflag; 956ca26842eSHajimu UMEMOTO 957e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 958e1ff74c0SDmitry Chagin if (error != 0) 95974f5d680SKonstantin Belousov return (error); 960d72a6158SRobert Watson 961d72a6158SRobert Watson /* 962d72a6158SRobert Watson * Some Linux applications (ping) define a non-NULL control data 963d72a6158SRobert Watson * pointer, but a msg_controllen of 0, which is not allowed in the 964d72a6158SRobert Watson * FreeBSD system call interface. NULL the msg_control pointer in 965d72a6158SRobert Watson * order to handle this case. This should be checked, but allows the 966d72a6158SRobert Watson * Linux ping to work. 967d72a6158SRobert Watson */ 968605da56bSAndriy Gapon if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) 969605da56bSAndriy Gapon linux_msg.msg_control = PTROUT(NULL); 970605da56bSAndriy Gapon 971605da56bSAndriy Gapon error = linux_to_bsd_msghdr(&msg, &linux_msg); 972e1ff74c0SDmitry Chagin if (error != 0) 973605da56bSAndriy Gapon return (error); 97474f5d680SKonstantin Belousov 97574f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 97674f5d680SKonstantin Belousov error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 97774f5d680SKonstantin Belousov &iov, EMSGSIZE); 97874f5d680SKonstantin Belousov #else 979552afd9cSPoul-Henning Kamp error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 98074f5d680SKonstantin Belousov #endif 981e1ff74c0SDmitry Chagin if (error != 0) 982552afd9cSPoul-Henning Kamp return (error); 98374f5d680SKonstantin Belousov 984605da56bSAndriy Gapon control = NULL; 985605da56bSAndriy Gapon 986e1ff74c0SDmitry Chagin error = kern_getsockname(td, s, &sa, &datalen); 987e1ff74c0SDmitry Chagin if (error != 0) 988605da56bSAndriy Gapon goto bad; 989605da56bSAndriy Gapon sa_family = sa->sa_family; 990605da56bSAndriy Gapon free(sa, M_SONAME); 991605da56bSAndriy Gapon 9921410bfe1SDmitry Chagin if (flags & LINUX_MSG_OOB) { 9931410bfe1SDmitry Chagin error = EOPNOTSUPP; 9941410bfe1SDmitry Chagin if (sa_family == AF_UNIX) 9951410bfe1SDmitry Chagin goto bad; 9961410bfe1SDmitry Chagin 9971410bfe1SDmitry Chagin error = getsock_cap(td, s, &cap_send_rights, &fp, 9981410bfe1SDmitry Chagin &fflag, NULL); 9991410bfe1SDmitry Chagin if (error != 0) 10001410bfe1SDmitry Chagin goto bad; 10011410bfe1SDmitry Chagin so = fp->f_data; 10021410bfe1SDmitry Chagin if (so->so_type != SOCK_STREAM) 10031410bfe1SDmitry Chagin error = EOPNOTSUPP; 10041410bfe1SDmitry Chagin fdrop(fp, td); 10051410bfe1SDmitry Chagin if (error != 0) 10061410bfe1SDmitry Chagin goto bad; 10071410bfe1SDmitry Chagin } 10081410bfe1SDmitry Chagin 10091410bfe1SDmitry Chagin if (linux_msg.msg_controllen >= sizeof(struct l_cmsghdr)) { 10101410bfe1SDmitry Chagin 101174f5d680SKonstantin Belousov error = ENOBUFS; 1012eb1b1807SGleb Smirnoff control = m_get(M_WAITOK, MT_CONTROL); 1013e3b385fcSTijl Coosemans MCLGET(control, M_WAITOK); 1014e3b385fcSTijl Coosemans data = mtod(control, void *); 1015e3b385fcSTijl Coosemans datalen = 0; 101674f5d680SKonstantin Belousov 10177df0e7beSTijl Coosemans ptr_cmsg = PTRIN(linux_msg.msg_control); 10187df0e7beSTijl Coosemans clen = linux_msg.msg_controllen; 101974f5d680SKonstantin Belousov do { 102074f5d680SKonstantin Belousov error = copyin(ptr_cmsg, &linux_cmsg, 102174f5d680SKonstantin Belousov sizeof(struct l_cmsghdr)); 1022e1ff74c0SDmitry Chagin if (error != 0) 102374f5d680SKonstantin Belousov goto bad; 102474f5d680SKonstantin Belousov 102574f5d680SKonstantin Belousov error = EINVAL; 10267df0e7beSTijl Coosemans if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || 10277df0e7beSTijl Coosemans linux_cmsg.cmsg_len > clen) 102874f5d680SKonstantin Belousov goto bad; 102974f5d680SKonstantin Belousov 1030e3b385fcSTijl Coosemans if (datalen + CMSG_HDRSZ > MCLBYTES) 1031e3b385fcSTijl Coosemans goto bad; 1032e3b385fcSTijl Coosemans 103374f5d680SKonstantin Belousov /* 1034605da56bSAndriy Gapon * Now we support only SCM_RIGHTS and SCM_CRED, 1035605da56bSAndriy Gapon * so return EINVAL in any other cmsg_type 103674f5d680SKonstantin Belousov */ 1037e3b385fcSTijl Coosemans cmsg = data; 1038605da56bSAndriy Gapon cmsg->cmsg_type = 1039605da56bSAndriy Gapon linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); 104074f5d680SKonstantin Belousov cmsg->cmsg_level = 104174f5d680SKonstantin Belousov linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1042605da56bSAndriy Gapon if (cmsg->cmsg_type == -1 1043605da56bSAndriy Gapon || cmsg->cmsg_level != SOL_SOCKET) 1044605da56bSAndriy Gapon goto bad; 104574f5d680SKonstantin Belousov 1046605da56bSAndriy Gapon /* 1047605da56bSAndriy Gapon * Some applications (e.g. pulseaudio) attempt to 1048605da56bSAndriy Gapon * send ancillary data even if the underlying protocol 1049605da56bSAndriy Gapon * doesn't support it which is not allowed in the 1050605da56bSAndriy Gapon * FreeBSD system call interface. 1051605da56bSAndriy Gapon */ 1052605da56bSAndriy Gapon if (sa_family != AF_UNIX) 1053605da56bSAndriy Gapon continue; 1054605da56bSAndriy Gapon 1055e3b385fcSTijl Coosemans if (cmsg->cmsg_type == SCM_CREDS) { 1056e3b385fcSTijl Coosemans len = sizeof(struct cmsgcred); 1057e3b385fcSTijl Coosemans if (datalen + CMSG_SPACE(len) > MCLBYTES) 1058e3b385fcSTijl Coosemans goto bad; 1059605da56bSAndriy Gapon 1060605da56bSAndriy Gapon /* 1061605da56bSAndriy Gapon * The lower levels will fill in the structure 1062605da56bSAndriy Gapon */ 1063e3b385fcSTijl Coosemans memset(CMSG_DATA(data), 0, len); 1064e3b385fcSTijl Coosemans } else { 1065e3b385fcSTijl Coosemans len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1066e3b385fcSTijl Coosemans if (datalen + CMSG_SPACE(len) < datalen || 1067e3b385fcSTijl Coosemans datalen + CMSG_SPACE(len) > MCLBYTES) 1068e3b385fcSTijl Coosemans goto bad; 1069e3b385fcSTijl Coosemans 1070e3b385fcSTijl Coosemans error = copyin(LINUX_CMSG_DATA(ptr_cmsg), 1071e3b385fcSTijl Coosemans CMSG_DATA(data), len); 1072e3b385fcSTijl Coosemans if (error != 0) 1073e3b385fcSTijl Coosemans goto bad; 1074605da56bSAndriy Gapon } 1075605da56bSAndriy Gapon 1076e3b385fcSTijl Coosemans cmsg->cmsg_len = CMSG_LEN(len); 1077e3b385fcSTijl Coosemans data = (char *)data + CMSG_SPACE(len); 1078e3b385fcSTijl Coosemans datalen += CMSG_SPACE(len); 10797df0e7beSTijl Coosemans 10807df0e7beSTijl Coosemans if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)) 10817df0e7beSTijl Coosemans break; 10827df0e7beSTijl Coosemans 10837df0e7beSTijl Coosemans clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len); 10847df0e7beSTijl Coosemans ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg + 10857df0e7beSTijl Coosemans LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)); 10867df0e7beSTijl Coosemans } while(clen >= sizeof(struct l_cmsghdr)); 1087605da56bSAndriy Gapon 1088e3b385fcSTijl Coosemans control->m_len = datalen; 1089e3b385fcSTijl Coosemans if (datalen == 0) { 1090605da56bSAndriy Gapon m_freem(control); 109174f5d680SKonstantin Belousov control = NULL; 1092605da56bSAndriy Gapon } 109374f5d680SKonstantin Belousov } 109474f5d680SKonstantin Belousov 10955a8a13e0SDavid Malone msg.msg_iov = iov; 10965a8a13e0SDavid Malone msg.msg_flags = 0; 1097e1ff74c0SDmitry Chagin error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); 109867968b35SDmitry Chagin control = NULL; 109974f5d680SKonstantin Belousov 110074f5d680SKonstantin Belousov bad: 11014f65e9cfSDmitry Chagin m_freem(control); 1102552afd9cSPoul-Henning Kamp free(iov, M_IOV); 1103ca26842eSHajimu UMEMOTO return (error); 1104c21dee17SSøren Schmidt } 1105c21dee17SSøren Schmidt 1106a12b9b3dSDmitry Chagin int 1107e1ff74c0SDmitry Chagin linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1108e1ff74c0SDmitry Chagin { 1109e1ff74c0SDmitry Chagin 1110e1ff74c0SDmitry Chagin return (linux_sendmsg_common(td, args->s, PTRIN(args->msg), 1111e1ff74c0SDmitry Chagin args->flags)); 1112e1ff74c0SDmitry Chagin } 1113e1ff74c0SDmitry Chagin 1114e1ff74c0SDmitry Chagin int 1115e1ff74c0SDmitry Chagin linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) 1116e1ff74c0SDmitry Chagin { 1117e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1118e1ff74c0SDmitry Chagin l_uint retval; 1119e1ff74c0SDmitry Chagin int error, datagrams; 1120e1ff74c0SDmitry Chagin 1121e1ff74c0SDmitry Chagin if (args->vlen > UIO_MAXIOV) 1122e1ff74c0SDmitry Chagin args->vlen = UIO_MAXIOV; 1123e1ff74c0SDmitry Chagin 1124e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1125e1ff74c0SDmitry Chagin datagrams = 0; 1126e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1127e1ff74c0SDmitry Chagin error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, 1128e1ff74c0SDmitry Chagin args->flags); 1129e1ff74c0SDmitry Chagin if (error != 0) 1130e1ff74c0SDmitry Chagin break; 1131e1ff74c0SDmitry Chagin 1132e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1133e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1134e1ff74c0SDmitry Chagin if (error != 0) 1135e1ff74c0SDmitry Chagin break; 1136e1ff74c0SDmitry Chagin ++msg; 1137e1ff74c0SDmitry Chagin ++datagrams; 1138e1ff74c0SDmitry Chagin } 1139e1ff74c0SDmitry Chagin if (error == 0) 1140e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1141e1ff74c0SDmitry Chagin return (error); 1142e1ff74c0SDmitry Chagin } 1143e1ff74c0SDmitry Chagin 1144e1ff74c0SDmitry Chagin static int 1145e1ff74c0SDmitry Chagin linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1146e1ff74c0SDmitry Chagin l_uint flags, struct msghdr *msg) 114740dbba57SAssar Westerlund { 114874f5d680SKonstantin Belousov struct cmsghdr *cm; 1149605da56bSAndriy Gapon struct cmsgcred *cmcred; 115074f5d680SKonstantin Belousov struct l_cmsghdr *linux_cmsg = NULL; 1151605da56bSAndriy Gapon struct l_ucred linux_ucred; 1152c7902fbeSMark Johnston socklen_t datalen, maxlen, outlen; 115374f5d680SKonstantin Belousov struct l_msghdr linux_msg; 115474f5d680SKonstantin Belousov struct iovec *iov, *uiov; 115574f5d680SKonstantin Belousov struct mbuf *control = NULL; 115674f5d680SKonstantin Belousov struct mbuf **controlp; 1157bbf392d5SDmitry Chagin struct timeval *ftmvl; 1158d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 1159d5368bf3SDmitry Chagin struct sockaddr *sa; 1160bbf392d5SDmitry Chagin l_timeval ltmvl; 116174f5d680SKonstantin Belousov caddr_t outbuf; 116274f5d680SKonstantin Belousov void *data; 11633a72bf04SDmitry Chagin int error, i, fd, fds, *fdp; 116440dbba57SAssar Westerlund 1165e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1166e1ff74c0SDmitry Chagin if (error != 0) 1167ca26842eSHajimu UMEMOTO return (error); 1168ca26842eSHajimu UMEMOTO 1169e1ff74c0SDmitry Chagin error = linux_to_bsd_msghdr(msg, &linux_msg); 1170e1ff74c0SDmitry Chagin if (error != 0) 117174f5d680SKonstantin Belousov return (error); 117274f5d680SKonstantin Belousov 117374f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 1174e1ff74c0SDmitry Chagin error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, 117574f5d680SKonstantin Belousov &iov, EMSGSIZE); 117674f5d680SKonstantin Belousov #else 1177e1ff74c0SDmitry Chagin error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); 117874f5d680SKonstantin Belousov #endif 1179e1ff74c0SDmitry Chagin if (error != 0) 118074f5d680SKonstantin Belousov return (error); 118174f5d680SKonstantin Belousov 1182e1ff74c0SDmitry Chagin if (msg->msg_name) { 1183d5368bf3SDmitry Chagin sa = malloc(msg->msg_namelen, M_SONAME, M_WAITOK); 1184d5368bf3SDmitry Chagin msg->msg_name = sa; 11858128cfc5SDmitry Chagin } else 11868128cfc5SDmitry Chagin sa = NULL; 118784b11cd8SMitsuru IWASAKI 1188e1ff74c0SDmitry Chagin uiov = msg->msg_iov; 1189e1ff74c0SDmitry Chagin msg->msg_iov = iov; 1190e1ff74c0SDmitry Chagin controlp = (msg->msg_control != NULL) ? &control : NULL; 1191d5368bf3SDmitry Chagin error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp); 1192e1ff74c0SDmitry Chagin msg->msg_iov = uiov; 1193e1ff74c0SDmitry Chagin if (error != 0) 119474f5d680SKonstantin Belousov goto bad; 119574f5d680SKonstantin Belousov 119657cb29a7SDmitry Chagin if (msg->msg_name) { 1197d5368bf3SDmitry Chagin msg->msg_name = PTRIN(linux_msg.msg_name); 1198d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, msg->msg_namelen); 1199d5368bf3SDmitry Chagin if (error == 0) 1200d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(msg->msg_name), 1201d5368bf3SDmitry Chagin msg->msg_namelen); 1202d5368bf3SDmitry Chagin free(lsa, M_SONAME); 1203d5368bf3SDmitry Chagin if (error != 0) 1204d5368bf3SDmitry Chagin goto bad; 1205d5368bf3SDmitry Chagin } 1206d5368bf3SDmitry Chagin 1207e1ff74c0SDmitry Chagin error = bsd_to_linux_msghdr(msg, &linux_msg); 1208e1ff74c0SDmitry Chagin if (error != 0) 120974f5d680SKonstantin Belousov goto bad; 121074f5d680SKonstantin Belousov 1211c7902fbeSMark Johnston maxlen = linux_msg.msg_controllen; 1212c7902fbeSMark Johnston linux_msg.msg_controllen = 0; 1213605da56bSAndriy Gapon if (control) { 1214e0d3ea8cSDmitry Chagin linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); 1215605da56bSAndriy Gapon 1216e1ff74c0SDmitry Chagin msg->msg_control = mtod(control, struct cmsghdr *); 1217e1ff74c0SDmitry Chagin msg->msg_controllen = control->m_len; 1218605da56bSAndriy Gapon 1219e1ff74c0SDmitry Chagin cm = CMSG_FIRSTHDR(msg); 1220c7902fbeSMark Johnston outbuf = PTRIN(linux_msg.msg_control); 1221c7902fbeSMark Johnston outlen = 0; 122274f5d680SKonstantin Belousov while (cm != NULL) { 1223605da56bSAndriy Gapon linux_cmsg->cmsg_type = 1224605da56bSAndriy Gapon bsd_to_linux_cmsg_type(cm->cmsg_type); 1225605da56bSAndriy Gapon linux_cmsg->cmsg_level = 1226605da56bSAndriy Gapon bsd_to_linux_sockopt_level(cm->cmsg_level); 1227c7902fbeSMark Johnston if (linux_cmsg->cmsg_type == -1 || 1228c7902fbeSMark Johnston cm->cmsg_level != SOL_SOCKET) { 122974f5d680SKonstantin Belousov error = EINVAL; 123074f5d680SKonstantin Belousov goto bad; 123174f5d680SKonstantin Belousov } 1232605da56bSAndriy Gapon 123374f5d680SKonstantin Belousov data = CMSG_DATA(cm); 123474f5d680SKonstantin Belousov datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 123574f5d680SKonstantin Belousov 1236c7902fbeSMark Johnston switch (cm->cmsg_type) { 1237605da56bSAndriy Gapon case SCM_RIGHTS: 1238e1ff74c0SDmitry Chagin if (flags & LINUX_MSG_CMSG_CLOEXEC) { 1239605da56bSAndriy Gapon fds = datalen / sizeof(int); 1240605da56bSAndriy Gapon fdp = data; 1241605da56bSAndriy Gapon for (i = 0; i < fds; i++) { 1242605da56bSAndriy Gapon fd = *fdp++; 1243605da56bSAndriy Gapon (void)kern_fcntl(td, fd, 1244605da56bSAndriy Gapon F_SETFD, FD_CLOEXEC); 1245605da56bSAndriy Gapon } 1246605da56bSAndriy Gapon } 1247605da56bSAndriy Gapon break; 1248605da56bSAndriy Gapon 1249605da56bSAndriy Gapon case SCM_CREDS: 1250605da56bSAndriy Gapon /* 1251605da56bSAndriy Gapon * Currently LOCAL_CREDS is never in 1252605da56bSAndriy Gapon * effect for Linux so no need to worry 1253605da56bSAndriy Gapon * about sockcred 1254605da56bSAndriy Gapon */ 1255605da56bSAndriy Gapon if (datalen != sizeof(*cmcred)) { 1256605da56bSAndriy Gapon error = EMSGSIZE; 1257605da56bSAndriy Gapon goto bad; 1258605da56bSAndriy Gapon } 1259605da56bSAndriy Gapon cmcred = (struct cmsgcred *)data; 1260605da56bSAndriy Gapon bzero(&linux_ucred, sizeof(linux_ucred)); 1261605da56bSAndriy Gapon linux_ucred.pid = cmcred->cmcred_pid; 1262605da56bSAndriy Gapon linux_ucred.uid = cmcred->cmcred_uid; 1263605da56bSAndriy Gapon linux_ucred.gid = cmcred->cmcred_gid; 1264605da56bSAndriy Gapon data = &linux_ucred; 1265605da56bSAndriy Gapon datalen = sizeof(linux_ucred); 1266605da56bSAndriy Gapon break; 1267bbf392d5SDmitry Chagin 1268bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 1269bbf392d5SDmitry Chagin if (datalen != sizeof(struct timeval)) { 1270bbf392d5SDmitry Chagin error = EMSGSIZE; 1271bbf392d5SDmitry Chagin goto bad; 1272bbf392d5SDmitry Chagin } 1273bbf392d5SDmitry Chagin ftmvl = (struct timeval *)data; 1274bbf392d5SDmitry Chagin ltmvl.tv_sec = ftmvl->tv_sec; 1275bbf392d5SDmitry Chagin ltmvl.tv_usec = ftmvl->tv_usec; 1276bbf392d5SDmitry Chagin data = <mvl; 1277bbf392d5SDmitry Chagin datalen = sizeof(ltmvl); 1278bbf392d5SDmitry Chagin break; 1279605da56bSAndriy Gapon } 1280605da56bSAndriy Gapon 1281c7902fbeSMark Johnston if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) { 128274f5d680SKonstantin Belousov if (outlen == 0) { 128374f5d680SKonstantin Belousov error = EMSGSIZE; 128474f5d680SKonstantin Belousov goto bad; 128574f5d680SKonstantin Belousov } else { 1286c7902fbeSMark Johnston linux_msg.msg_flags |= LINUX_MSG_CTRUNC; 1287c7902fbeSMark Johnston m_dispose_extcontrolm(control); 128874f5d680SKonstantin Belousov goto out; 128974f5d680SKonstantin Belousov } 129074f5d680SKonstantin Belousov } 129174f5d680SKonstantin Belousov 129274f5d680SKonstantin Belousov linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 129374f5d680SKonstantin Belousov 129474f5d680SKonstantin Belousov error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1295dddb7e7fSDmitry Chagin if (error != 0) 129674f5d680SKonstantin Belousov goto bad; 129774f5d680SKonstantin Belousov outbuf += L_CMSG_HDRSZ; 129874f5d680SKonstantin Belousov 129974f5d680SKonstantin Belousov error = copyout(data, outbuf, datalen); 1300dddb7e7fSDmitry Chagin if (error != 0) 130174f5d680SKonstantin Belousov goto bad; 130274f5d680SKonstantin Belousov 130374f5d680SKonstantin Belousov outbuf += LINUX_CMSG_ALIGN(datalen); 130474f5d680SKonstantin Belousov outlen += LINUX_CMSG_LEN(datalen); 130574f5d680SKonstantin Belousov 1306e1ff74c0SDmitry Chagin cm = CMSG_NXTHDR(msg, cm); 130774f5d680SKonstantin Belousov } 1308c7902fbeSMark Johnston linux_msg.msg_controllen = outlen; 130974f5d680SKonstantin Belousov } 131074f5d680SKonstantin Belousov 131174f5d680SKonstantin Belousov out: 1312e1ff74c0SDmitry Chagin error = copyout(&linux_msg, msghdr, sizeof(linux_msg)); 131374f5d680SKonstantin Belousov 131474f5d680SKonstantin Belousov bad: 1315c7902fbeSMark Johnston if (control != NULL) { 1316c7902fbeSMark Johnston if (error != 0) 1317c7902fbeSMark Johnston m_dispose_extcontrolm(control); 131874f5d680SKonstantin Belousov m_freem(control); 1319c7902fbeSMark Johnston } 1320c7902fbeSMark Johnston free(iov, M_IOV); 1321e0d3ea8cSDmitry Chagin free(linux_cmsg, M_LINUX); 13228128cfc5SDmitry Chagin free(sa, M_SONAME); 132374f5d680SKonstantin Belousov 1324ca26842eSHajimu UMEMOTO return (error); 132540dbba57SAssar Westerlund } 132640dbba57SAssar Westerlund 1327a12b9b3dSDmitry Chagin int 1328e1ff74c0SDmitry Chagin linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1329e1ff74c0SDmitry Chagin { 1330e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1331e1ff74c0SDmitry Chagin 1332e1ff74c0SDmitry Chagin return (linux_recvmsg_common(td, args->s, PTRIN(args->msg), 1333e1ff74c0SDmitry Chagin args->flags, &bsd_msg)); 1334e1ff74c0SDmitry Chagin } 1335e1ff74c0SDmitry Chagin 1336e1ff74c0SDmitry Chagin int 1337e1ff74c0SDmitry Chagin linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) 1338e1ff74c0SDmitry Chagin { 1339e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1340e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1341e1ff74c0SDmitry Chagin struct l_timespec lts; 1342e1ff74c0SDmitry Chagin struct timespec ts, tts; 1343e1ff74c0SDmitry Chagin l_uint retval; 1344e1ff74c0SDmitry Chagin int error, datagrams; 1345e1ff74c0SDmitry Chagin 1346e1ff74c0SDmitry Chagin if (args->timeout) { 1347e1ff74c0SDmitry Chagin error = copyin(args->timeout, <s, sizeof(struct l_timespec)); 1348e1ff74c0SDmitry Chagin if (error != 0) 1349e1ff74c0SDmitry Chagin return (error); 1350e1ff74c0SDmitry Chagin error = linux_to_native_timespec(&ts, <s); 1351e1ff74c0SDmitry Chagin if (error != 0) 1352e1ff74c0SDmitry Chagin return (error); 1353e1ff74c0SDmitry Chagin getnanotime(&tts); 13546040822cSAlan Somers timespecadd(&tts, &ts, &tts); 1355e1ff74c0SDmitry Chagin } 1356e1ff74c0SDmitry Chagin 1357e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1358e1ff74c0SDmitry Chagin datagrams = 0; 1359e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1360e1ff74c0SDmitry Chagin error = linux_recvmsg_common(td, args->s, &msg->msg_hdr, 1361e1ff74c0SDmitry Chagin args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); 1362e1ff74c0SDmitry Chagin if (error != 0) 1363e1ff74c0SDmitry Chagin break; 1364e1ff74c0SDmitry Chagin 1365e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1366e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1367e1ff74c0SDmitry Chagin if (error != 0) 1368e1ff74c0SDmitry Chagin break; 1369e1ff74c0SDmitry Chagin ++msg; 1370e1ff74c0SDmitry Chagin ++datagrams; 1371e1ff74c0SDmitry Chagin 1372e1ff74c0SDmitry Chagin /* 1373e1ff74c0SDmitry Chagin * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. 1374e1ff74c0SDmitry Chagin */ 1375e1ff74c0SDmitry Chagin if (args->flags & LINUX_MSG_WAITFORONE) 1376e1ff74c0SDmitry Chagin args->flags |= LINUX_MSG_DONTWAIT; 1377e1ff74c0SDmitry Chagin 1378e1ff74c0SDmitry Chagin /* 1379e1ff74c0SDmitry Chagin * See BUGS section of recvmmsg(2). 1380e1ff74c0SDmitry Chagin */ 1381e1ff74c0SDmitry Chagin if (args->timeout) { 1382e1ff74c0SDmitry Chagin getnanotime(&ts); 13836040822cSAlan Somers timespecsub(&ts, &tts, &ts); 1384e1ff74c0SDmitry Chagin if (!timespecisset(&ts) || ts.tv_sec > 0) 1385e1ff74c0SDmitry Chagin break; 1386e1ff74c0SDmitry Chagin } 1387e1ff74c0SDmitry Chagin /* Out of band data, return right away. */ 1388e1ff74c0SDmitry Chagin if (bsd_msg.msg_flags & MSG_OOB) 1389e1ff74c0SDmitry Chagin break; 1390e1ff74c0SDmitry Chagin } 1391e1ff74c0SDmitry Chagin if (error == 0) 1392e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1393e1ff74c0SDmitry Chagin return (error); 1394e1ff74c0SDmitry Chagin } 1395e1ff74c0SDmitry Chagin 1396e1ff74c0SDmitry Chagin int 1397b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1398c21dee17SSøren Schmidt { 1399c21dee17SSøren Schmidt 1400d293f35cSEdward Tomasz Napierala return (kern_shutdown(td, args->s, args->how)); 1401c21dee17SSøren Schmidt } 1402c21dee17SSøren Schmidt 1403a12b9b3dSDmitry Chagin int 1404b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1405c21dee17SSøren Schmidt { 140603cc95d2SDmitry Chagin l_timeval linux_tv; 1407d5368bf3SDmitry Chagin struct sockaddr *sa; 140803cc95d2SDmitry Chagin struct timeval tv; 1409d5368bf3SDmitry Chagin socklen_t len; 14109c6eb0f9SEdward Tomasz Napierala int error, level, name; 1411c21dee17SSøren Schmidt 14129c6eb0f9SEdward Tomasz Napierala level = linux_to_bsd_sockopt_level(args->level); 14139c6eb0f9SEdward Tomasz Napierala switch (level) { 1414c21dee17SSøren Schmidt case SOL_SOCKET: 1415745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 141603cc95d2SDmitry Chagin switch (name) { 141703cc95d2SDmitry Chagin case SO_RCVTIMEO: 141803cc95d2SDmitry Chagin /* FALLTHROUGH */ 141903cc95d2SDmitry Chagin case SO_SNDTIMEO: 142003cc95d2SDmitry Chagin error = copyin(PTRIN(args->optval), &linux_tv, 142103cc95d2SDmitry Chagin sizeof(linux_tv)); 1422dddb7e7fSDmitry Chagin if (error != 0) 142303cc95d2SDmitry Chagin return (error); 142403cc95d2SDmitry Chagin tv.tv_sec = linux_tv.tv_sec; 142503cc95d2SDmitry Chagin tv.tv_usec = linux_tv.tv_usec; 14269c6eb0f9SEdward Tomasz Napierala return (kern_setsockopt(td, args->s, level, 142703cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, sizeof(tv))); 142803cc95d2SDmitry Chagin /* NOTREACHED */ 142903cc95d2SDmitry Chagin default: 143003cc95d2SDmitry Chagin break; 143103cc95d2SDmitry Chagin } 1432c21dee17SSøren Schmidt break; 1433c21dee17SSøren Schmidt case IPPROTO_IP: 1434da6d8ae6SEdward Tomasz Napierala if (args->optname == LINUX_IP_RECVERR && 1435da6d8ae6SEdward Tomasz Napierala linux_ignore_ip_recverr) { 1436da6d8ae6SEdward Tomasz Napierala /* 1437da6d8ae6SEdward Tomasz Napierala * XXX: This is a hack to unbreak DNS resolution 1438da6d8ae6SEdward Tomasz Napierala * with glibc 2.30 and above. 1439da6d8ae6SEdward Tomasz Napierala */ 1440da6d8ae6SEdward Tomasz Napierala return (0); 1441da6d8ae6SEdward Tomasz Napierala } 1442745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1443c21dee17SSøren Schmidt break; 144486a9058bSAndrey V. Elsukov case IPPROTO_IPV6: 144586a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname); 144686a9058bSAndrey V. Elsukov break; 1447dad3b88aSMike Smith case IPPROTO_TCP: 1448fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1449dad3b88aSMike Smith break; 1450c21dee17SSøren Schmidt default: 14513f3a4815SMarcel Moolenaar name = -1; 14523f3a4815SMarcel Moolenaar break; 1453c21dee17SSøren Schmidt } 1454c21dee17SSøren Schmidt if (name == -1) 1455d4b7423fSAlexander Leidinger return (ENOPROTOOPT); 14563f3a4815SMarcel Moolenaar 1457d5368bf3SDmitry Chagin 1458d5368bf3SDmitry Chagin if (name == IPV6_NEXTHOP) { 1459d5368bf3SDmitry Chagin len = args->optlen; 1460d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->optval), &sa, &len); 1461d5368bf3SDmitry Chagin if (error != 0) 1462d5368bf3SDmitry Chagin return (error); 1463d5368bf3SDmitry Chagin 14649c6eb0f9SEdward Tomasz Napierala error = kern_setsockopt(td, args->s, level, 1465d5368bf3SDmitry Chagin name, sa, UIO_SYSSPACE, len); 1466d5368bf3SDmitry Chagin free(sa, M_SONAME); 1467d5368bf3SDmitry Chagin } else { 14689c6eb0f9SEdward Tomasz Napierala error = kern_setsockopt(td, args->s, level, 14699c6eb0f9SEdward Tomasz Napierala name, PTRIN(args->optval), UIO_USERSPACE, args->optlen); 1470d5368bf3SDmitry Chagin } 14715c8919adSAlexander Leidinger 14725c8919adSAlexander Leidinger return (error); 1473c21dee17SSøren Schmidt } 1474c21dee17SSøren Schmidt 1475a12b9b3dSDmitry Chagin int 1476b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1477c21dee17SSøren Schmidt { 147803cc95d2SDmitry Chagin l_timeval linux_tv; 147903cc95d2SDmitry Chagin struct timeval tv; 1480d56e689eSDmitry Chagin socklen_t tv_len, xulen, len; 1481d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 1482d5368bf3SDmitry Chagin struct sockaddr *sa; 1483d4dd69c4SDmitry Chagin struct xucred xu; 1484d4dd69c4SDmitry Chagin struct l_ucred lxu; 1485dfd060c0SEdward Tomasz Napierala int error, level, name, newval; 1486c21dee17SSøren Schmidt 1487dfd060c0SEdward Tomasz Napierala level = linux_to_bsd_sockopt_level(args->level); 1488dfd060c0SEdward Tomasz Napierala switch (level) { 1489c21dee17SSøren Schmidt case SOL_SOCKET: 1490745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 149103cc95d2SDmitry Chagin switch (name) { 149203cc95d2SDmitry Chagin case SO_RCVTIMEO: 149303cc95d2SDmitry Chagin /* FALLTHROUGH */ 149403cc95d2SDmitry Chagin case SO_SNDTIMEO: 149503cc95d2SDmitry Chagin tv_len = sizeof(tv); 1496dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 149703cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, &tv_len); 1498dddb7e7fSDmitry Chagin if (error != 0) 149903cc95d2SDmitry Chagin return (error); 150003cc95d2SDmitry Chagin linux_tv.tv_sec = tv.tv_sec; 150103cc95d2SDmitry Chagin linux_tv.tv_usec = tv.tv_usec; 150203cc95d2SDmitry Chagin return (copyout(&linux_tv, PTRIN(args->optval), 150303cc95d2SDmitry Chagin sizeof(linux_tv))); 150403cc95d2SDmitry Chagin /* NOTREACHED */ 1505d4dd69c4SDmitry Chagin case LOCAL_PEERCRED: 1506cd92d27eSDmitry Chagin if (args->optlen < sizeof(lxu)) 1507d4dd69c4SDmitry Chagin return (EINVAL); 1508bb376a99SMark Johnston /* 1509bb376a99SMark Johnston * LOCAL_PEERCRED is not served at the SOL_SOCKET level, 1510bb376a99SMark Johnston * but by the Unix socket's level 0. 1511bb376a99SMark Johnston */ 1512dfd060c0SEdward Tomasz Napierala level = 0; 1513d4dd69c4SDmitry Chagin xulen = sizeof(xu); 1514dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1515d4dd69c4SDmitry Chagin name, &xu, UIO_SYSSPACE, &xulen); 1516dddb7e7fSDmitry Chagin if (error != 0) 1517d4dd69c4SDmitry Chagin return (error); 1518c5afec6eSDmitry Chagin lxu.pid = xu.cr_pid; 1519d4dd69c4SDmitry Chagin lxu.uid = xu.cr_uid; 1520d4dd69c4SDmitry Chagin lxu.gid = xu.cr_gid; 1521d4dd69c4SDmitry Chagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1522d4dd69c4SDmitry Chagin /* NOTREACHED */ 1523d56e689eSDmitry Chagin case SO_ERROR: 1524d56e689eSDmitry Chagin len = sizeof(newval); 1525dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1526d56e689eSDmitry Chagin name, &newval, UIO_SYSSPACE, &len); 1527dddb7e7fSDmitry Chagin if (error != 0) 1528d56e689eSDmitry Chagin return (error); 1529d56e689eSDmitry Chagin newval = -SV_ABI_ERRNO(td->td_proc, newval); 1530d56e689eSDmitry Chagin return (copyout(&newval, PTRIN(args->optval), len)); 1531d56e689eSDmitry Chagin /* NOTREACHED */ 153203cc95d2SDmitry Chagin default: 153303cc95d2SDmitry Chagin break; 153403cc95d2SDmitry Chagin } 1535c21dee17SSøren Schmidt break; 1536c21dee17SSøren Schmidt case IPPROTO_IP: 1537745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1538c21dee17SSøren Schmidt break; 153986a9058bSAndrey V. Elsukov case IPPROTO_IPV6: 154086a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname); 154186a9058bSAndrey V. Elsukov break; 1542dad3b88aSMike Smith case IPPROTO_TCP: 1543fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1544dad3b88aSMike Smith break; 1545c21dee17SSøren Schmidt default: 15463f3a4815SMarcel Moolenaar name = -1; 15473f3a4815SMarcel Moolenaar break; 1548c21dee17SSøren Schmidt } 1549c21dee17SSøren Schmidt if (name == -1) 15503f3a4815SMarcel Moolenaar return (EINVAL); 15513f3a4815SMarcel Moolenaar 15525c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) { 1553d5368bf3SDmitry Chagin error = copyin(PTRIN(args->optlen), &len, sizeof(len)); 1554d5368bf3SDmitry Chagin if (error != 0) 1555d5368bf3SDmitry Chagin return (error); 1556d5368bf3SDmitry Chagin sa = malloc(len, M_SONAME, M_WAITOK); 1557d5368bf3SDmitry Chagin 1558dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1559d5368bf3SDmitry Chagin name, sa, UIO_SYSSPACE, &len); 1560d5368bf3SDmitry Chagin if (error != 0) 1561d5368bf3SDmitry Chagin goto out; 1562d5368bf3SDmitry Chagin 1563d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 1564d5368bf3SDmitry Chagin if (error == 0) 1565d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->optval), len); 1566d5368bf3SDmitry Chagin free(lsa, M_SONAME); 1567d5368bf3SDmitry Chagin if (error == 0) 1568d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->optlen), 1569d5368bf3SDmitry Chagin sizeof(len)); 1570d5368bf3SDmitry Chagin out: 1571d5368bf3SDmitry Chagin free(sa, M_SONAME); 1572d5368bf3SDmitry Chagin } else { 1573dfd060c0SEdward Tomasz Napierala if (args->optval) { 1574dfd060c0SEdward Tomasz Napierala error = copyin(PTRIN(args->optlen), &len, sizeof(len)); 1575dfd060c0SEdward Tomasz Napierala if (error != 0) 1576dfd060c0SEdward Tomasz Napierala return (error); 1577dfd060c0SEdward Tomasz Napierala } 1578dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1579dfd060c0SEdward Tomasz Napierala name, PTRIN(args->optval), UIO_USERSPACE, &len); 1580dfd060c0SEdward Tomasz Napierala if (error == 0) 1581dfd060c0SEdward Tomasz Napierala error = copyout(&len, PTRIN(args->optlen), 1582dfd060c0SEdward Tomasz Napierala sizeof(len)); 1583d5368bf3SDmitry Chagin } 15845c8919adSAlexander Leidinger 15855c8919adSAlexander Leidinger return (error); 1586c21dee17SSøren Schmidt } 1587c21dee17SSøren Schmidt 1588*fc7510aeSEd Maste static int 1589*fc7510aeSEd Maste linux_sendfile_common(struct thread *td, l_int out, l_int in, 1590*fc7510aeSEd Maste l_loff_t *offset, l_size_t count) 1591*fc7510aeSEd Maste { 1592*fc7510aeSEd Maste off_t bytes_read; 1593*fc7510aeSEd Maste int error; 1594*fc7510aeSEd Maste l_loff_t current_offset; 1595*fc7510aeSEd Maste struct file *fp; 1596*fc7510aeSEd Maste 1597*fc7510aeSEd Maste AUDIT_ARG_FD(in); 1598*fc7510aeSEd Maste error = fget_read(td, in, &cap_pread_rights, &fp); 1599*fc7510aeSEd Maste if (error != 0) 1600*fc7510aeSEd Maste return (error); 1601*fc7510aeSEd Maste 1602*fc7510aeSEd Maste if (offset != NULL) { 1603*fc7510aeSEd Maste current_offset = *offset; 1604*fc7510aeSEd Maste } else { 1605*fc7510aeSEd Maste error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ? 1606*fc7510aeSEd Maste fo_seek(fp, 0, SEEK_CUR, td) : ESPIPE; 1607*fc7510aeSEd Maste if (error != 0) 1608*fc7510aeSEd Maste goto drop; 1609*fc7510aeSEd Maste current_offset = td->td_uretoff.tdu_off; 1610*fc7510aeSEd Maste } 1611*fc7510aeSEd Maste 1612*fc7510aeSEd Maste bytes_read = 0; 1613*fc7510aeSEd Maste 1614*fc7510aeSEd Maste /* Linux cannot have 0 count. */ 1615*fc7510aeSEd Maste if (count <= 0 || current_offset < 0) { 1616*fc7510aeSEd Maste error = EINVAL; 1617*fc7510aeSEd Maste goto drop; 1618*fc7510aeSEd Maste } 1619*fc7510aeSEd Maste 1620*fc7510aeSEd Maste error = fo_sendfile(fp, out, NULL, NULL, current_offset, count, 1621*fc7510aeSEd Maste &bytes_read, 0, td); 1622*fc7510aeSEd Maste if (error != 0) 1623*fc7510aeSEd Maste goto drop; 1624*fc7510aeSEd Maste current_offset += bytes_read; 1625*fc7510aeSEd Maste 1626*fc7510aeSEd Maste if (offset != NULL) { 1627*fc7510aeSEd Maste *offset = current_offset; 1628*fc7510aeSEd Maste } else { 1629*fc7510aeSEd Maste error = fo_seek(fp, current_offset, SEEK_SET, td); 1630*fc7510aeSEd Maste if (error != 0) 1631*fc7510aeSEd Maste goto drop; 1632*fc7510aeSEd Maste } 1633*fc7510aeSEd Maste 1634*fc7510aeSEd Maste td->td_retval[0] = (ssize_t)bytes_read; 1635*fc7510aeSEd Maste drop: 1636*fc7510aeSEd Maste fdrop(fp, td); 1637*fc7510aeSEd Maste return (error); 1638*fc7510aeSEd Maste } 1639*fc7510aeSEd Maste 1640*fc7510aeSEd Maste int 1641*fc7510aeSEd Maste linux_sendfile(struct thread *td, struct linux_sendfile_args *arg) 1642*fc7510aeSEd Maste { 1643*fc7510aeSEd Maste /* 1644*fc7510aeSEd Maste * Differences between FreeBSD and Linux sendfile: 1645*fc7510aeSEd Maste * - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to 1646*fc7510aeSEd Maste * mean send the whole file.) In linux_sendfile given fds are still 1647*fc7510aeSEd Maste * checked for validity when the count is 0. 1648*fc7510aeSEd Maste * - Linux can send to any fd whereas FreeBSD only supports sockets. 1649*fc7510aeSEd Maste * The same restriction follows for linux_sendfile. 1650*fc7510aeSEd Maste * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr. 1651*fc7510aeSEd Maste * - Linux takes an offset pointer and updates it to the read location. 1652*fc7510aeSEd Maste * FreeBSD takes in an offset and a 'bytes read' parameter which is 1653*fc7510aeSEd Maste * only filled if it isn't NULL. We use this parameter to update the 1654*fc7510aeSEd Maste * offset pointer if it exists. 1655*fc7510aeSEd Maste * - Linux sendfile returns bytes read on success while FreeBSD 1656*fc7510aeSEd Maste * returns 0. We use the 'bytes read' parameter to get this value. 1657*fc7510aeSEd Maste */ 1658*fc7510aeSEd Maste 1659*fc7510aeSEd Maste l_loff_t offset64; 1660*fc7510aeSEd Maste l_long offset; 1661*fc7510aeSEd Maste int ret; 1662*fc7510aeSEd Maste int error; 1663*fc7510aeSEd Maste 1664*fc7510aeSEd Maste if (arg->offset != NULL) { 1665*fc7510aeSEd Maste error = copyin(arg->offset, &offset, sizeof(offset)); 1666*fc7510aeSEd Maste if (error != 0) 1667*fc7510aeSEd Maste return (error); 1668*fc7510aeSEd Maste offset64 = (l_loff_t)offset; 1669*fc7510aeSEd Maste } 1670*fc7510aeSEd Maste 1671*fc7510aeSEd Maste ret = linux_sendfile_common(td, arg->out, arg->in, 1672*fc7510aeSEd Maste arg->offset != NULL ? &offset64 : NULL, arg->count); 1673*fc7510aeSEd Maste 1674*fc7510aeSEd Maste if (arg->offset != NULL) { 1675*fc7510aeSEd Maste #if defined(__i386__) || defined(__arm__) || \ 1676*fc7510aeSEd Maste (defined(__amd64__) && defined(COMPAT_LINUX32)) 1677*fc7510aeSEd Maste if (offset64 > INT32_MAX) 1678*fc7510aeSEd Maste return (EOVERFLOW); 1679*fc7510aeSEd Maste #endif 1680*fc7510aeSEd Maste offset = (l_long)offset64; 1681*fc7510aeSEd Maste error = copyout(&offset, arg->offset, sizeof(offset)); 1682*fc7510aeSEd Maste if (error != 0) 1683*fc7510aeSEd Maste return (error); 1684*fc7510aeSEd Maste } 1685*fc7510aeSEd Maste 1686*fc7510aeSEd Maste return (ret); 1687*fc7510aeSEd Maste } 1688*fc7510aeSEd Maste 1689*fc7510aeSEd Maste #if defined(__i386__) || defined(__arm__) || \ 1690*fc7510aeSEd Maste (defined(__amd64__) && defined(COMPAT_LINUX32)) 1691*fc7510aeSEd Maste 1692*fc7510aeSEd Maste int 1693*fc7510aeSEd Maste linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg) 1694*fc7510aeSEd Maste { 1695*fc7510aeSEd Maste l_loff_t offset; 1696*fc7510aeSEd Maste int ret; 1697*fc7510aeSEd Maste int error; 1698*fc7510aeSEd Maste 1699*fc7510aeSEd Maste if (arg->offset != NULL) { 1700*fc7510aeSEd Maste error = copyin(arg->offset, &offset, sizeof(offset)); 1701*fc7510aeSEd Maste if (error != 0) 1702*fc7510aeSEd Maste return (error); 1703*fc7510aeSEd Maste } 1704*fc7510aeSEd Maste 1705*fc7510aeSEd Maste ret = linux_sendfile_common(td, arg->out, arg->in, 1706*fc7510aeSEd Maste arg->offset != NULL ? &offset : NULL, arg->count); 1707*fc7510aeSEd Maste 1708*fc7510aeSEd Maste if (arg->offset != NULL) { 1709*fc7510aeSEd Maste error = copyout(&offset, arg->offset, sizeof(offset)); 1710*fc7510aeSEd Maste if (error != 0) 1711*fc7510aeSEd Maste return (error); 1712*fc7510aeSEd Maste } 1713*fc7510aeSEd Maste 1714*fc7510aeSEd Maste return (ret); 1715*fc7510aeSEd Maste } 17167f8f1d7fSDmitry Chagin 1717ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */ 1718abf20e93SDmitry Chagin static const unsigned char lxs_args_cnt[] = { 1719abf20e93SDmitry Chagin 0 /* unused*/, 3 /* socket */, 1720abf20e93SDmitry Chagin 3 /* bind */, 3 /* connect */, 1721abf20e93SDmitry Chagin 2 /* listen */, 3 /* accept */, 1722abf20e93SDmitry Chagin 3 /* getsockname */, 3 /* getpeername */, 1723abf20e93SDmitry Chagin 4 /* socketpair */, 4 /* send */, 1724abf20e93SDmitry Chagin 4 /* recv */, 6 /* sendto */, 1725abf20e93SDmitry Chagin 6 /* recvfrom */, 2 /* shutdown */, 1726abf20e93SDmitry Chagin 5 /* setsockopt */, 5 /* getsockopt */, 1727abf20e93SDmitry Chagin 3 /* sendmsg */, 3 /* recvmsg */, 1728abf20e93SDmitry Chagin 4 /* accept4 */, 5 /* recvmmsg */, 1729*fc7510aeSEd Maste 4 /* sendmmsg */, 4 /* sendfile */ 1730ea7b81d2SDmitry Chagin }; 1731abf20e93SDmitry Chagin #define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1) 1732abf20e93SDmitry Chagin #define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong)) 1733ea7b81d2SDmitry Chagin 1734c21dee17SSøren Schmidt int 1735b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1736c21dee17SSøren Schmidt { 1737ea7b81d2SDmitry Chagin l_ulong a[6]; 1738abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32) 1739abf20e93SDmitry Chagin register_t l_args[6]; 1740abf20e93SDmitry Chagin #endif 1741ea7b81d2SDmitry Chagin void *arg; 1742ea7b81d2SDmitry Chagin int error; 17433f3a4815SMarcel Moolenaar 1744abf20e93SDmitry Chagin if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT) 1745ea7b81d2SDmitry Chagin return (EINVAL); 1746abf20e93SDmitry Chagin error = copyin(PTRIN(args->args), a, LINUX_ARG_SIZE(args->what)); 1747abf20e93SDmitry Chagin if (error != 0) 1748ea7b81d2SDmitry Chagin return (error); 1749ea7b81d2SDmitry Chagin 1750abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32) 1751abf20e93SDmitry Chagin for (int i = 0; i < lxs_args_cnt[args->what]; ++i) 1752abf20e93SDmitry Chagin l_args[i] = a[i]; 1753abf20e93SDmitry Chagin arg = l_args; 1754abf20e93SDmitry Chagin #else 1755ea7b81d2SDmitry Chagin arg = a; 1756abf20e93SDmitry Chagin #endif 1757c21dee17SSøren Schmidt switch (args->what) { 1758c21dee17SSøren Schmidt case LINUX_SOCKET: 1759b40ce416SJulian Elischer return (linux_socket(td, arg)); 1760c21dee17SSøren Schmidt case LINUX_BIND: 1761b40ce416SJulian Elischer return (linux_bind(td, arg)); 1762c21dee17SSøren Schmidt case LINUX_CONNECT: 1763b40ce416SJulian Elischer return (linux_connect(td, arg)); 1764c21dee17SSøren Schmidt case LINUX_LISTEN: 1765b40ce416SJulian Elischer return (linux_listen(td, arg)); 1766c21dee17SSøren Schmidt case LINUX_ACCEPT: 1767b40ce416SJulian Elischer return (linux_accept(td, arg)); 1768c21dee17SSøren Schmidt case LINUX_GETSOCKNAME: 1769b40ce416SJulian Elischer return (linux_getsockname(td, arg)); 1770c21dee17SSøren Schmidt case LINUX_GETPEERNAME: 1771b40ce416SJulian Elischer return (linux_getpeername(td, arg)); 1772c21dee17SSøren Schmidt case LINUX_SOCKETPAIR: 1773b40ce416SJulian Elischer return (linux_socketpair(td, arg)); 1774c21dee17SSøren Schmidt case LINUX_SEND: 1775b40ce416SJulian Elischer return (linux_send(td, arg)); 1776c21dee17SSøren Schmidt case LINUX_RECV: 1777b40ce416SJulian Elischer return (linux_recv(td, arg)); 1778c21dee17SSøren Schmidt case LINUX_SENDTO: 1779b40ce416SJulian Elischer return (linux_sendto(td, arg)); 1780c21dee17SSøren Schmidt case LINUX_RECVFROM: 1781b40ce416SJulian Elischer return (linux_recvfrom(td, arg)); 1782c21dee17SSøren Schmidt case LINUX_SHUTDOWN: 1783b40ce416SJulian Elischer return (linux_shutdown(td, arg)); 1784c21dee17SSøren Schmidt case LINUX_SETSOCKOPT: 1785b40ce416SJulian Elischer return (linux_setsockopt(td, arg)); 1786c21dee17SSøren Schmidt case LINUX_GETSOCKOPT: 1787b40ce416SJulian Elischer return (linux_getsockopt(td, arg)); 1788e76bba09SSøren Schmidt case LINUX_SENDMSG: 1789ca26842eSHajimu UMEMOTO return (linux_sendmsg(td, arg)); 1790e76bba09SSøren Schmidt case LINUX_RECVMSG: 1791b40ce416SJulian Elischer return (linux_recvmsg(td, arg)); 1792f8cd0af2SDmitry Chagin case LINUX_ACCEPT4: 1793f8cd0af2SDmitry Chagin return (linux_accept4(td, arg)); 1794e1ff74c0SDmitry Chagin case LINUX_RECVMMSG: 1795e1ff74c0SDmitry Chagin return (linux_recvmmsg(td, arg)); 1796e1ff74c0SDmitry Chagin case LINUX_SENDMMSG: 1797e1ff74c0SDmitry Chagin return (linux_sendmmsg(td, arg)); 1798*fc7510aeSEd Maste case LINUX_SENDFILE: 1799*fc7510aeSEd Maste return (linux_sendfile(td, arg)); 1800c21dee17SSøren Schmidt } 18013f3a4815SMarcel Moolenaar 18023f3a4815SMarcel Moolenaar uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 18033f3a4815SMarcel Moolenaar return (ENOSYS); 1804c21dee17SSøren Schmidt } 1805*fc7510aeSEd Maste #endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */ 1806