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> 52ca26842eSHajimu UMEMOTO #include <sys/syslog.h> 53d0b2365eSKonstantin Belousov #include <sys/un.h> 541f3dad5aSBruce Evans 554b79449eSBjoern A. Zeeb #include <net/if.h> 56eedc7fd9SGleb Smirnoff #include <net/vnet.h> 57c21dee17SSøren Schmidt #include <netinet/in.h> 58f2477ae1SMike Smith #include <netinet/in_systm.h> 59f2477ae1SMike Smith #include <netinet/ip.h> 60fb709557SJohn Baldwin #include <netinet/tcp.h> 61ca26842eSHajimu UMEMOTO #ifdef INET6 62ca26842eSHajimu UMEMOTO #include <netinet/ip6.h> 63ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h> 64ca26842eSHajimu UMEMOTO #endif 65c21dee17SSøren Schmidt 661997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32 674af27623STim J. Robbins #include <machine/../linux32/linux.h> 684af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h> 691997c537SDavid E. O'Brien #else 701997c537SDavid E. O'Brien #include <machine/../linux/linux.h> 711997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h> 724af27623STim J. Robbins #endif 73d5368bf3SDmitry Chagin #include <compat/linux/linux_common.h> 744d0f380dSDmitry Chagin #include <compat/linux/linux_file.h> 75da6d8ae6SEdward Tomasz Napierala #include <compat/linux/linux_mib.h> 7640dbba57SAssar Westerlund #include <compat/linux/linux_socket.h> 77e1ff74c0SDmitry Chagin #include <compat/linux/linux_timer.h> 78ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h> 79c21dee17SSøren Schmidt 80e1ff74c0SDmitry Chagin static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *, 81e1ff74c0SDmitry Chagin l_uint); 82e1ff74c0SDmitry Chagin static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *, 83e1ff74c0SDmitry Chagin l_uint, struct msghdr *); 844cf10e29SDmitry Chagin static int linux_set_socket_flags(int, int *); 85ca26842eSHajimu UMEMOTO 86ca26842eSHajimu UMEMOTO 87c21dee17SSøren Schmidt static int 88c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level) 89c21dee17SSøren Schmidt { 903f3a4815SMarcel Moolenaar 91c21dee17SSøren Schmidt switch (level) { 92c21dee17SSøren Schmidt case LINUX_SOL_SOCKET: 933f3a4815SMarcel Moolenaar return (SOL_SOCKET); 94c21dee17SSøren Schmidt } 953f3a4815SMarcel Moolenaar return (level); 96c21dee17SSøren Schmidt } 97c21dee17SSøren Schmidt 983f3a4815SMarcel Moolenaar static int 9984b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level) 10084b11cd8SMitsuru IWASAKI { 10184b11cd8SMitsuru IWASAKI 10284b11cd8SMitsuru IWASAKI switch (level) { 10384b11cd8SMitsuru IWASAKI case SOL_SOCKET: 10484b11cd8SMitsuru IWASAKI return (LINUX_SOL_SOCKET); 10584b11cd8SMitsuru IWASAKI } 10684b11cd8SMitsuru IWASAKI return (level); 10784b11cd8SMitsuru IWASAKI } 10884b11cd8SMitsuru IWASAKI 10984b11cd8SMitsuru IWASAKI static int 1103f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt) 111c21dee17SSøren Schmidt { 1123f3a4815SMarcel Moolenaar 113c21dee17SSøren Schmidt switch (opt) { 114c21dee17SSøren Schmidt case LINUX_IP_TOS: 1153f3a4815SMarcel Moolenaar return (IP_TOS); 116c21dee17SSøren Schmidt case LINUX_IP_TTL: 1173f3a4815SMarcel Moolenaar return (IP_TTL); 11866ff6a3cSBill Fenner case LINUX_IP_OPTIONS: 1193f3a4815SMarcel Moolenaar return (IP_OPTIONS); 12066ff6a3cSBill Fenner case LINUX_IP_MULTICAST_IF: 1213f3a4815SMarcel Moolenaar return (IP_MULTICAST_IF); 12266ff6a3cSBill Fenner case LINUX_IP_MULTICAST_TTL: 1233f3a4815SMarcel Moolenaar return (IP_MULTICAST_TTL); 12466ff6a3cSBill Fenner case LINUX_IP_MULTICAST_LOOP: 1253f3a4815SMarcel Moolenaar return (IP_MULTICAST_LOOP); 12666ff6a3cSBill Fenner case LINUX_IP_ADD_MEMBERSHIP: 1273f3a4815SMarcel Moolenaar return (IP_ADD_MEMBERSHIP); 12866ff6a3cSBill Fenner case LINUX_IP_DROP_MEMBERSHIP: 1293f3a4815SMarcel Moolenaar return (IP_DROP_MEMBERSHIP); 13066ff6a3cSBill Fenner case LINUX_IP_HDRINCL: 1313f3a4815SMarcel Moolenaar return (IP_HDRINCL); 132c21dee17SSøren Schmidt } 1333f3a4815SMarcel Moolenaar return (-1); 134c21dee17SSøren Schmidt } 135c21dee17SSøren Schmidt 136c21dee17SSøren Schmidt static int 13786a9058bSAndrey V. Elsukov linux_to_bsd_ip6_sockopt(int opt) 13886a9058bSAndrey V. Elsukov { 13986a9058bSAndrey V. Elsukov 14086a9058bSAndrey V. Elsukov switch (opt) { 14186a9058bSAndrey V. Elsukov case LINUX_IPV6_NEXTHOP: 14286a9058bSAndrey V. Elsukov return (IPV6_NEXTHOP); 14386a9058bSAndrey V. Elsukov case LINUX_IPV6_UNICAST_HOPS: 14486a9058bSAndrey V. Elsukov return (IPV6_UNICAST_HOPS); 14586a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_IF: 14686a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_IF); 14786a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_HOPS: 14886a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_HOPS); 14986a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_LOOP: 15086a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_LOOP); 15186a9058bSAndrey V. Elsukov case LINUX_IPV6_ADD_MEMBERSHIP: 15286a9058bSAndrey V. Elsukov return (IPV6_JOIN_GROUP); 15386a9058bSAndrey V. Elsukov case LINUX_IPV6_DROP_MEMBERSHIP: 15486a9058bSAndrey V. Elsukov return (IPV6_LEAVE_GROUP); 15586a9058bSAndrey V. Elsukov case LINUX_IPV6_V6ONLY: 15686a9058bSAndrey V. Elsukov return (IPV6_V6ONLY); 15786a9058bSAndrey V. Elsukov case LINUX_IPV6_DONTFRAG: 15886a9058bSAndrey V. Elsukov return (IPV6_DONTFRAG); 15986a9058bSAndrey V. Elsukov #if 0 16086a9058bSAndrey V. Elsukov case LINUX_IPV6_CHECKSUM: 16186a9058bSAndrey V. Elsukov return (IPV6_CHECKSUM); 16286a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPKTINFO: 16386a9058bSAndrey V. Elsukov return (IPV6_RECVPKTINFO); 16486a9058bSAndrey V. Elsukov case LINUX_IPV6_PKTINFO: 16586a9058bSAndrey V. Elsukov return (IPV6_PKTINFO); 16686a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPLIMIT: 16786a9058bSAndrey V. Elsukov return (IPV6_RECVHOPLIMIT); 16886a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPLIMIT: 16986a9058bSAndrey V. Elsukov return (IPV6_HOPLIMIT); 17086a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPOPTS: 17186a9058bSAndrey V. Elsukov return (IPV6_RECVHOPOPTS); 17286a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPOPTS: 17386a9058bSAndrey V. Elsukov return (IPV6_HOPOPTS); 17486a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDRDSTOPTS: 17586a9058bSAndrey V. Elsukov return (IPV6_RTHDRDSTOPTS); 17686a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVRTHDR: 17786a9058bSAndrey V. Elsukov return (IPV6_RECVRTHDR); 17886a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDR: 17986a9058bSAndrey V. Elsukov return (IPV6_RTHDR); 18086a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVDSTOPTS: 18186a9058bSAndrey V. Elsukov return (IPV6_RECVDSTOPTS); 18286a9058bSAndrey V. Elsukov case LINUX_IPV6_DSTOPTS: 18386a9058bSAndrey V. Elsukov return (IPV6_DSTOPTS); 18486a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPATHMTU: 18586a9058bSAndrey V. Elsukov return (IPV6_RECVPATHMTU); 18686a9058bSAndrey V. Elsukov case LINUX_IPV6_PATHMTU: 18786a9058bSAndrey V. Elsukov return (IPV6_PATHMTU); 18886a9058bSAndrey V. Elsukov #endif 18986a9058bSAndrey V. Elsukov } 19086a9058bSAndrey V. Elsukov return (-1); 19186a9058bSAndrey V. Elsukov } 19286a9058bSAndrey V. Elsukov 19386a9058bSAndrey V. Elsukov static int 194c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt) 195c21dee17SSøren Schmidt { 1963f3a4815SMarcel Moolenaar 197c21dee17SSøren Schmidt switch (opt) { 198c21dee17SSøren Schmidt case LINUX_SO_DEBUG: 1993f3a4815SMarcel Moolenaar return (SO_DEBUG); 200c21dee17SSøren Schmidt case LINUX_SO_REUSEADDR: 2013f3a4815SMarcel Moolenaar return (SO_REUSEADDR); 202c21dee17SSøren Schmidt case LINUX_SO_TYPE: 2033f3a4815SMarcel Moolenaar return (SO_TYPE); 204c21dee17SSøren Schmidt case LINUX_SO_ERROR: 2053f3a4815SMarcel Moolenaar return (SO_ERROR); 206c21dee17SSøren Schmidt case LINUX_SO_DONTROUTE: 2073f3a4815SMarcel Moolenaar return (SO_DONTROUTE); 208c21dee17SSøren Schmidt case LINUX_SO_BROADCAST: 2093f3a4815SMarcel Moolenaar return (SO_BROADCAST); 210c21dee17SSøren Schmidt case LINUX_SO_SNDBUF: 2113f3a4815SMarcel Moolenaar return (SO_SNDBUF); 212c21dee17SSøren Schmidt case LINUX_SO_RCVBUF: 2133f3a4815SMarcel Moolenaar return (SO_RCVBUF); 214c21dee17SSøren Schmidt case LINUX_SO_KEEPALIVE: 2153f3a4815SMarcel Moolenaar return (SO_KEEPALIVE); 216c21dee17SSøren Schmidt case LINUX_SO_OOBINLINE: 2173f3a4815SMarcel Moolenaar return (SO_OOBINLINE); 218c21dee17SSøren Schmidt case LINUX_SO_LINGER: 2193f3a4815SMarcel Moolenaar return (SO_LINGER); 220d0b2365eSKonstantin Belousov case LINUX_SO_PEERCRED: 221d0b2365eSKonstantin Belousov return (LOCAL_PEERCRED); 222d0b2365eSKonstantin Belousov case LINUX_SO_RCVLOWAT: 223d0b2365eSKonstantin Belousov return (SO_RCVLOWAT); 224d0b2365eSKonstantin Belousov case LINUX_SO_SNDLOWAT: 225d0b2365eSKonstantin Belousov return (SO_SNDLOWAT); 226d0b2365eSKonstantin Belousov case LINUX_SO_RCVTIMEO: 227d0b2365eSKonstantin Belousov return (SO_RCVTIMEO); 228d0b2365eSKonstantin Belousov case LINUX_SO_SNDTIMEO: 229d0b2365eSKonstantin Belousov return (SO_SNDTIMEO); 230d0b2365eSKonstantin Belousov case LINUX_SO_TIMESTAMP: 231d0b2365eSKonstantin Belousov return (SO_TIMESTAMP); 232d0b2365eSKonstantin Belousov case LINUX_SO_ACCEPTCONN: 233d0b2365eSKonstantin Belousov return (SO_ACCEPTCONN); 234c21dee17SSøren Schmidt } 2353f3a4815SMarcel Moolenaar return (-1); 236c21dee17SSøren Schmidt } 237c21dee17SSøren Schmidt 23840dbba57SAssar Westerlund static int 239fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt) 240fb709557SJohn Baldwin { 241fb709557SJohn Baldwin 242fb709557SJohn Baldwin switch (opt) { 243fb709557SJohn Baldwin case LINUX_TCP_NODELAY: 244fb709557SJohn Baldwin return (TCP_NODELAY); 245fb709557SJohn Baldwin case LINUX_TCP_MAXSEG: 246fb709557SJohn Baldwin return (TCP_MAXSEG); 247*c2d47457SEdward Tomasz Napierala case LINUX_TCP_CORK: 248*c2d47457SEdward Tomasz Napierala return (TCP_NOPUSH); 249fb709557SJohn Baldwin case LINUX_TCP_KEEPIDLE: 250fb709557SJohn Baldwin return (TCP_KEEPIDLE); 251fb709557SJohn Baldwin case LINUX_TCP_KEEPINTVL: 252fb709557SJohn Baldwin return (TCP_KEEPINTVL); 253fb709557SJohn Baldwin case LINUX_TCP_KEEPCNT: 254fb709557SJohn Baldwin return (TCP_KEEPCNT); 255fb709557SJohn Baldwin case LINUX_TCP_MD5SIG: 256fb709557SJohn Baldwin return (TCP_MD5SIG); 257fb709557SJohn Baldwin } 258fb709557SJohn Baldwin return (-1); 259fb709557SJohn Baldwin } 260fb709557SJohn Baldwin 261fb709557SJohn Baldwin static int 26240dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags) 26340dbba57SAssar Westerlund { 26440dbba57SAssar Westerlund int ret_flags = 0; 26540dbba57SAssar Westerlund 26640dbba57SAssar Westerlund if (flags & LINUX_MSG_OOB) 26740dbba57SAssar Westerlund ret_flags |= MSG_OOB; 26840dbba57SAssar Westerlund if (flags & LINUX_MSG_PEEK) 26940dbba57SAssar Westerlund ret_flags |= MSG_PEEK; 27040dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTROUTE) 27140dbba57SAssar Westerlund ret_flags |= MSG_DONTROUTE; 27240dbba57SAssar Westerlund if (flags & LINUX_MSG_CTRUNC) 27340dbba57SAssar Westerlund ret_flags |= MSG_CTRUNC; 27440dbba57SAssar Westerlund if (flags & LINUX_MSG_TRUNC) 27540dbba57SAssar Westerlund ret_flags |= MSG_TRUNC; 27640dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTWAIT) 27740dbba57SAssar Westerlund ret_flags |= MSG_DONTWAIT; 27840dbba57SAssar Westerlund if (flags & LINUX_MSG_EOR) 27940dbba57SAssar Westerlund ret_flags |= MSG_EOR; 28040dbba57SAssar Westerlund if (flags & LINUX_MSG_WAITALL) 28140dbba57SAssar Westerlund ret_flags |= MSG_WAITALL; 2828d6e40c3SMaxim Sobolev if (flags & LINUX_MSG_NOSIGNAL) 2838d6e40c3SMaxim Sobolev ret_flags |= MSG_NOSIGNAL; 28440dbba57SAssar Westerlund #if 0 /* not handled */ 28540dbba57SAssar Westerlund if (flags & LINUX_MSG_PROXY) 28640dbba57SAssar Westerlund ; 28740dbba57SAssar Westerlund if (flags & LINUX_MSG_FIN) 28840dbba57SAssar Westerlund ; 28940dbba57SAssar Westerlund if (flags & LINUX_MSG_SYN) 29040dbba57SAssar Westerlund ; 29140dbba57SAssar Westerlund if (flags & LINUX_MSG_CONFIRM) 29240dbba57SAssar Westerlund ; 29340dbba57SAssar Westerlund if (flags & LINUX_MSG_RST) 29440dbba57SAssar Westerlund ; 29540dbba57SAssar Westerlund if (flags & LINUX_MSG_ERRQUEUE) 29640dbba57SAssar Westerlund ; 29740dbba57SAssar Westerlund #endif 298e667ee63SDmitry Chagin return (ret_flags); 29940dbba57SAssar Westerlund } 30040dbba57SAssar Westerlund 3015a8a13e0SDavid Malone static int 30274f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type) 3035a8a13e0SDavid Malone { 30474f5d680SKonstantin Belousov 30574f5d680SKonstantin Belousov switch (cmsg_type) { 30674f5d680SKonstantin Belousov case LINUX_SCM_RIGHTS: 30774f5d680SKonstantin Belousov return (SCM_RIGHTS); 308605da56bSAndriy Gapon case LINUX_SCM_CREDENTIALS: 309605da56bSAndriy Gapon return (SCM_CREDS); 31074f5d680SKonstantin Belousov } 31174f5d680SKonstantin Belousov return (-1); 31274f5d680SKonstantin Belousov } 31374f5d680SKonstantin Belousov 31474f5d680SKonstantin Belousov static int 31574f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type) 31674f5d680SKonstantin Belousov { 31774f5d680SKonstantin Belousov 31874f5d680SKonstantin Belousov switch (cmsg_type) { 31974f5d680SKonstantin Belousov case SCM_RIGHTS: 32074f5d680SKonstantin Belousov return (LINUX_SCM_RIGHTS); 321605da56bSAndriy Gapon case SCM_CREDS: 322605da56bSAndriy Gapon return (LINUX_SCM_CREDENTIALS); 323bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 324bbf392d5SDmitry Chagin return (LINUX_SCM_TIMESTAMP); 32574f5d680SKonstantin Belousov } 32674f5d680SKonstantin Belousov return (-1); 32774f5d680SKonstantin Belousov } 32874f5d680SKonstantin Belousov 32974f5d680SKonstantin Belousov static int 33074f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 33174f5d680SKonstantin Belousov { 33274f5d680SKonstantin Belousov if (lhdr->msg_controllen > INT_MAX) 33374f5d680SKonstantin Belousov return (ENOBUFS); 33474f5d680SKonstantin Belousov 33574f5d680SKonstantin Belousov bhdr->msg_name = PTRIN(lhdr->msg_name); 33674f5d680SKonstantin Belousov bhdr->msg_namelen = lhdr->msg_namelen; 33774f5d680SKonstantin Belousov bhdr->msg_iov = PTRIN(lhdr->msg_iov); 33874f5d680SKonstantin Belousov bhdr->msg_iovlen = lhdr->msg_iovlen; 33974f5d680SKonstantin Belousov bhdr->msg_control = PTRIN(lhdr->msg_control); 340605da56bSAndriy Gapon 341605da56bSAndriy Gapon /* 342605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 343605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 344605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 345605da56bSAndriy Gapon * 346605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 347605da56bSAndriy Gapon * control messages. 348605da56bSAndriy Gapon */ 349605da56bSAndriy Gapon 35074f5d680SKonstantin Belousov bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 35174f5d680SKonstantin Belousov return (0); 35274f5d680SKonstantin Belousov } 35374f5d680SKonstantin Belousov 35474f5d680SKonstantin Belousov static int 35574f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 35674f5d680SKonstantin Belousov { 35774f5d680SKonstantin Belousov lhdr->msg_name = PTROUT(bhdr->msg_name); 35874f5d680SKonstantin Belousov lhdr->msg_namelen = bhdr->msg_namelen; 35974f5d680SKonstantin Belousov lhdr->msg_iov = PTROUT(bhdr->msg_iov); 36074f5d680SKonstantin Belousov lhdr->msg_iovlen = bhdr->msg_iovlen; 36174f5d680SKonstantin Belousov lhdr->msg_control = PTROUT(bhdr->msg_control); 362605da56bSAndriy Gapon 363605da56bSAndriy Gapon /* 364605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 365605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 366605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 367605da56bSAndriy Gapon * 368605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 369605da56bSAndriy Gapon * control messages. 370605da56bSAndriy Gapon */ 371605da56bSAndriy Gapon 37274f5d680SKonstantin Belousov /* msg_flags skipped */ 37374f5d680SKonstantin Belousov return (0); 37474f5d680SKonstantin Belousov } 37574f5d680SKonstantin Belousov 37674f5d680SKonstantin Belousov static int 3774cf10e29SDmitry Chagin linux_set_socket_flags(int lflags, int *flags) 37838a18e97SDmitry Chagin { 37938a18e97SDmitry Chagin 3804cf10e29SDmitry Chagin if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 3814cf10e29SDmitry Chagin return (EINVAL); 3824cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_NONBLOCK) 3834cf10e29SDmitry Chagin *flags |= SOCK_NONBLOCK; 3844cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_CLOEXEC) 3854cf10e29SDmitry Chagin *flags |= SOCK_CLOEXEC; 38638a18e97SDmitry Chagin return (0); 38738a18e97SDmitry Chagin } 38838a18e97SDmitry Chagin 38938a18e97SDmitry Chagin static int 39074f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 39174f5d680SKonstantin Belousov struct mbuf *control, enum uio_seg segflg) 39274f5d680SKonstantin Belousov { 3935a8a13e0SDavid Malone struct sockaddr *to; 394d5368bf3SDmitry Chagin int error, len; 3955a8a13e0SDavid Malone 3965a8a13e0SDavid Malone if (mp->msg_name != NULL) { 397d5368bf3SDmitry Chagin len = mp->msg_namelen; 398d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(mp->msg_name, &to, &len); 399dddb7e7fSDmitry Chagin if (error != 0) 4005a8a13e0SDavid Malone return (error); 4015a8a13e0SDavid Malone mp->msg_name = to; 4025a8a13e0SDavid Malone } else 4035a8a13e0SDavid Malone to = NULL; 4045a8a13e0SDavid Malone 405a6886ef1SMaxim Sobolev error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 406a6886ef1SMaxim Sobolev segflg); 4075a8a13e0SDavid Malone 4085a8a13e0SDavid Malone if (to) 4091ede983cSDag-Erling Smørgrav free(to, M_SONAME); 4105a8a13e0SDavid Malone return (error); 4115a8a13e0SDavid Malone } 4125a8a13e0SDavid Malone 4133f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */ 414f2477ae1SMike Smith static int 415e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s) 416f2477ae1SMike Smith { 417857ad5a3SDmitry Chagin int error, optval; 418857ad5a3SDmitry Chagin socklen_t size_val; 419f2477ae1SMike Smith 420e140eb43SDavid Malone size_val = sizeof(optval); 421e140eb43SDavid Malone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 422e140eb43SDavid Malone &optval, UIO_SYSSPACE, &size_val); 423dddb7e7fSDmitry Chagin if (error != 0) 4243f3a4815SMarcel Moolenaar return (error); 4253f3a4815SMarcel Moolenaar 4263f3a4815SMarcel Moolenaar return (optval == 0); 427f2477ae1SMike Smith } 428f2477ae1SMike Smith 429f2477ae1SMike Smith /* 430f2477ae1SMike Smith * Updated sendto() when IP_HDRINCL is set: 431f2477ae1SMike Smith * tweak endian-dependent fields in the IP packet. 432f2477ae1SMike Smith */ 433f2477ae1SMike Smith static int 43438da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 435f2477ae1SMike Smith { 436f2477ae1SMike Smith /* 437f2477ae1SMike Smith * linux_ip_copysize defines how many bytes we should copy 438f2477ae1SMike Smith * from the beginning of the IP packet before we customize it for BSD. 439a6886ef1SMaxim Sobolev * It should include all the fields we modify (ip_len and ip_off). 440f2477ae1SMike Smith */ 441f2477ae1SMike Smith #define linux_ip_copysize 8 442f2477ae1SMike Smith 443f2477ae1SMike Smith struct ip *packet; 4445a8a13e0SDavid Malone struct msghdr msg; 445a6886ef1SMaxim Sobolev struct iovec aiov[1]; 446f2477ae1SMike Smith int error; 447f2477ae1SMike Smith 448aa675b57SDavid Schultz /* Check that the packet isn't too big or too small. */ 449aa675b57SDavid Schultz if (linux_args->len < linux_ip_copysize || 450aa675b57SDavid Schultz linux_args->len > IP_MAXPACKET) 4513f3a4815SMarcel Moolenaar return (EINVAL); 452f2477ae1SMike Smith 453e0d3ea8cSDmitry Chagin packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); 454f2477ae1SMike Smith 455a6886ef1SMaxim Sobolev /* Make kernel copy of the packet to be sent */ 4564af27623STim J. Robbins if ((error = copyin(PTRIN(linux_args->msg), packet, 457a6886ef1SMaxim Sobolev linux_args->len))) 458a6886ef1SMaxim Sobolev goto goout; 459f2477ae1SMike Smith 460f2477ae1SMike Smith /* Convert fields from Linux to BSD raw IP socket format */ 4615a8a13e0SDavid Malone packet->ip_len = linux_args->len; 462f2477ae1SMike Smith packet->ip_off = ntohs(packet->ip_off); 463f2477ae1SMike Smith 464f2477ae1SMike Smith /* Prepare the msghdr and iovec structures describing the new packet */ 4654af27623STim J. Robbins msg.msg_name = PTRIN(linux_args->to); 4665a8a13e0SDavid Malone msg.msg_namelen = linux_args->tolen; 4675a8a13e0SDavid Malone msg.msg_iov = aiov; 468a6886ef1SMaxim Sobolev msg.msg_iovlen = 1; 4695a8a13e0SDavid Malone msg.msg_control = NULL; 4705a8a13e0SDavid Malone msg.msg_flags = 0; 4715a8a13e0SDavid Malone aiov[0].iov_base = (char *)packet; 472a6886ef1SMaxim Sobolev aiov[0].iov_len = linux_args->len; 473a6886ef1SMaxim Sobolev error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 47474f5d680SKonstantin Belousov NULL, UIO_SYSSPACE); 475a6886ef1SMaxim Sobolev goout: 476e0d3ea8cSDmitry Chagin free(packet, M_LINUX); 4775a8a13e0SDavid Malone return (error); 478f2477ae1SMike Smith } 479f2477ae1SMike Smith 480a12b9b3dSDmitry Chagin int 481b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args) 482c21dee17SSøren Schmidt { 483d293f35cSEdward Tomasz Napierala int domain, retval_socket, type; 484c21dee17SSøren Schmidt 485d293f35cSEdward Tomasz Napierala type = args->type & LINUX_SOCK_TYPE_MASK; 486d293f35cSEdward Tomasz Napierala if (type < 0 || type > LINUX_SOCK_MAX) 487eeb63e51SDmitry Chagin return (EINVAL); 4884cf10e29SDmitry Chagin retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 489d293f35cSEdward Tomasz Napierala &type); 4904cf10e29SDmitry Chagin if (retval_socket != 0) 4914cf10e29SDmitry Chagin return (retval_socket); 492d293f35cSEdward Tomasz Napierala domain = linux_to_bsd_domain(args->domain); 493d293f35cSEdward Tomasz Napierala if (domain == -1) 494d9b063ccSDmitry Chagin return (EAFNOSUPPORT); 495f2477ae1SMike Smith 496d293f35cSEdward Tomasz Napierala retval_socket = kern_socket(td, domain, type, args->protocol); 4976994ea54SDmitry Chagin if (retval_socket) 4986994ea54SDmitry Chagin return (retval_socket); 4996994ea54SDmitry Chagin 500d293f35cSEdward Tomasz Napierala if (type == SOCK_RAW 501d293f35cSEdward Tomasz Napierala && (args->protocol == IPPROTO_RAW || args->protocol == 0) 502d293f35cSEdward Tomasz Napierala && domain == PF_INET) { 503f2477ae1SMike Smith /* It's a raw IP socket: set the IP_HDRINCL option. */ 504e140eb43SDavid Malone int hdrincl; 505f2477ae1SMike Smith 506e140eb43SDavid Malone hdrincl = 1; 507e140eb43SDavid Malone /* We ignore any error returned by kern_setsockopt() */ 508e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 509e140eb43SDavid Malone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 510f2477ae1SMike Smith } 511ca26842eSHajimu UMEMOTO #ifdef INET6 512ca26842eSHajimu UMEMOTO /* 513d97bee3eSBjoern A. Zeeb * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default 514d97bee3eSBjoern A. Zeeb * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. 515d97bee3eSBjoern A. Zeeb * For simplicity we do this unconditionally of the net.inet6.ip6.v6only 516d97bee3eSBjoern A. Zeeb * sysctl value. 517ca26842eSHajimu UMEMOTO */ 518d293f35cSEdward Tomasz Napierala if (domain == PF_INET6) { 519e140eb43SDavid Malone int v6only; 520ca26842eSHajimu UMEMOTO 521e140eb43SDavid Malone v6only = 0; 522ca26842eSHajimu UMEMOTO /* We ignore any error returned by setsockopt() */ 523e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 524e140eb43SDavid Malone &v6only, UIO_SYSSPACE, sizeof(v6only)); 525ca26842eSHajimu UMEMOTO } 526ca26842eSHajimu UMEMOTO #endif 5273f3a4815SMarcel Moolenaar 5283f3a4815SMarcel Moolenaar return (retval_socket); 529c21dee17SSøren Schmidt } 530c21dee17SSøren Schmidt 531a12b9b3dSDmitry Chagin int 532b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args) 533c21dee17SSøren Schmidt { 534ca26842eSHajimu UMEMOTO struct sockaddr *sa; 535c21dee17SSøren Schmidt int error; 536c21dee17SSøren Schmidt 537d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, 538d5368bf3SDmitry Chagin &args->namelen); 539dddb7e7fSDmitry Chagin if (error != 0) 540ca26842eSHajimu UMEMOTO return (error); 541ca26842eSHajimu UMEMOTO 5426e646651SKonstantin Belousov error = kern_bindat(td, AT_FDCWD, args->s, sa); 543b33887eaSJohn Baldwin free(sa, M_SONAME); 544d5368bf3SDmitry Chagin 545d5368bf3SDmitry Chagin /* XXX */ 546745aaef5SKonstantin Belousov if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 547d4b7423fSAlexander Leidinger return (EINVAL); 548b33887eaSJohn Baldwin return (error); 549c21dee17SSøren Schmidt } 550c21dee17SSøren Schmidt 551930a65feSAndrew Gallatin int 552b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args) 553c21dee17SSøren Schmidt { 5540bf301c0SJonathan Lemon struct socket *so; 555ca26842eSHajimu UMEMOTO struct sockaddr *sa; 55695653579SGleb Smirnoff struct file *fp; 55739c95b83SMatthew Dillon u_int fflag; 558c21dee17SSøren Schmidt int error; 559c21dee17SSøren Schmidt 560d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa, 561d5368bf3SDmitry Chagin &args->namelen); 562dddb7e7fSDmitry Chagin if (error != 0) 563ca26842eSHajimu UMEMOTO return (error); 564ca26842eSHajimu UMEMOTO 5656e646651SKonstantin Belousov error = kern_connectat(td, AT_FDCWD, args->s, sa); 566b33887eaSJohn Baldwin free(sa, M_SONAME); 5670bf301c0SJonathan Lemon if (error != EISCONN) 5680bf301c0SJonathan Lemon return (error); 5690bf301c0SJonathan Lemon 570dad3b88aSMike Smith /* 571dad3b88aSMike Smith * Linux doesn't return EISCONN the first time it occurs, 572dad3b88aSMike Smith * when on a non-blocking socket. Instead it returns the 573dad3b88aSMike Smith * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 574dad3b88aSMike Smith */ 575cbd92ce6SMatt Macy error = getsock_cap(td, args->s, &cap_connect_rights, 57695653579SGleb Smirnoff &fp, &fflag, NULL); 57795653579SGleb Smirnoff if (error != 0) 57895653579SGleb Smirnoff return (error); 57995653579SGleb Smirnoff 5800bf301c0SJonathan Lemon error = EISCONN; 58195653579SGleb Smirnoff so = fp->f_data; 58239c95b83SMatthew Dillon if (fflag & FNONBLOCK) { 5834641373fSJohn Baldwin SOCK_LOCK(so); 5845002a60fSMarcel Moolenaar if (so->so_emuldata == 0) 5850bf301c0SJonathan Lemon error = so->so_error; 5860bf301c0SJonathan Lemon so->so_emuldata = (void *)1; 5874641373fSJohn Baldwin SOCK_UNLOCK(so); 588dad3b88aSMike Smith } 58995653579SGleb Smirnoff fdrop(fp, td); 59095653579SGleb Smirnoff 5913f3a4815SMarcel Moolenaar return (error); 592c21dee17SSøren Schmidt } 593c21dee17SSøren Schmidt 594a12b9b3dSDmitry Chagin int 595b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args) 596c21dee17SSøren Schmidt { 597c21dee17SSøren Schmidt 598d293f35cSEdward Tomasz Napierala return (kern_listen(td, args->s, args->backlog)); 599c21dee17SSøren Schmidt } 600c21dee17SSøren Schmidt 60101e0ffbaSAlexander Leidinger static int 602c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr, 603f83427b8SDmitry Chagin l_uintptr_t namelen, int flags) 604c21dee17SSøren Schmidt { 605d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 606d5368bf3SDmitry Chagin struct sockaddr *sa; 607fc4b98fbSDmitry Chagin struct file *fp; 608d5368bf3SDmitry Chagin int bflags, len; 609d5368bf3SDmitry Chagin struct socket *so; 610fc4b98fbSDmitry Chagin int error, error1; 61193e694c9SDmitry Chagin 612d5368bf3SDmitry Chagin bflags = 0; 613d5368bf3SDmitry Chagin error = linux_set_socket_flags(flags, &bflags); 6144cf10e29SDmitry Chagin if (error != 0) 6154cf10e29SDmitry Chagin return (error); 616d5368bf3SDmitry Chagin 617d5368bf3SDmitry Chagin sa = NULL; 618d5368bf3SDmitry Chagin if (PTRIN(addr) == NULL) { 619d5368bf3SDmitry Chagin len = 0; 620d5368bf3SDmitry Chagin error = kern_accept4(td, s, NULL, NULL, bflags, NULL); 621d5368bf3SDmitry Chagin } else { 622d5368bf3SDmitry Chagin error = copyin(PTRIN(namelen), &len, sizeof(len)); 623d5368bf3SDmitry Chagin if (error != 0) 624d5368bf3SDmitry Chagin return (error); 625d5368bf3SDmitry Chagin if (len < 0) 626d4b7423fSAlexander Leidinger return (EINVAL); 627d5368bf3SDmitry Chagin error = kern_accept4(td, s, &sa, &len, bflags, &fp); 628d5368bf3SDmitry Chagin if (error == 0) 629d5368bf3SDmitry Chagin fdrop(fp, td); 630d5368bf3SDmitry Chagin } 631d5368bf3SDmitry Chagin 632d5368bf3SDmitry Chagin if (error != 0) { 633d5368bf3SDmitry Chagin /* 634d5368bf3SDmitry Chagin * XXX. This is wrong, different sockaddr structures 635d5368bf3SDmitry Chagin * have different sizes. 636d5368bf3SDmitry Chagin */ 637d5368bf3SDmitry Chagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 638d5368bf3SDmitry Chagin { 639d5368bf3SDmitry Chagin error = EINVAL; 640d5368bf3SDmitry Chagin goto out; 641d5368bf3SDmitry Chagin } 642fc4b98fbSDmitry Chagin if (error == EINVAL) { 643cbd92ce6SMatt Macy error1 = getsock_cap(td, s, &cap_accept_rights, &fp, NULL, NULL); 644d5368bf3SDmitry Chagin if (error1 != 0) { 645d5368bf3SDmitry Chagin error = error1; 646d5368bf3SDmitry Chagin goto out; 647d5368bf3SDmitry Chagin } 64891f514e4SDmitry Chagin so = fp->f_data; 649d5368bf3SDmitry Chagin if (so->so_type == SOCK_DGRAM) 650d5368bf3SDmitry Chagin error = EOPNOTSUPP; 65191f514e4SDmitry Chagin fdrop(fp, td); 65291f514e4SDmitry Chagin } 653d5368bf3SDmitry Chagin goto out; 654d4b7423fSAlexander Leidinger } 655d5368bf3SDmitry Chagin 656d5368bf3SDmitry Chagin if (len != 0 && error == 0) { 657d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 658d5368bf3SDmitry Chagin if (error == 0) 659d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(addr), len); 660d5368bf3SDmitry Chagin free(lsa, M_SONAME); 661d5368bf3SDmitry Chagin } 662d5368bf3SDmitry Chagin 663d5368bf3SDmitry Chagin free(sa, M_SONAME); 664d5368bf3SDmitry Chagin 665d5368bf3SDmitry Chagin out: 666dddb7e7fSDmitry Chagin if (error != 0) { 66793e694c9SDmitry Chagin (void)kern_close(td, td->td_retval[0]); 66893e694c9SDmitry Chagin td->td_retval[0] = 0; 66993e694c9SDmitry Chagin } 67093e694c9SDmitry Chagin return (error); 671c21dee17SSøren Schmidt } 672c21dee17SSøren Schmidt 673a12b9b3dSDmitry Chagin int 674c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args) 675c8f37d61SDmitry Chagin { 676c8f37d61SDmitry Chagin 677c8f37d61SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 678f83427b8SDmitry Chagin args->namelen, 0)); 679c8f37d61SDmitry Chagin } 680c8f37d61SDmitry Chagin 681a12b9b3dSDmitry Chagin int 682f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args) 683f8cd0af2SDmitry Chagin { 684f8cd0af2SDmitry Chagin 685f8cd0af2SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 686f8cd0af2SDmitry Chagin args->namelen, args->flags)); 687f8cd0af2SDmitry Chagin } 688f8cd0af2SDmitry Chagin 689a12b9b3dSDmitry Chagin int 690b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 691c21dee17SSøren Schmidt { 692d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 693d5368bf3SDmitry Chagin struct sockaddr *sa; 694d5368bf3SDmitry Chagin int len, error; 695c21dee17SSøren Schmidt 696d5368bf3SDmitry Chagin error = copyin(PTRIN(args->namelen), &len, sizeof(len)); 697dddb7e7fSDmitry Chagin if (error != 0) 698ca26842eSHajimu UMEMOTO return (error); 699d5368bf3SDmitry Chagin 700d5368bf3SDmitry Chagin error = kern_getsockname(td, args->s, &sa, &len); 701d5368bf3SDmitry Chagin if (error != 0) 702d5368bf3SDmitry Chagin return (error); 703d5368bf3SDmitry Chagin 704d5368bf3SDmitry Chagin if (len != 0) { 705d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 706d5368bf3SDmitry Chagin if (error == 0) 707d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->addr), 708d5368bf3SDmitry Chagin len); 709d5368bf3SDmitry Chagin free(lsa, M_SONAME); 710d5368bf3SDmitry Chagin } 711d5368bf3SDmitry Chagin 712d5368bf3SDmitry Chagin free(sa, M_SONAME); 713d5368bf3SDmitry Chagin if (error == 0) 714d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->namelen), sizeof(len)); 715d5368bf3SDmitry Chagin return (error); 716c21dee17SSøren Schmidt } 717c21dee17SSøren Schmidt 718a12b9b3dSDmitry Chagin int 719b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 720c21dee17SSøren Schmidt { 721d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 722d5368bf3SDmitry Chagin struct sockaddr *sa; 723d5368bf3SDmitry Chagin int len, error; 724c21dee17SSøren Schmidt 725d5368bf3SDmitry Chagin error = copyin(PTRIN(args->namelen), &len, sizeof(len)); 726dddb7e7fSDmitry Chagin if (error != 0) 727ca26842eSHajimu UMEMOTO return (error); 728caaad873SDmitry Chagin if (len < 0) 729caaad873SDmitry Chagin return (EINVAL); 730d5368bf3SDmitry Chagin 731d5368bf3SDmitry Chagin error = kern_getpeername(td, args->s, &sa, &len); 732d5368bf3SDmitry Chagin if (error != 0) 733d5368bf3SDmitry Chagin return (error); 734d5368bf3SDmitry Chagin 735d5368bf3SDmitry Chagin if (len != 0) { 736d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 737d5368bf3SDmitry Chagin if (error == 0) 738d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->addr), 739d5368bf3SDmitry Chagin len); 740d5368bf3SDmitry Chagin free(lsa, M_SONAME); 741d5368bf3SDmitry Chagin } 742d5368bf3SDmitry Chagin 743d5368bf3SDmitry Chagin free(sa, M_SONAME); 744d5368bf3SDmitry Chagin if (error == 0) 745d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->namelen), sizeof(len)); 746d5368bf3SDmitry Chagin return (error); 747c21dee17SSøren Schmidt } 748c21dee17SSøren Schmidt 749a12b9b3dSDmitry Chagin int 750b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 751c21dee17SSøren Schmidt { 752ef04503dSPeter Wemm struct socketpair_args /* { 753c21dee17SSøren Schmidt int domain; 754c21dee17SSøren Schmidt int type; 755c21dee17SSøren Schmidt int protocol; 756c21dee17SSøren Schmidt int *rsv; 757ef04503dSPeter Wemm } */ bsd_args; 7584cf10e29SDmitry Chagin int error; 759c21dee17SSøren Schmidt 760745aaef5SKonstantin Belousov bsd_args.domain = linux_to_bsd_domain(args->domain); 7611a52a4abSDmitry Chagin if (bsd_args.domain != PF_LOCAL) 7621a52a4abSDmitry Chagin return (EAFNOSUPPORT); 76339253cf9SDmitry Chagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 76439253cf9SDmitry Chagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 76539253cf9SDmitry Chagin return (EINVAL); 7664cf10e29SDmitry Chagin error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 7674cf10e29SDmitry Chagin &bsd_args.type); 7684cf10e29SDmitry Chagin if (error != 0) 7694cf10e29SDmitry Chagin return (error); 7701a52a4abSDmitry Chagin if (args->protocol != 0 && args->protocol != PF_UNIX) 7711a52a4abSDmitry Chagin 7721a52a4abSDmitry Chagin /* 7731a52a4abSDmitry Chagin * Use of PF_UNIX as protocol argument is not right, 7741a52a4abSDmitry Chagin * but Linux does it. 7751a52a4abSDmitry Chagin * Do not map PF_UNIX as its Linux value is identical 7761a52a4abSDmitry Chagin * to FreeBSD one. 7771a52a4abSDmitry Chagin */ 7781a52a4abSDmitry Chagin return (EPROTONOSUPPORT); 77940092d93SDmitry Chagin else 7801a52a4abSDmitry Chagin bsd_args.protocol = 0; 781745aaef5SKonstantin Belousov bsd_args.rsv = (int *)PTRIN(args->rsv); 7824cf10e29SDmitry Chagin return (sys_socketpair(td, &bsd_args)); 783c21dee17SSøren Schmidt } 784c21dee17SSøren Schmidt 785a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 78601e0ffbaSAlexander Leidinger struct linux_send_args { 78756fba8e6SDmitry Chagin register_t s; 78856fba8e6SDmitry Chagin register_t msg; 78956fba8e6SDmitry Chagin register_t len; 79056fba8e6SDmitry Chagin register_t flags; 791c21dee17SSøren Schmidt }; 792c21dee17SSøren Schmidt 79301e0ffbaSAlexander Leidinger static int 794b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args) 795c21dee17SSøren Schmidt { 79687d72a8fSPoul-Henning Kamp struct sendto_args /* { 797c21dee17SSøren Schmidt int s; 798c21dee17SSøren Schmidt caddr_t buf; 799044af7c3SJonathan Mini int len; 800c21dee17SSøren Schmidt int flags; 80187d72a8fSPoul-Henning Kamp caddr_t to; 80287d72a8fSPoul-Henning Kamp int tolen; 803ef04503dSPeter Wemm } */ bsd_args; 804aa288712SDmitry Chagin struct file *fp; 805aa288712SDmitry Chagin int error, fflag; 806c21dee17SSøren Schmidt 807745aaef5SKonstantin Belousov bsd_args.s = args->s; 808745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 809745aaef5SKonstantin Belousov bsd_args.len = args->len; 810745aaef5SKonstantin Belousov bsd_args.flags = args->flags; 81187d72a8fSPoul-Henning Kamp bsd_args.to = NULL; 81287d72a8fSPoul-Henning Kamp bsd_args.tolen = 0; 813aa288712SDmitry Chagin error = sys_sendto(td, &bsd_args); 814aa288712SDmitry Chagin if (error == ENOTCONN) { 815aa288712SDmitry Chagin /* 816aa288712SDmitry Chagin * Linux doesn't return ENOTCONN for non-blocking sockets. 817aa288712SDmitry Chagin * Instead it returns the EAGAIN. 818aa288712SDmitry Chagin */ 819aa288712SDmitry Chagin error = getsock_cap(td, args->s, &cap_send_rights, &fp, 820aa288712SDmitry Chagin &fflag, NULL); 821aa288712SDmitry Chagin if (error == 0) { 822aa288712SDmitry Chagin if (fflag & FNONBLOCK) 823aa288712SDmitry Chagin error = EAGAIN; 824aa288712SDmitry Chagin fdrop(fp, td); 825aa288712SDmitry Chagin } 826aa288712SDmitry Chagin } 827aa288712SDmitry Chagin return (error); 828c21dee17SSøren Schmidt } 829c21dee17SSøren Schmidt 83001e0ffbaSAlexander Leidinger struct linux_recv_args { 83156fba8e6SDmitry Chagin register_t s; 83256fba8e6SDmitry Chagin register_t msg; 83356fba8e6SDmitry Chagin register_t len; 83456fba8e6SDmitry Chagin register_t flags; 835c21dee17SSøren Schmidt }; 836c21dee17SSøren Schmidt 83701e0ffbaSAlexander Leidinger static int 838b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args) 839c21dee17SSøren Schmidt { 84087d72a8fSPoul-Henning Kamp struct recvfrom_args /* { 841c21dee17SSøren Schmidt int s; 842c21dee17SSøren Schmidt caddr_t buf; 843c21dee17SSøren Schmidt int len; 844c21dee17SSøren Schmidt int flags; 84587d72a8fSPoul-Henning Kamp struct sockaddr *from; 84687d72a8fSPoul-Henning Kamp socklen_t fromlenaddr; 847ef04503dSPeter Wemm } */ bsd_args; 848c21dee17SSøren Schmidt 849745aaef5SKonstantin Belousov bsd_args.s = args->s; 850745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 851745aaef5SKonstantin Belousov bsd_args.len = args->len; 8523980a435SDmitry Chagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 85387d72a8fSPoul-Henning Kamp bsd_args.from = NULL; 85487d72a8fSPoul-Henning Kamp bsd_args.fromlenaddr = 0; 8558451d0ddSKip Macy return (sys_recvfrom(td, &bsd_args)); 856c21dee17SSøren Schmidt } 857a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 858c21dee17SSøren Schmidt 859a12b9b3dSDmitry Chagin int 860b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args) 861c21dee17SSøren Schmidt { 8625a8a13e0SDavid Malone struct msghdr msg; 8635a8a13e0SDavid Malone struct iovec aiov; 864c21dee17SSøren Schmidt 865745aaef5SKonstantin Belousov if (linux_check_hdrincl(td, args->s) == 0) 866f2477ae1SMike Smith /* IP_HDRINCL set, tweak the packet before sending */ 867745aaef5SKonstantin Belousov return (linux_sendto_hdrincl(td, args)); 868f2477ae1SMike Smith 869745aaef5SKonstantin Belousov msg.msg_name = PTRIN(args->to); 870745aaef5SKonstantin Belousov msg.msg_namelen = args->tolen; 8715a8a13e0SDavid Malone msg.msg_iov = &aiov; 8725a8a13e0SDavid Malone msg.msg_iovlen = 1; 8735a8a13e0SDavid Malone msg.msg_control = NULL; 8745a8a13e0SDavid Malone msg.msg_flags = 0; 875745aaef5SKonstantin Belousov aiov.iov_base = PTRIN(args->msg); 876745aaef5SKonstantin Belousov aiov.iov_len = args->len; 877e667ee63SDmitry Chagin return (linux_sendit(td, args->s, &msg, args->flags, NULL, 878e667ee63SDmitry Chagin UIO_USERSPACE)); 879c21dee17SSøren Schmidt } 880c21dee17SSøren Schmidt 881a12b9b3dSDmitry Chagin int 882b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 883c21dee17SSøren Schmidt { 884d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 885d5368bf3SDmitry Chagin struct sockaddr *sa; 8869599b0ecSDmitry Chagin struct msghdr msg; 8879599b0ecSDmitry Chagin struct iovec aiov; 8883a49978fSDmitry Chagin int error, fromlen; 889c21dee17SSøren Schmidt 8909599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL) { 8913a49978fSDmitry Chagin error = copyin(PTRIN(args->fromlen), &fromlen, 8923a49978fSDmitry Chagin sizeof(fromlen)); 8939599b0ecSDmitry Chagin if (error != 0) 8943f3a4815SMarcel Moolenaar return (error); 8953a49978fSDmitry Chagin if (fromlen < 0) 8963a49978fSDmitry Chagin return (EINVAL); 897d5368bf3SDmitry Chagin sa = malloc(fromlen, M_SONAME, M_WAITOK); 898d5368bf3SDmitry Chagin } else { 899d5368bf3SDmitry Chagin fromlen = 0; 900d5368bf3SDmitry Chagin sa = NULL; 901d5368bf3SDmitry Chagin } 9029599b0ecSDmitry Chagin 903d5368bf3SDmitry Chagin msg.msg_name = sa; 904d5368bf3SDmitry Chagin msg.msg_namelen = fromlen; 9059599b0ecSDmitry Chagin msg.msg_iov = &aiov; 9069599b0ecSDmitry Chagin msg.msg_iovlen = 1; 9079599b0ecSDmitry Chagin aiov.iov_base = PTRIN(args->buf); 9089599b0ecSDmitry Chagin aiov.iov_len = args->len; 9099599b0ecSDmitry Chagin msg.msg_control = 0; 9109599b0ecSDmitry Chagin msg.msg_flags = linux_to_bsd_msg_flags(args->flags); 9119599b0ecSDmitry Chagin 912d5368bf3SDmitry Chagin error = kern_recvit(td, args->s, &msg, UIO_SYSSPACE, NULL); 9139599b0ecSDmitry Chagin if (error != 0) 914dcd62418SDmitry Chagin goto out; 9159599b0ecSDmitry Chagin 9169599b0ecSDmitry Chagin if (PTRIN(args->from) != NULL) { 917d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, msg.msg_namelen); 918d5368bf3SDmitry Chagin if (error == 0) 919d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->from), 920d5368bf3SDmitry Chagin msg.msg_namelen); 921d5368bf3SDmitry Chagin free(lsa, M_SONAME); 922ca26842eSHajimu UMEMOTO } 9239599b0ecSDmitry Chagin 924d5368bf3SDmitry Chagin if (error == 0 && PTRIN(args->fromlen) != NULL) 9259599b0ecSDmitry Chagin error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), 9269599b0ecSDmitry Chagin sizeof(msg.msg_namelen)); 927dcd62418SDmitry Chagin out: 928d5368bf3SDmitry Chagin free(sa, M_SONAME); 9299599b0ecSDmitry Chagin return (error); 930ca26842eSHajimu UMEMOTO } 931ca26842eSHajimu UMEMOTO 932e1ff74c0SDmitry Chagin static int 933e1ff74c0SDmitry Chagin linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 934e1ff74c0SDmitry Chagin l_uint flags) 935ca26842eSHajimu UMEMOTO { 93674f5d680SKonstantin Belousov struct cmsghdr *cmsg; 93774f5d680SKonstantin Belousov struct mbuf *control; 938ca26842eSHajimu UMEMOTO struct msghdr msg; 93974f5d680SKonstantin Belousov struct l_cmsghdr linux_cmsg; 94074f5d680SKonstantin Belousov struct l_cmsghdr *ptr_cmsg; 94174f5d680SKonstantin Belousov struct l_msghdr linux_msg; 942552afd9cSPoul-Henning Kamp struct iovec *iov; 94374f5d680SKonstantin Belousov socklen_t datalen; 944605da56bSAndriy Gapon struct sockaddr *sa; 9451410bfe1SDmitry Chagin struct socket *so; 946605da56bSAndriy Gapon sa_family_t sa_family; 9471410bfe1SDmitry Chagin struct file *fp; 94874f5d680SKonstantin Belousov void *data; 949e3b385fcSTijl Coosemans l_size_t len; 9507df0e7beSTijl Coosemans l_size_t clen; 9511410bfe1SDmitry Chagin int error, fflag; 952ca26842eSHajimu UMEMOTO 953e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 954e1ff74c0SDmitry Chagin if (error != 0) 95574f5d680SKonstantin Belousov return (error); 956d72a6158SRobert Watson 957d72a6158SRobert Watson /* 958d72a6158SRobert Watson * Some Linux applications (ping) define a non-NULL control data 959d72a6158SRobert Watson * pointer, but a msg_controllen of 0, which is not allowed in the 960d72a6158SRobert Watson * FreeBSD system call interface. NULL the msg_control pointer in 961d72a6158SRobert Watson * order to handle this case. This should be checked, but allows the 962d72a6158SRobert Watson * Linux ping to work. 963d72a6158SRobert Watson */ 964605da56bSAndriy Gapon if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) 965605da56bSAndriy Gapon linux_msg.msg_control = PTROUT(NULL); 966605da56bSAndriy Gapon 967605da56bSAndriy Gapon error = linux_to_bsd_msghdr(&msg, &linux_msg); 968e1ff74c0SDmitry Chagin if (error != 0) 969605da56bSAndriy Gapon return (error); 97074f5d680SKonstantin Belousov 97174f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 97274f5d680SKonstantin Belousov error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 97374f5d680SKonstantin Belousov &iov, EMSGSIZE); 97474f5d680SKonstantin Belousov #else 975552afd9cSPoul-Henning Kamp error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 97674f5d680SKonstantin Belousov #endif 977e1ff74c0SDmitry Chagin if (error != 0) 978552afd9cSPoul-Henning Kamp return (error); 97974f5d680SKonstantin Belousov 980605da56bSAndriy Gapon control = NULL; 981605da56bSAndriy Gapon 982e1ff74c0SDmitry Chagin error = kern_getsockname(td, s, &sa, &datalen); 983e1ff74c0SDmitry Chagin if (error != 0) 984605da56bSAndriy Gapon goto bad; 985605da56bSAndriy Gapon sa_family = sa->sa_family; 986605da56bSAndriy Gapon free(sa, M_SONAME); 987605da56bSAndriy Gapon 9881410bfe1SDmitry Chagin if (flags & LINUX_MSG_OOB) { 9891410bfe1SDmitry Chagin error = EOPNOTSUPP; 9901410bfe1SDmitry Chagin if (sa_family == AF_UNIX) 9911410bfe1SDmitry Chagin goto bad; 9921410bfe1SDmitry Chagin 9931410bfe1SDmitry Chagin error = getsock_cap(td, s, &cap_send_rights, &fp, 9941410bfe1SDmitry Chagin &fflag, NULL); 9951410bfe1SDmitry Chagin if (error != 0) 9961410bfe1SDmitry Chagin goto bad; 9971410bfe1SDmitry Chagin so = fp->f_data; 9981410bfe1SDmitry Chagin if (so->so_type != SOCK_STREAM) 9991410bfe1SDmitry Chagin error = EOPNOTSUPP; 10001410bfe1SDmitry Chagin fdrop(fp, td); 10011410bfe1SDmitry Chagin if (error != 0) 10021410bfe1SDmitry Chagin goto bad; 10031410bfe1SDmitry Chagin } 10041410bfe1SDmitry Chagin 10051410bfe1SDmitry Chagin if (linux_msg.msg_controllen >= sizeof(struct l_cmsghdr)) { 10061410bfe1SDmitry Chagin 100774f5d680SKonstantin Belousov error = ENOBUFS; 1008eb1b1807SGleb Smirnoff control = m_get(M_WAITOK, MT_CONTROL); 1009e3b385fcSTijl Coosemans MCLGET(control, M_WAITOK); 1010e3b385fcSTijl Coosemans data = mtod(control, void *); 1011e3b385fcSTijl Coosemans datalen = 0; 101274f5d680SKonstantin Belousov 10137df0e7beSTijl Coosemans ptr_cmsg = PTRIN(linux_msg.msg_control); 10147df0e7beSTijl Coosemans clen = linux_msg.msg_controllen; 101574f5d680SKonstantin Belousov do { 101674f5d680SKonstantin Belousov error = copyin(ptr_cmsg, &linux_cmsg, 101774f5d680SKonstantin Belousov sizeof(struct l_cmsghdr)); 1018e1ff74c0SDmitry Chagin if (error != 0) 101974f5d680SKonstantin Belousov goto bad; 102074f5d680SKonstantin Belousov 102174f5d680SKonstantin Belousov error = EINVAL; 10227df0e7beSTijl Coosemans if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) || 10237df0e7beSTijl Coosemans linux_cmsg.cmsg_len > clen) 102474f5d680SKonstantin Belousov goto bad; 102574f5d680SKonstantin Belousov 1026e3b385fcSTijl Coosemans if (datalen + CMSG_HDRSZ > MCLBYTES) 1027e3b385fcSTijl Coosemans goto bad; 1028e3b385fcSTijl Coosemans 102974f5d680SKonstantin Belousov /* 1030605da56bSAndriy Gapon * Now we support only SCM_RIGHTS and SCM_CRED, 1031605da56bSAndriy Gapon * so return EINVAL in any other cmsg_type 103274f5d680SKonstantin Belousov */ 1033e3b385fcSTijl Coosemans cmsg = data; 1034605da56bSAndriy Gapon cmsg->cmsg_type = 1035605da56bSAndriy Gapon linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); 103674f5d680SKonstantin Belousov cmsg->cmsg_level = 103774f5d680SKonstantin Belousov linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1038605da56bSAndriy Gapon if (cmsg->cmsg_type == -1 1039605da56bSAndriy Gapon || cmsg->cmsg_level != SOL_SOCKET) 1040605da56bSAndriy Gapon goto bad; 104174f5d680SKonstantin Belousov 1042605da56bSAndriy Gapon /* 1043605da56bSAndriy Gapon * Some applications (e.g. pulseaudio) attempt to 1044605da56bSAndriy Gapon * send ancillary data even if the underlying protocol 1045605da56bSAndriy Gapon * doesn't support it which is not allowed in the 1046605da56bSAndriy Gapon * FreeBSD system call interface. 1047605da56bSAndriy Gapon */ 1048605da56bSAndriy Gapon if (sa_family != AF_UNIX) 1049605da56bSAndriy Gapon continue; 1050605da56bSAndriy Gapon 1051e3b385fcSTijl Coosemans if (cmsg->cmsg_type == SCM_CREDS) { 1052e3b385fcSTijl Coosemans len = sizeof(struct cmsgcred); 1053e3b385fcSTijl Coosemans if (datalen + CMSG_SPACE(len) > MCLBYTES) 1054e3b385fcSTijl Coosemans goto bad; 1055605da56bSAndriy Gapon 1056605da56bSAndriy Gapon /* 1057605da56bSAndriy Gapon * The lower levels will fill in the structure 1058605da56bSAndriy Gapon */ 1059e3b385fcSTijl Coosemans memset(CMSG_DATA(data), 0, len); 1060e3b385fcSTijl Coosemans } else { 1061e3b385fcSTijl Coosemans len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1062e3b385fcSTijl Coosemans if (datalen + CMSG_SPACE(len) < datalen || 1063e3b385fcSTijl Coosemans datalen + CMSG_SPACE(len) > MCLBYTES) 1064e3b385fcSTijl Coosemans goto bad; 1065e3b385fcSTijl Coosemans 1066e3b385fcSTijl Coosemans error = copyin(LINUX_CMSG_DATA(ptr_cmsg), 1067e3b385fcSTijl Coosemans CMSG_DATA(data), len); 1068e3b385fcSTijl Coosemans if (error != 0) 1069e3b385fcSTijl Coosemans goto bad; 1070605da56bSAndriy Gapon } 1071605da56bSAndriy Gapon 1072e3b385fcSTijl Coosemans cmsg->cmsg_len = CMSG_LEN(len); 1073e3b385fcSTijl Coosemans data = (char *)data + CMSG_SPACE(len); 1074e3b385fcSTijl Coosemans datalen += CMSG_SPACE(len); 10757df0e7beSTijl Coosemans 10767df0e7beSTijl Coosemans if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)) 10777df0e7beSTijl Coosemans break; 10787df0e7beSTijl Coosemans 10797df0e7beSTijl Coosemans clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len); 10807df0e7beSTijl Coosemans ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg + 10817df0e7beSTijl Coosemans LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len)); 10827df0e7beSTijl Coosemans } while(clen >= sizeof(struct l_cmsghdr)); 1083605da56bSAndriy Gapon 1084e3b385fcSTijl Coosemans control->m_len = datalen; 1085e3b385fcSTijl Coosemans if (datalen == 0) { 1086605da56bSAndriy Gapon m_freem(control); 108774f5d680SKonstantin Belousov control = NULL; 1088605da56bSAndriy Gapon } 108974f5d680SKonstantin Belousov } 109074f5d680SKonstantin Belousov 10915a8a13e0SDavid Malone msg.msg_iov = iov; 10925a8a13e0SDavid Malone msg.msg_flags = 0; 1093e1ff74c0SDmitry Chagin error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); 109467968b35SDmitry Chagin control = NULL; 109574f5d680SKonstantin Belousov 109674f5d680SKonstantin Belousov bad: 10974f65e9cfSDmitry Chagin m_freem(control); 1098552afd9cSPoul-Henning Kamp free(iov, M_IOV); 1099ca26842eSHajimu UMEMOTO return (error); 1100c21dee17SSøren Schmidt } 1101c21dee17SSøren Schmidt 1102a12b9b3dSDmitry Chagin int 1103e1ff74c0SDmitry Chagin linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1104e1ff74c0SDmitry Chagin { 1105e1ff74c0SDmitry Chagin 1106e1ff74c0SDmitry Chagin return (linux_sendmsg_common(td, args->s, PTRIN(args->msg), 1107e1ff74c0SDmitry Chagin args->flags)); 1108e1ff74c0SDmitry Chagin } 1109e1ff74c0SDmitry Chagin 1110e1ff74c0SDmitry Chagin int 1111e1ff74c0SDmitry Chagin linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) 1112e1ff74c0SDmitry Chagin { 1113e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1114e1ff74c0SDmitry Chagin l_uint retval; 1115e1ff74c0SDmitry Chagin int error, datagrams; 1116e1ff74c0SDmitry Chagin 1117e1ff74c0SDmitry Chagin if (args->vlen > UIO_MAXIOV) 1118e1ff74c0SDmitry Chagin args->vlen = UIO_MAXIOV; 1119e1ff74c0SDmitry Chagin 1120e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1121e1ff74c0SDmitry Chagin datagrams = 0; 1122e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1123e1ff74c0SDmitry Chagin error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, 1124e1ff74c0SDmitry Chagin args->flags); 1125e1ff74c0SDmitry Chagin if (error != 0) 1126e1ff74c0SDmitry Chagin break; 1127e1ff74c0SDmitry Chagin 1128e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1129e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1130e1ff74c0SDmitry Chagin if (error != 0) 1131e1ff74c0SDmitry Chagin break; 1132e1ff74c0SDmitry Chagin ++msg; 1133e1ff74c0SDmitry Chagin ++datagrams; 1134e1ff74c0SDmitry Chagin } 1135e1ff74c0SDmitry Chagin if (error == 0) 1136e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1137e1ff74c0SDmitry Chagin return (error); 1138e1ff74c0SDmitry Chagin } 1139e1ff74c0SDmitry Chagin 1140e1ff74c0SDmitry Chagin static int 1141e1ff74c0SDmitry Chagin linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1142e1ff74c0SDmitry Chagin l_uint flags, struct msghdr *msg) 114340dbba57SAssar Westerlund { 114474f5d680SKonstantin Belousov struct cmsghdr *cm; 1145605da56bSAndriy Gapon struct cmsgcred *cmcred; 114674f5d680SKonstantin Belousov struct l_cmsghdr *linux_cmsg = NULL; 1147605da56bSAndriy Gapon struct l_ucred linux_ucred; 1148c7902fbeSMark Johnston socklen_t datalen, maxlen, outlen; 114974f5d680SKonstantin Belousov struct l_msghdr linux_msg; 115074f5d680SKonstantin Belousov struct iovec *iov, *uiov; 115174f5d680SKonstantin Belousov struct mbuf *control = NULL; 115274f5d680SKonstantin Belousov struct mbuf **controlp; 1153bbf392d5SDmitry Chagin struct timeval *ftmvl; 1154d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 1155d5368bf3SDmitry Chagin struct sockaddr *sa; 1156bbf392d5SDmitry Chagin l_timeval ltmvl; 115774f5d680SKonstantin Belousov caddr_t outbuf; 115874f5d680SKonstantin Belousov void *data; 11593a72bf04SDmitry Chagin int error, i, fd, fds, *fdp; 116040dbba57SAssar Westerlund 1161e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1162e1ff74c0SDmitry Chagin if (error != 0) 1163ca26842eSHajimu UMEMOTO return (error); 1164ca26842eSHajimu UMEMOTO 1165e1ff74c0SDmitry Chagin error = linux_to_bsd_msghdr(msg, &linux_msg); 1166e1ff74c0SDmitry Chagin if (error != 0) 116774f5d680SKonstantin Belousov return (error); 116874f5d680SKonstantin Belousov 116974f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 1170e1ff74c0SDmitry Chagin error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, 117174f5d680SKonstantin Belousov &iov, EMSGSIZE); 117274f5d680SKonstantin Belousov #else 1173e1ff74c0SDmitry Chagin error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); 117474f5d680SKonstantin Belousov #endif 1175e1ff74c0SDmitry Chagin if (error != 0) 117674f5d680SKonstantin Belousov return (error); 117774f5d680SKonstantin Belousov 1178e1ff74c0SDmitry Chagin if (msg->msg_name) { 1179d5368bf3SDmitry Chagin sa = malloc(msg->msg_namelen, M_SONAME, M_WAITOK); 1180d5368bf3SDmitry Chagin msg->msg_name = sa; 11818128cfc5SDmitry Chagin } else 11828128cfc5SDmitry Chagin sa = NULL; 118384b11cd8SMitsuru IWASAKI 1184e1ff74c0SDmitry Chagin uiov = msg->msg_iov; 1185e1ff74c0SDmitry Chagin msg->msg_iov = iov; 1186e1ff74c0SDmitry Chagin controlp = (msg->msg_control != NULL) ? &control : NULL; 1187d5368bf3SDmitry Chagin error = kern_recvit(td, s, msg, UIO_SYSSPACE, controlp); 1188e1ff74c0SDmitry Chagin msg->msg_iov = uiov; 1189e1ff74c0SDmitry Chagin if (error != 0) 119074f5d680SKonstantin Belousov goto bad; 119174f5d680SKonstantin Belousov 119257cb29a7SDmitry Chagin if (msg->msg_name) { 1193d5368bf3SDmitry Chagin msg->msg_name = PTRIN(linux_msg.msg_name); 1194d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, msg->msg_namelen); 1195d5368bf3SDmitry Chagin if (error == 0) 1196d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(msg->msg_name), 1197d5368bf3SDmitry Chagin msg->msg_namelen); 1198d5368bf3SDmitry Chagin free(lsa, M_SONAME); 1199d5368bf3SDmitry Chagin if (error != 0) 1200d5368bf3SDmitry Chagin goto bad; 1201d5368bf3SDmitry Chagin } 1202d5368bf3SDmitry Chagin 1203e1ff74c0SDmitry Chagin error = bsd_to_linux_msghdr(msg, &linux_msg); 1204e1ff74c0SDmitry Chagin if (error != 0) 120574f5d680SKonstantin Belousov goto bad; 120674f5d680SKonstantin Belousov 1207c7902fbeSMark Johnston maxlen = linux_msg.msg_controllen; 1208c7902fbeSMark Johnston linux_msg.msg_controllen = 0; 1209605da56bSAndriy Gapon if (control) { 1210e0d3ea8cSDmitry Chagin linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); 1211605da56bSAndriy Gapon 1212e1ff74c0SDmitry Chagin msg->msg_control = mtod(control, struct cmsghdr *); 1213e1ff74c0SDmitry Chagin msg->msg_controllen = control->m_len; 1214605da56bSAndriy Gapon 1215e1ff74c0SDmitry Chagin cm = CMSG_FIRSTHDR(msg); 1216c7902fbeSMark Johnston outbuf = PTRIN(linux_msg.msg_control); 1217c7902fbeSMark Johnston outlen = 0; 121874f5d680SKonstantin Belousov while (cm != NULL) { 1219605da56bSAndriy Gapon linux_cmsg->cmsg_type = 1220605da56bSAndriy Gapon bsd_to_linux_cmsg_type(cm->cmsg_type); 1221605da56bSAndriy Gapon linux_cmsg->cmsg_level = 1222605da56bSAndriy Gapon bsd_to_linux_sockopt_level(cm->cmsg_level); 1223c7902fbeSMark Johnston if (linux_cmsg->cmsg_type == -1 || 1224c7902fbeSMark Johnston cm->cmsg_level != SOL_SOCKET) { 122574f5d680SKonstantin Belousov error = EINVAL; 122674f5d680SKonstantin Belousov goto bad; 122774f5d680SKonstantin Belousov } 1228605da56bSAndriy Gapon 122974f5d680SKonstantin Belousov data = CMSG_DATA(cm); 123074f5d680SKonstantin Belousov datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 123174f5d680SKonstantin Belousov 1232c7902fbeSMark Johnston switch (cm->cmsg_type) { 1233605da56bSAndriy Gapon case SCM_RIGHTS: 1234e1ff74c0SDmitry Chagin if (flags & LINUX_MSG_CMSG_CLOEXEC) { 1235605da56bSAndriy Gapon fds = datalen / sizeof(int); 1236605da56bSAndriy Gapon fdp = data; 1237605da56bSAndriy Gapon for (i = 0; i < fds; i++) { 1238605da56bSAndriy Gapon fd = *fdp++; 1239605da56bSAndriy Gapon (void)kern_fcntl(td, fd, 1240605da56bSAndriy Gapon F_SETFD, FD_CLOEXEC); 1241605da56bSAndriy Gapon } 1242605da56bSAndriy Gapon } 1243605da56bSAndriy Gapon break; 1244605da56bSAndriy Gapon 1245605da56bSAndriy Gapon case SCM_CREDS: 1246605da56bSAndriy Gapon /* 1247605da56bSAndriy Gapon * Currently LOCAL_CREDS is never in 1248605da56bSAndriy Gapon * effect for Linux so no need to worry 1249605da56bSAndriy Gapon * about sockcred 1250605da56bSAndriy Gapon */ 1251605da56bSAndriy Gapon if (datalen != sizeof(*cmcred)) { 1252605da56bSAndriy Gapon error = EMSGSIZE; 1253605da56bSAndriy Gapon goto bad; 1254605da56bSAndriy Gapon } 1255605da56bSAndriy Gapon cmcred = (struct cmsgcred *)data; 1256605da56bSAndriy Gapon bzero(&linux_ucred, sizeof(linux_ucred)); 1257605da56bSAndriy Gapon linux_ucred.pid = cmcred->cmcred_pid; 1258605da56bSAndriy Gapon linux_ucred.uid = cmcred->cmcred_uid; 1259605da56bSAndriy Gapon linux_ucred.gid = cmcred->cmcred_gid; 1260605da56bSAndriy Gapon data = &linux_ucred; 1261605da56bSAndriy Gapon datalen = sizeof(linux_ucred); 1262605da56bSAndriy Gapon break; 1263bbf392d5SDmitry Chagin 1264bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 1265bbf392d5SDmitry Chagin if (datalen != sizeof(struct timeval)) { 1266bbf392d5SDmitry Chagin error = EMSGSIZE; 1267bbf392d5SDmitry Chagin goto bad; 1268bbf392d5SDmitry Chagin } 1269bbf392d5SDmitry Chagin ftmvl = (struct timeval *)data; 1270bbf392d5SDmitry Chagin ltmvl.tv_sec = ftmvl->tv_sec; 1271bbf392d5SDmitry Chagin ltmvl.tv_usec = ftmvl->tv_usec; 1272bbf392d5SDmitry Chagin data = <mvl; 1273bbf392d5SDmitry Chagin datalen = sizeof(ltmvl); 1274bbf392d5SDmitry Chagin break; 1275605da56bSAndriy Gapon } 1276605da56bSAndriy Gapon 1277c7902fbeSMark Johnston if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) { 127874f5d680SKonstantin Belousov if (outlen == 0) { 127974f5d680SKonstantin Belousov error = EMSGSIZE; 128074f5d680SKonstantin Belousov goto bad; 128174f5d680SKonstantin Belousov } else { 1282c7902fbeSMark Johnston linux_msg.msg_flags |= LINUX_MSG_CTRUNC; 1283c7902fbeSMark Johnston m_dispose_extcontrolm(control); 128474f5d680SKonstantin Belousov goto out; 128574f5d680SKonstantin Belousov } 128674f5d680SKonstantin Belousov } 128774f5d680SKonstantin Belousov 128874f5d680SKonstantin Belousov linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 128974f5d680SKonstantin Belousov 129074f5d680SKonstantin Belousov error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1291dddb7e7fSDmitry Chagin if (error != 0) 129274f5d680SKonstantin Belousov goto bad; 129374f5d680SKonstantin Belousov outbuf += L_CMSG_HDRSZ; 129474f5d680SKonstantin Belousov 129574f5d680SKonstantin Belousov error = copyout(data, outbuf, datalen); 1296dddb7e7fSDmitry Chagin if (error != 0) 129774f5d680SKonstantin Belousov goto bad; 129874f5d680SKonstantin Belousov 129974f5d680SKonstantin Belousov outbuf += LINUX_CMSG_ALIGN(datalen); 130074f5d680SKonstantin Belousov outlen += LINUX_CMSG_LEN(datalen); 130174f5d680SKonstantin Belousov 1302e1ff74c0SDmitry Chagin cm = CMSG_NXTHDR(msg, cm); 130374f5d680SKonstantin Belousov } 1304c7902fbeSMark Johnston linux_msg.msg_controllen = outlen; 130574f5d680SKonstantin Belousov } 130674f5d680SKonstantin Belousov 130774f5d680SKonstantin Belousov out: 1308e1ff74c0SDmitry Chagin error = copyout(&linux_msg, msghdr, sizeof(linux_msg)); 130974f5d680SKonstantin Belousov 131074f5d680SKonstantin Belousov bad: 1311c7902fbeSMark Johnston if (control != NULL) { 1312c7902fbeSMark Johnston if (error != 0) 1313c7902fbeSMark Johnston m_dispose_extcontrolm(control); 131474f5d680SKonstantin Belousov m_freem(control); 1315c7902fbeSMark Johnston } 1316c7902fbeSMark Johnston free(iov, M_IOV); 1317e0d3ea8cSDmitry Chagin free(linux_cmsg, M_LINUX); 13188128cfc5SDmitry Chagin free(sa, M_SONAME); 131974f5d680SKonstantin Belousov 1320ca26842eSHajimu UMEMOTO return (error); 132140dbba57SAssar Westerlund } 132240dbba57SAssar Westerlund 1323a12b9b3dSDmitry Chagin int 1324e1ff74c0SDmitry Chagin linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1325e1ff74c0SDmitry Chagin { 1326e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1327e1ff74c0SDmitry Chagin 1328e1ff74c0SDmitry Chagin return (linux_recvmsg_common(td, args->s, PTRIN(args->msg), 1329e1ff74c0SDmitry Chagin args->flags, &bsd_msg)); 1330e1ff74c0SDmitry Chagin } 1331e1ff74c0SDmitry Chagin 1332e1ff74c0SDmitry Chagin int 1333e1ff74c0SDmitry Chagin linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) 1334e1ff74c0SDmitry Chagin { 1335e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1336e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1337e1ff74c0SDmitry Chagin struct l_timespec lts; 1338e1ff74c0SDmitry Chagin struct timespec ts, tts; 1339e1ff74c0SDmitry Chagin l_uint retval; 1340e1ff74c0SDmitry Chagin int error, datagrams; 1341e1ff74c0SDmitry Chagin 1342e1ff74c0SDmitry Chagin if (args->timeout) { 1343e1ff74c0SDmitry Chagin error = copyin(args->timeout, <s, sizeof(struct l_timespec)); 1344e1ff74c0SDmitry Chagin if (error != 0) 1345e1ff74c0SDmitry Chagin return (error); 1346e1ff74c0SDmitry Chagin error = linux_to_native_timespec(&ts, <s); 1347e1ff74c0SDmitry Chagin if (error != 0) 1348e1ff74c0SDmitry Chagin return (error); 1349e1ff74c0SDmitry Chagin getnanotime(&tts); 13506040822cSAlan Somers timespecadd(&tts, &ts, &tts); 1351e1ff74c0SDmitry Chagin } 1352e1ff74c0SDmitry Chagin 1353e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1354e1ff74c0SDmitry Chagin datagrams = 0; 1355e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1356e1ff74c0SDmitry Chagin error = linux_recvmsg_common(td, args->s, &msg->msg_hdr, 1357e1ff74c0SDmitry Chagin args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); 1358e1ff74c0SDmitry Chagin if (error != 0) 1359e1ff74c0SDmitry Chagin break; 1360e1ff74c0SDmitry Chagin 1361e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1362e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1363e1ff74c0SDmitry Chagin if (error != 0) 1364e1ff74c0SDmitry Chagin break; 1365e1ff74c0SDmitry Chagin ++msg; 1366e1ff74c0SDmitry Chagin ++datagrams; 1367e1ff74c0SDmitry Chagin 1368e1ff74c0SDmitry Chagin /* 1369e1ff74c0SDmitry Chagin * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. 1370e1ff74c0SDmitry Chagin */ 1371e1ff74c0SDmitry Chagin if (args->flags & LINUX_MSG_WAITFORONE) 1372e1ff74c0SDmitry Chagin args->flags |= LINUX_MSG_DONTWAIT; 1373e1ff74c0SDmitry Chagin 1374e1ff74c0SDmitry Chagin /* 1375e1ff74c0SDmitry Chagin * See BUGS section of recvmmsg(2). 1376e1ff74c0SDmitry Chagin */ 1377e1ff74c0SDmitry Chagin if (args->timeout) { 1378e1ff74c0SDmitry Chagin getnanotime(&ts); 13796040822cSAlan Somers timespecsub(&ts, &tts, &ts); 1380e1ff74c0SDmitry Chagin if (!timespecisset(&ts) || ts.tv_sec > 0) 1381e1ff74c0SDmitry Chagin break; 1382e1ff74c0SDmitry Chagin } 1383e1ff74c0SDmitry Chagin /* Out of band data, return right away. */ 1384e1ff74c0SDmitry Chagin if (bsd_msg.msg_flags & MSG_OOB) 1385e1ff74c0SDmitry Chagin break; 1386e1ff74c0SDmitry Chagin } 1387e1ff74c0SDmitry Chagin if (error == 0) 1388e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1389e1ff74c0SDmitry Chagin return (error); 1390e1ff74c0SDmitry Chagin } 1391e1ff74c0SDmitry Chagin 1392e1ff74c0SDmitry Chagin int 1393b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1394c21dee17SSøren Schmidt { 1395c21dee17SSøren Schmidt 1396d293f35cSEdward Tomasz Napierala return (kern_shutdown(td, args->s, args->how)); 1397c21dee17SSøren Schmidt } 1398c21dee17SSøren Schmidt 1399a12b9b3dSDmitry Chagin int 1400b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1401c21dee17SSøren Schmidt { 140203cc95d2SDmitry Chagin l_timeval linux_tv; 1403d5368bf3SDmitry Chagin struct sockaddr *sa; 140403cc95d2SDmitry Chagin struct timeval tv; 1405d5368bf3SDmitry Chagin socklen_t len; 14069c6eb0f9SEdward Tomasz Napierala int error, level, name; 1407c21dee17SSøren Schmidt 14089c6eb0f9SEdward Tomasz Napierala level = linux_to_bsd_sockopt_level(args->level); 14099c6eb0f9SEdward Tomasz Napierala switch (level) { 1410c21dee17SSøren Schmidt case SOL_SOCKET: 1411745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 141203cc95d2SDmitry Chagin switch (name) { 141303cc95d2SDmitry Chagin case SO_RCVTIMEO: 141403cc95d2SDmitry Chagin /* FALLTHROUGH */ 141503cc95d2SDmitry Chagin case SO_SNDTIMEO: 141603cc95d2SDmitry Chagin error = copyin(PTRIN(args->optval), &linux_tv, 141703cc95d2SDmitry Chagin sizeof(linux_tv)); 1418dddb7e7fSDmitry Chagin if (error != 0) 141903cc95d2SDmitry Chagin return (error); 142003cc95d2SDmitry Chagin tv.tv_sec = linux_tv.tv_sec; 142103cc95d2SDmitry Chagin tv.tv_usec = linux_tv.tv_usec; 14229c6eb0f9SEdward Tomasz Napierala return (kern_setsockopt(td, args->s, level, 142303cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, sizeof(tv))); 142403cc95d2SDmitry Chagin /* NOTREACHED */ 142503cc95d2SDmitry Chagin default: 142603cc95d2SDmitry Chagin break; 142703cc95d2SDmitry Chagin } 1428c21dee17SSøren Schmidt break; 1429c21dee17SSøren Schmidt case IPPROTO_IP: 1430da6d8ae6SEdward Tomasz Napierala if (args->optname == LINUX_IP_RECVERR && 1431da6d8ae6SEdward Tomasz Napierala linux_ignore_ip_recverr) { 1432da6d8ae6SEdward Tomasz Napierala /* 1433da6d8ae6SEdward Tomasz Napierala * XXX: This is a hack to unbreak DNS resolution 1434da6d8ae6SEdward Tomasz Napierala * with glibc 2.30 and above. 1435da6d8ae6SEdward Tomasz Napierala */ 1436da6d8ae6SEdward Tomasz Napierala return (0); 1437da6d8ae6SEdward Tomasz Napierala } 1438745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1439c21dee17SSøren Schmidt break; 144086a9058bSAndrey V. Elsukov case IPPROTO_IPV6: 144186a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname); 144286a9058bSAndrey V. Elsukov break; 1443dad3b88aSMike Smith case IPPROTO_TCP: 1444fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1445dad3b88aSMike Smith break; 1446c21dee17SSøren Schmidt default: 14473f3a4815SMarcel Moolenaar name = -1; 14483f3a4815SMarcel Moolenaar break; 1449c21dee17SSøren Schmidt } 1450c21dee17SSøren Schmidt if (name == -1) 1451d4b7423fSAlexander Leidinger return (ENOPROTOOPT); 14523f3a4815SMarcel Moolenaar 1453d5368bf3SDmitry Chagin 1454d5368bf3SDmitry Chagin if (name == IPV6_NEXTHOP) { 1455d5368bf3SDmitry Chagin len = args->optlen; 1456d5368bf3SDmitry Chagin error = linux_to_bsd_sockaddr(PTRIN(args->optval), &sa, &len); 1457d5368bf3SDmitry Chagin if (error != 0) 1458d5368bf3SDmitry Chagin return (error); 1459d5368bf3SDmitry Chagin 14609c6eb0f9SEdward Tomasz Napierala error = kern_setsockopt(td, args->s, level, 1461d5368bf3SDmitry Chagin name, sa, UIO_SYSSPACE, len); 1462d5368bf3SDmitry Chagin free(sa, M_SONAME); 1463d5368bf3SDmitry Chagin } else { 14649c6eb0f9SEdward Tomasz Napierala error = kern_setsockopt(td, args->s, level, 14659c6eb0f9SEdward Tomasz Napierala name, PTRIN(args->optval), UIO_USERSPACE, args->optlen); 1466d5368bf3SDmitry Chagin } 14675c8919adSAlexander Leidinger 14685c8919adSAlexander Leidinger return (error); 1469c21dee17SSøren Schmidt } 1470c21dee17SSøren Schmidt 1471a12b9b3dSDmitry Chagin int 1472b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1473c21dee17SSøren Schmidt { 147403cc95d2SDmitry Chagin l_timeval linux_tv; 147503cc95d2SDmitry Chagin struct timeval tv; 1476d56e689eSDmitry Chagin socklen_t tv_len, xulen, len; 1477d5368bf3SDmitry Chagin struct l_sockaddr *lsa; 1478d5368bf3SDmitry Chagin struct sockaddr *sa; 1479d4dd69c4SDmitry Chagin struct xucred xu; 1480d4dd69c4SDmitry Chagin struct l_ucred lxu; 1481dfd060c0SEdward Tomasz Napierala int error, level, name, newval; 1482c21dee17SSøren Schmidt 1483dfd060c0SEdward Tomasz Napierala level = linux_to_bsd_sockopt_level(args->level); 1484dfd060c0SEdward Tomasz Napierala switch (level) { 1485c21dee17SSøren Schmidt case SOL_SOCKET: 1486745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 148703cc95d2SDmitry Chagin switch (name) { 148803cc95d2SDmitry Chagin case SO_RCVTIMEO: 148903cc95d2SDmitry Chagin /* FALLTHROUGH */ 149003cc95d2SDmitry Chagin case SO_SNDTIMEO: 149103cc95d2SDmitry Chagin tv_len = sizeof(tv); 1492dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 149303cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, &tv_len); 1494dddb7e7fSDmitry Chagin if (error != 0) 149503cc95d2SDmitry Chagin return (error); 149603cc95d2SDmitry Chagin linux_tv.tv_sec = tv.tv_sec; 149703cc95d2SDmitry Chagin linux_tv.tv_usec = tv.tv_usec; 149803cc95d2SDmitry Chagin return (copyout(&linux_tv, PTRIN(args->optval), 149903cc95d2SDmitry Chagin sizeof(linux_tv))); 150003cc95d2SDmitry Chagin /* NOTREACHED */ 1501d4dd69c4SDmitry Chagin case LOCAL_PEERCRED: 1502cd92d27eSDmitry Chagin if (args->optlen < sizeof(lxu)) 1503d4dd69c4SDmitry Chagin return (EINVAL); 1504bb376a99SMark Johnston /* 1505bb376a99SMark Johnston * LOCAL_PEERCRED is not served at the SOL_SOCKET level, 1506bb376a99SMark Johnston * but by the Unix socket's level 0. 1507bb376a99SMark Johnston */ 1508dfd060c0SEdward Tomasz Napierala level = 0; 1509d4dd69c4SDmitry Chagin xulen = sizeof(xu); 1510dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1511d4dd69c4SDmitry Chagin name, &xu, UIO_SYSSPACE, &xulen); 1512dddb7e7fSDmitry Chagin if (error != 0) 1513d4dd69c4SDmitry Chagin return (error); 1514c5afec6eSDmitry Chagin lxu.pid = xu.cr_pid; 1515d4dd69c4SDmitry Chagin lxu.uid = xu.cr_uid; 1516d4dd69c4SDmitry Chagin lxu.gid = xu.cr_gid; 1517d4dd69c4SDmitry Chagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1518d4dd69c4SDmitry Chagin /* NOTREACHED */ 1519d56e689eSDmitry Chagin case SO_ERROR: 1520d56e689eSDmitry Chagin len = sizeof(newval); 1521dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1522d56e689eSDmitry Chagin name, &newval, UIO_SYSSPACE, &len); 1523dddb7e7fSDmitry Chagin if (error != 0) 1524d56e689eSDmitry Chagin return (error); 1525d56e689eSDmitry Chagin newval = -SV_ABI_ERRNO(td->td_proc, newval); 1526d56e689eSDmitry Chagin return (copyout(&newval, PTRIN(args->optval), len)); 1527d56e689eSDmitry Chagin /* NOTREACHED */ 152803cc95d2SDmitry Chagin default: 152903cc95d2SDmitry Chagin break; 153003cc95d2SDmitry Chagin } 1531c21dee17SSøren Schmidt break; 1532c21dee17SSøren Schmidt case IPPROTO_IP: 1533745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1534c21dee17SSøren Schmidt break; 153586a9058bSAndrey V. Elsukov case IPPROTO_IPV6: 153686a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname); 153786a9058bSAndrey V. Elsukov break; 1538dad3b88aSMike Smith case IPPROTO_TCP: 1539fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1540dad3b88aSMike Smith break; 1541c21dee17SSøren Schmidt default: 15423f3a4815SMarcel Moolenaar name = -1; 15433f3a4815SMarcel Moolenaar break; 1544c21dee17SSøren Schmidt } 1545c21dee17SSøren Schmidt if (name == -1) 15463f3a4815SMarcel Moolenaar return (EINVAL); 15473f3a4815SMarcel Moolenaar 15485c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) { 1549d5368bf3SDmitry Chagin error = copyin(PTRIN(args->optlen), &len, sizeof(len)); 1550d5368bf3SDmitry Chagin if (error != 0) 1551d5368bf3SDmitry Chagin return (error); 1552d5368bf3SDmitry Chagin sa = malloc(len, M_SONAME, M_WAITOK); 1553d5368bf3SDmitry Chagin 1554dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1555d5368bf3SDmitry Chagin name, sa, UIO_SYSSPACE, &len); 1556d5368bf3SDmitry Chagin if (error != 0) 1557d5368bf3SDmitry Chagin goto out; 1558d5368bf3SDmitry Chagin 1559d5368bf3SDmitry Chagin error = bsd_to_linux_sockaddr(sa, &lsa, len); 1560d5368bf3SDmitry Chagin if (error == 0) 1561d5368bf3SDmitry Chagin error = copyout(lsa, PTRIN(args->optval), len); 1562d5368bf3SDmitry Chagin free(lsa, M_SONAME); 1563d5368bf3SDmitry Chagin if (error == 0) 1564d5368bf3SDmitry Chagin error = copyout(&len, PTRIN(args->optlen), 1565d5368bf3SDmitry Chagin sizeof(len)); 1566d5368bf3SDmitry Chagin out: 1567d5368bf3SDmitry Chagin free(sa, M_SONAME); 1568d5368bf3SDmitry Chagin } else { 1569dfd060c0SEdward Tomasz Napierala if (args->optval) { 1570dfd060c0SEdward Tomasz Napierala error = copyin(PTRIN(args->optlen), &len, sizeof(len)); 1571dfd060c0SEdward Tomasz Napierala if (error != 0) 1572dfd060c0SEdward Tomasz Napierala return (error); 1573dfd060c0SEdward Tomasz Napierala } 1574dfd060c0SEdward Tomasz Napierala error = kern_getsockopt(td, args->s, level, 1575dfd060c0SEdward Tomasz Napierala name, PTRIN(args->optval), UIO_USERSPACE, &len); 1576dfd060c0SEdward Tomasz Napierala if (error == 0) 1577dfd060c0SEdward Tomasz Napierala error = copyout(&len, PTRIN(args->optlen), 1578dfd060c0SEdward Tomasz Napierala sizeof(len)); 1579d5368bf3SDmitry Chagin } 15805c8919adSAlexander Leidinger 15815c8919adSAlexander Leidinger return (error); 1582c21dee17SSøren Schmidt } 1583c21dee17SSøren Schmidt 15847f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 15857f8f1d7fSDmitry Chagin 1586ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */ 1587abf20e93SDmitry Chagin static const unsigned char lxs_args_cnt[] = { 1588abf20e93SDmitry Chagin 0 /* unused*/, 3 /* socket */, 1589abf20e93SDmitry Chagin 3 /* bind */, 3 /* connect */, 1590abf20e93SDmitry Chagin 2 /* listen */, 3 /* accept */, 1591abf20e93SDmitry Chagin 3 /* getsockname */, 3 /* getpeername */, 1592abf20e93SDmitry Chagin 4 /* socketpair */, 4 /* send */, 1593abf20e93SDmitry Chagin 4 /* recv */, 6 /* sendto */, 1594abf20e93SDmitry Chagin 6 /* recvfrom */, 2 /* shutdown */, 1595abf20e93SDmitry Chagin 5 /* setsockopt */, 5 /* getsockopt */, 1596abf20e93SDmitry Chagin 3 /* sendmsg */, 3 /* recvmsg */, 1597abf20e93SDmitry Chagin 4 /* accept4 */, 5 /* recvmmsg */, 1598abf20e93SDmitry Chagin 4 /* sendmmsg */ 1599ea7b81d2SDmitry Chagin }; 1600abf20e93SDmitry Chagin #define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1) 1601abf20e93SDmitry Chagin #define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong)) 1602ea7b81d2SDmitry Chagin 1603c21dee17SSøren Schmidt int 1604b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1605c21dee17SSøren Schmidt { 1606ea7b81d2SDmitry Chagin l_ulong a[6]; 1607abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32) 1608abf20e93SDmitry Chagin register_t l_args[6]; 1609abf20e93SDmitry Chagin #endif 1610ea7b81d2SDmitry Chagin void *arg; 1611ea7b81d2SDmitry Chagin int error; 16123f3a4815SMarcel Moolenaar 1613abf20e93SDmitry Chagin if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT) 1614ea7b81d2SDmitry Chagin return (EINVAL); 1615abf20e93SDmitry Chagin error = copyin(PTRIN(args->args), a, LINUX_ARG_SIZE(args->what)); 1616abf20e93SDmitry Chagin if (error != 0) 1617ea7b81d2SDmitry Chagin return (error); 1618ea7b81d2SDmitry Chagin 1619abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32) 1620abf20e93SDmitry Chagin for (int i = 0; i < lxs_args_cnt[args->what]; ++i) 1621abf20e93SDmitry Chagin l_args[i] = a[i]; 1622abf20e93SDmitry Chagin arg = l_args; 1623abf20e93SDmitry Chagin #else 1624ea7b81d2SDmitry Chagin arg = a; 1625abf20e93SDmitry Chagin #endif 1626c21dee17SSøren Schmidt switch (args->what) { 1627c21dee17SSøren Schmidt case LINUX_SOCKET: 1628b40ce416SJulian Elischer return (linux_socket(td, arg)); 1629c21dee17SSøren Schmidt case LINUX_BIND: 1630b40ce416SJulian Elischer return (linux_bind(td, arg)); 1631c21dee17SSøren Schmidt case LINUX_CONNECT: 1632b40ce416SJulian Elischer return (linux_connect(td, arg)); 1633c21dee17SSøren Schmidt case LINUX_LISTEN: 1634b40ce416SJulian Elischer return (linux_listen(td, arg)); 1635c21dee17SSøren Schmidt case LINUX_ACCEPT: 1636b40ce416SJulian Elischer return (linux_accept(td, arg)); 1637c21dee17SSøren Schmidt case LINUX_GETSOCKNAME: 1638b40ce416SJulian Elischer return (linux_getsockname(td, arg)); 1639c21dee17SSøren Schmidt case LINUX_GETPEERNAME: 1640b40ce416SJulian Elischer return (linux_getpeername(td, arg)); 1641c21dee17SSøren Schmidt case LINUX_SOCKETPAIR: 1642b40ce416SJulian Elischer return (linux_socketpair(td, arg)); 1643c21dee17SSøren Schmidt case LINUX_SEND: 1644b40ce416SJulian Elischer return (linux_send(td, arg)); 1645c21dee17SSøren Schmidt case LINUX_RECV: 1646b40ce416SJulian Elischer return (linux_recv(td, arg)); 1647c21dee17SSøren Schmidt case LINUX_SENDTO: 1648b40ce416SJulian Elischer return (linux_sendto(td, arg)); 1649c21dee17SSøren Schmidt case LINUX_RECVFROM: 1650b40ce416SJulian Elischer return (linux_recvfrom(td, arg)); 1651c21dee17SSøren Schmidt case LINUX_SHUTDOWN: 1652b40ce416SJulian Elischer return (linux_shutdown(td, arg)); 1653c21dee17SSøren Schmidt case LINUX_SETSOCKOPT: 1654b40ce416SJulian Elischer return (linux_setsockopt(td, arg)); 1655c21dee17SSøren Schmidt case LINUX_GETSOCKOPT: 1656b40ce416SJulian Elischer return (linux_getsockopt(td, arg)); 1657e76bba09SSøren Schmidt case LINUX_SENDMSG: 1658ca26842eSHajimu UMEMOTO return (linux_sendmsg(td, arg)); 1659e76bba09SSøren Schmidt case LINUX_RECVMSG: 1660b40ce416SJulian Elischer return (linux_recvmsg(td, arg)); 1661f8cd0af2SDmitry Chagin case LINUX_ACCEPT4: 1662f8cd0af2SDmitry Chagin return (linux_accept4(td, arg)); 1663e1ff74c0SDmitry Chagin case LINUX_RECVMMSG: 1664e1ff74c0SDmitry Chagin return (linux_recvmmsg(td, arg)); 1665e1ff74c0SDmitry Chagin case LINUX_SENDMMSG: 1666e1ff74c0SDmitry Chagin return (linux_sendmmsg(td, arg)); 1667c21dee17SSøren Schmidt } 16683f3a4815SMarcel Moolenaar 16693f3a4815SMarcel Moolenaar uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 16703f3a4815SMarcel Moolenaar return (ENOSYS); 1671c21dee17SSøren Schmidt } 1672a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1673