1c21dee17SSøren Schmidt /*- 29a14aa01SUlrich Spörlein * Copyright (c) 1995 Søren Schmidt 3c21dee17SSøren Schmidt * All rights reserved. 4c21dee17SSøren Schmidt * 5c21dee17SSøren Schmidt * Redistribution and use in source and binary forms, with or without 6c21dee17SSøren Schmidt * modification, are permitted provided that the following conditions 7c21dee17SSøren Schmidt * are met: 8c21dee17SSøren Schmidt * 1. Redistributions of source code must retain the above copyright 9c21dee17SSøren Schmidt * notice, this list of conditions and the following disclaimer 10c21dee17SSøren Schmidt * in this position and unchanged. 11c21dee17SSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 12c21dee17SSøren Schmidt * notice, this list of conditions and the following disclaimer in the 13c21dee17SSøren Schmidt * documentation and/or other materials provided with the distribution. 14c21dee17SSøren Schmidt * 3. The name of the author may not be used to endorse or promote products 1521dc7d4fSJens Schweikhardt * derived from this software without specific prior written permission 16c21dee17SSøren Schmidt * 17c21dee17SSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18c21dee17SSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19c21dee17SSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20c21dee17SSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21c21dee17SSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22c21dee17SSøren Schmidt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23c21dee17SSøren Schmidt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24c21dee17SSøren Schmidt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25c21dee17SSøren Schmidt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26c21dee17SSøren Schmidt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 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 734d0f380dSDmitry Chagin #include <compat/linux/linux_file.h> 7440dbba57SAssar Westerlund #include <compat/linux/linux_socket.h> 75e1ff74c0SDmitry Chagin #include <compat/linux/linux_timer.h> 76ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h> 77c21dee17SSøren Schmidt 78ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int); 79e1ff74c0SDmitry Chagin static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *, 80e1ff74c0SDmitry Chagin l_uint); 81e1ff74c0SDmitry Chagin static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *, 82e1ff74c0SDmitry Chagin l_uint, struct msghdr *); 834cf10e29SDmitry Chagin static int linux_set_socket_flags(int, int *); 84ca26842eSHajimu UMEMOTO 854730796cSBill Fenner /* 86ca26842eSHajimu UMEMOTO * Reads a linux sockaddr and does any necessary translation. 87ca26842eSHajimu UMEMOTO * Linux sockaddrs don't have a length field, only a family. 88ca26842eSHajimu UMEMOTO * Copy the osockaddr structure pointed to by osa to kernel, adjust 89ca26842eSHajimu UMEMOTO * family and convert to sockaddr. 90ca26842eSHajimu UMEMOTO */ 91ca26842eSHajimu UMEMOTO static int 92b6f96462SJung-uk Kim linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen) 93ca26842eSHajimu UMEMOTO { 94ca26842eSHajimu UMEMOTO struct sockaddr *sa; 95ca26842eSHajimu UMEMOTO struct osockaddr *kosa; 96ca26842eSHajimu UMEMOTO #ifdef INET6 97ca26842eSHajimu UMEMOTO struct sockaddr_in6 *sin6; 983106d670SJung-uk Kim int oldv6size; 99ca26842eSHajimu UMEMOTO #endif 100c02637c7SJung-uk Kim char *name; 101b6f96462SJung-uk Kim int bdom, error, hdrlen, namelen; 102ca26842eSHajimu UMEMOTO 103b6f96462SJung-uk Kim if (salen < 2 || salen > UCHAR_MAX || !osa) 104ca26842eSHajimu UMEMOTO return (EINVAL); 105ca26842eSHajimu UMEMOTO 106ca26842eSHajimu UMEMOTO #ifdef INET6 107ca26842eSHajimu UMEMOTO oldv6size = 0; 108ca26842eSHajimu UMEMOTO /* 109ca26842eSHajimu UMEMOTO * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 110ca26842eSHajimu UMEMOTO * if it's a v4-mapped address, so reserve the proper space 111ca26842eSHajimu UMEMOTO * for it. 112ca26842eSHajimu UMEMOTO */ 113b6f96462SJung-uk Kim if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { 114b6f96462SJung-uk Kim salen += sizeof(uint32_t); 115ca26842eSHajimu UMEMOTO oldv6size = 1; 116ca26842eSHajimu UMEMOTO } 117ca26842eSHajimu UMEMOTO #endif 118ca26842eSHajimu UMEMOTO 119b6f96462SJung-uk Kim kosa = malloc(salen, M_SONAME, M_WAITOK); 120ca26842eSHajimu UMEMOTO 121b6f96462SJung-uk Kim if ((error = copyin(osa, kosa, salen))) 122ca26842eSHajimu UMEMOTO goto out; 123ca26842eSHajimu UMEMOTO 124ca26842eSHajimu UMEMOTO bdom = linux_to_bsd_domain(kosa->sa_family); 125ca26842eSHajimu UMEMOTO if (bdom == -1) { 1265cb9c68cSXin LI error = EAFNOSUPPORT; 127ca26842eSHajimu UMEMOTO goto out; 128ca26842eSHajimu UMEMOTO } 129ca26842eSHajimu UMEMOTO 130ca26842eSHajimu UMEMOTO #ifdef INET6 131ca26842eSHajimu UMEMOTO /* 132ca26842eSHajimu UMEMOTO * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 133ca26842eSHajimu UMEMOTO * which lacks the scope id compared with RFC2553 one. If we detect 134ca26842eSHajimu UMEMOTO * the situation, reject the address and write a message to system log. 135ca26842eSHajimu UMEMOTO * 136ca26842eSHajimu UMEMOTO * Still accept addresses for which the scope id is not used. 137ca26842eSHajimu UMEMOTO */ 138f05531a3SJung-uk Kim if (oldv6size) { 139f05531a3SJung-uk Kim if (bdom == AF_INET6) { 140ca26842eSHajimu UMEMOTO sin6 = (struct sockaddr_in6 *)kosa; 141ca26842eSHajimu UMEMOTO if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 142ca26842eSHajimu UMEMOTO (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 143ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 144ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 145ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 146ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 147ca26842eSHajimu UMEMOTO sin6->sin6_scope_id = 0; 148ca26842eSHajimu UMEMOTO } else { 149ca26842eSHajimu UMEMOTO log(LOG_DEBUG, 1503c616032SGleb Smirnoff "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); 151ca26842eSHajimu UMEMOTO error = EINVAL; 152ca26842eSHajimu UMEMOTO goto out; 153ca26842eSHajimu UMEMOTO } 154ca26842eSHajimu UMEMOTO } else 155b6f96462SJung-uk Kim salen -= sizeof(uint32_t); 156f05531a3SJung-uk Kim } 157ca26842eSHajimu UMEMOTO #endif 1585cb9c68cSXin LI if (bdom == AF_INET) { 159b6f96462SJung-uk Kim if (salen < sizeof(struct sockaddr_in)) { 1605cb9c68cSXin LI error = EINVAL; 1615cb9c68cSXin LI goto out; 1625cb9c68cSXin LI } 163b6f96462SJung-uk Kim salen = sizeof(struct sockaddr_in); 1645cb9c68cSXin LI } 165ca26842eSHajimu UMEMOTO 166b6f96462SJung-uk Kim if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) { 167c15cdbf2SJung-uk Kim hdrlen = offsetof(struct sockaddr_un, sun_path); 168c02637c7SJung-uk Kim name = ((struct sockaddr_un *)kosa)->sun_path; 169c02637c7SJung-uk Kim if (*name == '\0') { 170c02637c7SJung-uk Kim /* 171c02637c7SJung-uk Kim * Linux abstract namespace starts with a NULL byte. 172c02637c7SJung-uk Kim * XXX We do not support abstract namespace yet. 173c02637c7SJung-uk Kim */ 174b6f96462SJung-uk Kim namelen = strnlen(name + 1, salen - hdrlen - 1) + 1; 175c02637c7SJung-uk Kim } else 176b6f96462SJung-uk Kim namelen = strnlen(name, salen - hdrlen); 177bf3a36ccSJung-uk Kim salen = hdrlen + namelen; 178bf3a36ccSJung-uk Kim if (salen > sizeof(struct sockaddr_un)) { 17943399111SJung-uk Kim error = ENAMETOOLONG; 1805da3eb94SColin Percival goto out; 1815da3eb94SColin Percival } 1825da3eb94SColin Percival } 1835da3eb94SColin Percival 184ca26842eSHajimu UMEMOTO sa = (struct sockaddr *)kosa; 185ca26842eSHajimu UMEMOTO sa->sa_family = bdom; 186b6f96462SJung-uk Kim sa->sa_len = salen; 187ca26842eSHajimu UMEMOTO 188ca26842eSHajimu UMEMOTO *sap = sa; 189ca26842eSHajimu UMEMOTO return (0); 190ca26842eSHajimu UMEMOTO 191ca26842eSHajimu UMEMOTO out: 1920007f669SJung-uk Kim free(kosa, M_SONAME); 193ca26842eSHajimu UMEMOTO return (error); 194ca26842eSHajimu UMEMOTO } 195ca26842eSHajimu UMEMOTO 196c21dee17SSøren Schmidt static int 197c21dee17SSøren Schmidt linux_to_bsd_domain(int domain) 198c21dee17SSøren Schmidt { 1993f3a4815SMarcel Moolenaar 200c21dee17SSøren Schmidt switch (domain) { 201c21dee17SSøren Schmidt case LINUX_AF_UNSPEC: 2023f3a4815SMarcel Moolenaar return (AF_UNSPEC); 203c21dee17SSøren Schmidt case LINUX_AF_UNIX: 2043f3a4815SMarcel Moolenaar return (AF_LOCAL); 205c21dee17SSøren Schmidt case LINUX_AF_INET: 2063f3a4815SMarcel Moolenaar return (AF_INET); 207ca26842eSHajimu UMEMOTO case LINUX_AF_INET6: 208ca26842eSHajimu UMEMOTO return (AF_INET6); 209c21dee17SSøren Schmidt case LINUX_AF_AX25: 2103f3a4815SMarcel Moolenaar return (AF_CCITT); 211c21dee17SSøren Schmidt case LINUX_AF_IPX: 2123f3a4815SMarcel Moolenaar return (AF_IPX); 213c21dee17SSøren Schmidt case LINUX_AF_APPLETALK: 2143f3a4815SMarcel Moolenaar return (AF_APPLETALK); 215c21dee17SSøren Schmidt } 2163f3a4815SMarcel Moolenaar return (-1); 217c21dee17SSøren Schmidt } 218c21dee17SSøren Schmidt 219ca26842eSHajimu UMEMOTO static int 220ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain) 221ca26842eSHajimu UMEMOTO { 222ca26842eSHajimu UMEMOTO 223ca26842eSHajimu UMEMOTO switch (domain) { 224ca26842eSHajimu UMEMOTO case AF_UNSPEC: 225ca26842eSHajimu UMEMOTO return (LINUX_AF_UNSPEC); 226ca26842eSHajimu UMEMOTO case AF_LOCAL: 227ca26842eSHajimu UMEMOTO return (LINUX_AF_UNIX); 228ca26842eSHajimu UMEMOTO case AF_INET: 229ca26842eSHajimu UMEMOTO return (LINUX_AF_INET); 230ca26842eSHajimu UMEMOTO case AF_INET6: 231ca26842eSHajimu UMEMOTO return (LINUX_AF_INET6); 232ca26842eSHajimu UMEMOTO case AF_CCITT: 233ca26842eSHajimu UMEMOTO return (LINUX_AF_AX25); 234ca26842eSHajimu UMEMOTO case AF_IPX: 235ca26842eSHajimu UMEMOTO return (LINUX_AF_IPX); 236ca26842eSHajimu UMEMOTO case AF_APPLETALK: 237ca26842eSHajimu UMEMOTO return (LINUX_AF_APPLETALK); 238ca26842eSHajimu UMEMOTO } 239ca26842eSHajimu UMEMOTO return (-1); 240ca26842eSHajimu UMEMOTO } 241ca26842eSHajimu UMEMOTO 242c21dee17SSøren Schmidt static int 243c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level) 244c21dee17SSøren Schmidt { 2453f3a4815SMarcel Moolenaar 246c21dee17SSøren Schmidt switch (level) { 247c21dee17SSøren Schmidt case LINUX_SOL_SOCKET: 2483f3a4815SMarcel Moolenaar return (SOL_SOCKET); 249c21dee17SSøren Schmidt } 2503f3a4815SMarcel Moolenaar return (level); 251c21dee17SSøren Schmidt } 252c21dee17SSøren Schmidt 2533f3a4815SMarcel Moolenaar static int 25484b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level) 25584b11cd8SMitsuru IWASAKI { 25684b11cd8SMitsuru IWASAKI 25784b11cd8SMitsuru IWASAKI switch (level) { 25884b11cd8SMitsuru IWASAKI case SOL_SOCKET: 25984b11cd8SMitsuru IWASAKI return (LINUX_SOL_SOCKET); 26084b11cd8SMitsuru IWASAKI } 26184b11cd8SMitsuru IWASAKI return (level); 26284b11cd8SMitsuru IWASAKI } 26384b11cd8SMitsuru IWASAKI 26484b11cd8SMitsuru IWASAKI static int 2653f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt) 266c21dee17SSøren Schmidt { 2673f3a4815SMarcel Moolenaar 268c21dee17SSøren Schmidt switch (opt) { 269c21dee17SSøren Schmidt case LINUX_IP_TOS: 2703f3a4815SMarcel Moolenaar return (IP_TOS); 271c21dee17SSøren Schmidt case LINUX_IP_TTL: 2723f3a4815SMarcel Moolenaar return (IP_TTL); 27366ff6a3cSBill Fenner case LINUX_IP_OPTIONS: 2743f3a4815SMarcel Moolenaar return (IP_OPTIONS); 27566ff6a3cSBill Fenner case LINUX_IP_MULTICAST_IF: 2763f3a4815SMarcel Moolenaar return (IP_MULTICAST_IF); 27766ff6a3cSBill Fenner case LINUX_IP_MULTICAST_TTL: 2783f3a4815SMarcel Moolenaar return (IP_MULTICAST_TTL); 27966ff6a3cSBill Fenner case LINUX_IP_MULTICAST_LOOP: 2803f3a4815SMarcel Moolenaar return (IP_MULTICAST_LOOP); 28166ff6a3cSBill Fenner case LINUX_IP_ADD_MEMBERSHIP: 2823f3a4815SMarcel Moolenaar return (IP_ADD_MEMBERSHIP); 28366ff6a3cSBill Fenner case LINUX_IP_DROP_MEMBERSHIP: 2843f3a4815SMarcel Moolenaar return (IP_DROP_MEMBERSHIP); 28566ff6a3cSBill Fenner case LINUX_IP_HDRINCL: 2863f3a4815SMarcel Moolenaar return (IP_HDRINCL); 287c21dee17SSøren Schmidt } 2883f3a4815SMarcel Moolenaar return (-1); 289c21dee17SSøren Schmidt } 290c21dee17SSøren Schmidt 291c21dee17SSøren Schmidt static int 292c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt) 293c21dee17SSøren Schmidt { 2943f3a4815SMarcel Moolenaar 295c21dee17SSøren Schmidt switch (opt) { 296c21dee17SSøren Schmidt case LINUX_SO_DEBUG: 2973f3a4815SMarcel Moolenaar return (SO_DEBUG); 298c21dee17SSøren Schmidt case LINUX_SO_REUSEADDR: 2993f3a4815SMarcel Moolenaar return (SO_REUSEADDR); 300c21dee17SSøren Schmidt case LINUX_SO_TYPE: 3013f3a4815SMarcel Moolenaar return (SO_TYPE); 302c21dee17SSøren Schmidt case LINUX_SO_ERROR: 3033f3a4815SMarcel Moolenaar return (SO_ERROR); 304c21dee17SSøren Schmidt case LINUX_SO_DONTROUTE: 3053f3a4815SMarcel Moolenaar return (SO_DONTROUTE); 306c21dee17SSøren Schmidt case LINUX_SO_BROADCAST: 3073f3a4815SMarcel Moolenaar return (SO_BROADCAST); 308c21dee17SSøren Schmidt case LINUX_SO_SNDBUF: 3093f3a4815SMarcel Moolenaar return (SO_SNDBUF); 310c21dee17SSøren Schmidt case LINUX_SO_RCVBUF: 3113f3a4815SMarcel Moolenaar return (SO_RCVBUF); 312c21dee17SSøren Schmidt case LINUX_SO_KEEPALIVE: 3133f3a4815SMarcel Moolenaar return (SO_KEEPALIVE); 314c21dee17SSøren Schmidt case LINUX_SO_OOBINLINE: 3153f3a4815SMarcel Moolenaar return (SO_OOBINLINE); 316c21dee17SSøren Schmidt case LINUX_SO_LINGER: 3173f3a4815SMarcel Moolenaar return (SO_LINGER); 318d0b2365eSKonstantin Belousov case LINUX_SO_PEERCRED: 319d0b2365eSKonstantin Belousov return (LOCAL_PEERCRED); 320d0b2365eSKonstantin Belousov case LINUX_SO_RCVLOWAT: 321d0b2365eSKonstantin Belousov return (SO_RCVLOWAT); 322d0b2365eSKonstantin Belousov case LINUX_SO_SNDLOWAT: 323d0b2365eSKonstantin Belousov return (SO_SNDLOWAT); 324d0b2365eSKonstantin Belousov case LINUX_SO_RCVTIMEO: 325d0b2365eSKonstantin Belousov return (SO_RCVTIMEO); 326d0b2365eSKonstantin Belousov case LINUX_SO_SNDTIMEO: 327d0b2365eSKonstantin Belousov return (SO_SNDTIMEO); 328d0b2365eSKonstantin Belousov case LINUX_SO_TIMESTAMP: 329d0b2365eSKonstantin Belousov return (SO_TIMESTAMP); 330d0b2365eSKonstantin Belousov case LINUX_SO_ACCEPTCONN: 331d0b2365eSKonstantin Belousov return (SO_ACCEPTCONN); 332c21dee17SSøren Schmidt } 3333f3a4815SMarcel Moolenaar return (-1); 334c21dee17SSøren Schmidt } 335c21dee17SSøren Schmidt 33640dbba57SAssar Westerlund static int 337fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt) 338fb709557SJohn Baldwin { 339fb709557SJohn Baldwin 340fb709557SJohn Baldwin switch (opt) { 341fb709557SJohn Baldwin case LINUX_TCP_NODELAY: 342fb709557SJohn Baldwin return (TCP_NODELAY); 343fb709557SJohn Baldwin case LINUX_TCP_MAXSEG: 344fb709557SJohn Baldwin return (TCP_MAXSEG); 345fb709557SJohn Baldwin case LINUX_TCP_KEEPIDLE: 346fb709557SJohn Baldwin return (TCP_KEEPIDLE); 347fb709557SJohn Baldwin case LINUX_TCP_KEEPINTVL: 348fb709557SJohn Baldwin return (TCP_KEEPINTVL); 349fb709557SJohn Baldwin case LINUX_TCP_KEEPCNT: 350fb709557SJohn Baldwin return (TCP_KEEPCNT); 351fb709557SJohn Baldwin case LINUX_TCP_MD5SIG: 352fb709557SJohn Baldwin return (TCP_MD5SIG); 353fb709557SJohn Baldwin } 354fb709557SJohn Baldwin return (-1); 355fb709557SJohn Baldwin } 356fb709557SJohn Baldwin 357fb709557SJohn Baldwin static int 35840dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags) 35940dbba57SAssar Westerlund { 36040dbba57SAssar Westerlund int ret_flags = 0; 36140dbba57SAssar Westerlund 36240dbba57SAssar Westerlund if (flags & LINUX_MSG_OOB) 36340dbba57SAssar Westerlund ret_flags |= MSG_OOB; 36440dbba57SAssar Westerlund if (flags & LINUX_MSG_PEEK) 36540dbba57SAssar Westerlund ret_flags |= MSG_PEEK; 36640dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTROUTE) 36740dbba57SAssar Westerlund ret_flags |= MSG_DONTROUTE; 36840dbba57SAssar Westerlund if (flags & LINUX_MSG_CTRUNC) 36940dbba57SAssar Westerlund ret_flags |= MSG_CTRUNC; 37040dbba57SAssar Westerlund if (flags & LINUX_MSG_TRUNC) 37140dbba57SAssar Westerlund ret_flags |= MSG_TRUNC; 37240dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTWAIT) 37340dbba57SAssar Westerlund ret_flags |= MSG_DONTWAIT; 37440dbba57SAssar Westerlund if (flags & LINUX_MSG_EOR) 37540dbba57SAssar Westerlund ret_flags |= MSG_EOR; 37640dbba57SAssar Westerlund if (flags & LINUX_MSG_WAITALL) 37740dbba57SAssar Westerlund ret_flags |= MSG_WAITALL; 3788d6e40c3SMaxim Sobolev if (flags & LINUX_MSG_NOSIGNAL) 3798d6e40c3SMaxim Sobolev ret_flags |= MSG_NOSIGNAL; 38040dbba57SAssar Westerlund #if 0 /* not handled */ 38140dbba57SAssar Westerlund if (flags & LINUX_MSG_PROXY) 38240dbba57SAssar Westerlund ; 38340dbba57SAssar Westerlund if (flags & LINUX_MSG_FIN) 38440dbba57SAssar Westerlund ; 38540dbba57SAssar Westerlund if (flags & LINUX_MSG_SYN) 38640dbba57SAssar Westerlund ; 38740dbba57SAssar Westerlund if (flags & LINUX_MSG_CONFIRM) 38840dbba57SAssar Westerlund ; 38940dbba57SAssar Westerlund if (flags & LINUX_MSG_RST) 39040dbba57SAssar Westerlund ; 39140dbba57SAssar Westerlund if (flags & LINUX_MSG_ERRQUEUE) 39240dbba57SAssar Westerlund ; 39340dbba57SAssar Westerlund #endif 39440dbba57SAssar Westerlund return ret_flags; 39540dbba57SAssar Westerlund } 39640dbba57SAssar Westerlund 3975c8919adSAlexander Leidinger /* 3985c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the 3995c8919adSAlexander Leidinger * native syscall will fault. Thus, we don't really need to check the 4005c8919adSAlexander Leidinger * return values for these functions. 4015c8919adSAlexander Leidinger */ 4025c8919adSAlexander Leidinger 4035c8919adSAlexander Leidinger static int 4045c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg) 4055c8919adSAlexander Leidinger { 4065c8919adSAlexander Leidinger struct sockaddr sa; 4075c8919adSAlexander Leidinger size_t sa_len = sizeof(struct sockaddr); 4085c8919adSAlexander Leidinger int error; 4095c8919adSAlexander Leidinger 4105c8919adSAlexander Leidinger if ((error = copyin(arg, &sa, sa_len))) 4115c8919adSAlexander Leidinger return (error); 4125c8919adSAlexander Leidinger 4135c8919adSAlexander Leidinger *(u_short *)&sa = sa.sa_family; 4145c8919adSAlexander Leidinger 4155c8919adSAlexander Leidinger error = copyout(&sa, arg, sa_len); 4165c8919adSAlexander Leidinger 4175c8919adSAlexander Leidinger return (error); 4185c8919adSAlexander Leidinger } 4195c8919adSAlexander Leidinger 4205c8919adSAlexander Leidinger static int 4215c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len) 4225c8919adSAlexander Leidinger { 4235c8919adSAlexander Leidinger struct sockaddr sa; 4245c8919adSAlexander Leidinger size_t sa_len = sizeof(struct sockaddr); 4255c8919adSAlexander Leidinger int error; 4265c8919adSAlexander Leidinger 4275c8919adSAlexander Leidinger if ((error = copyin(arg, &sa, sa_len))) 4285c8919adSAlexander Leidinger return (error); 4295c8919adSAlexander Leidinger 4305c8919adSAlexander Leidinger sa.sa_family = *(sa_family_t *)&sa; 4315c8919adSAlexander Leidinger sa.sa_len = len; 4325c8919adSAlexander Leidinger 4335c8919adSAlexander Leidinger error = copyout(&sa, arg, sa_len); 4345c8919adSAlexander Leidinger 4355c8919adSAlexander Leidinger return (error); 4365c8919adSAlexander Leidinger } 4375c8919adSAlexander Leidinger 438ca26842eSHajimu UMEMOTO static int 439ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa) 440ca26842eSHajimu UMEMOTO { 441ca26842eSHajimu UMEMOTO struct osockaddr sa; 442ca26842eSHajimu UMEMOTO int error, bdom; 443ca26842eSHajimu UMEMOTO 444ca26842eSHajimu UMEMOTO /* 445ca26842eSHajimu UMEMOTO * Only read/write the osockaddr family part, the rest is 446ca26842eSHajimu UMEMOTO * not changed. 447ca26842eSHajimu UMEMOTO */ 4484b7ef73dSDag-Erling Smørgrav error = copyin(osa, &sa, sizeof(sa.sa_family)); 449ca26842eSHajimu UMEMOTO if (error) 450ca26842eSHajimu UMEMOTO return (error); 451ca26842eSHajimu UMEMOTO 452ca26842eSHajimu UMEMOTO bdom = bsd_to_linux_domain(sa.sa_family); 453ca26842eSHajimu UMEMOTO if (bdom == -1) 454ca26842eSHajimu UMEMOTO return (EINVAL); 455ca26842eSHajimu UMEMOTO 456ca26842eSHajimu UMEMOTO sa.sa_family = bdom; 457ca26842eSHajimu UMEMOTO error = copyout(&sa, osa, sizeof(sa.sa_family)); 458ca26842eSHajimu UMEMOTO if (error) 459ca26842eSHajimu UMEMOTO return (error); 460ca26842eSHajimu UMEMOTO 461ca26842eSHajimu UMEMOTO return (0); 462ca26842eSHajimu UMEMOTO } 463ca26842eSHajimu UMEMOTO 4645a8a13e0SDavid Malone static int 46574f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type) 4665a8a13e0SDavid Malone { 46774f5d680SKonstantin Belousov 46874f5d680SKonstantin Belousov switch (cmsg_type) { 46974f5d680SKonstantin Belousov case LINUX_SCM_RIGHTS: 47074f5d680SKonstantin Belousov return (SCM_RIGHTS); 471605da56bSAndriy Gapon case LINUX_SCM_CREDENTIALS: 472605da56bSAndriy Gapon return (SCM_CREDS); 47374f5d680SKonstantin Belousov } 47474f5d680SKonstantin Belousov return (-1); 47574f5d680SKonstantin Belousov } 47674f5d680SKonstantin Belousov 47774f5d680SKonstantin Belousov static int 47874f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type) 47974f5d680SKonstantin Belousov { 48074f5d680SKonstantin Belousov 48174f5d680SKonstantin Belousov switch (cmsg_type) { 48274f5d680SKonstantin Belousov case SCM_RIGHTS: 48374f5d680SKonstantin Belousov return (LINUX_SCM_RIGHTS); 484605da56bSAndriy Gapon case SCM_CREDS: 485605da56bSAndriy Gapon return (LINUX_SCM_CREDENTIALS); 486*bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 487*bbf392d5SDmitry Chagin return (LINUX_SCM_TIMESTAMP); 48874f5d680SKonstantin Belousov } 48974f5d680SKonstantin Belousov return (-1); 49074f5d680SKonstantin Belousov } 49174f5d680SKonstantin Belousov 49274f5d680SKonstantin Belousov static int 49374f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 49474f5d680SKonstantin Belousov { 49574f5d680SKonstantin Belousov if (lhdr->msg_controllen > INT_MAX) 49674f5d680SKonstantin Belousov return (ENOBUFS); 49774f5d680SKonstantin Belousov 49874f5d680SKonstantin Belousov bhdr->msg_name = PTRIN(lhdr->msg_name); 49974f5d680SKonstantin Belousov bhdr->msg_namelen = lhdr->msg_namelen; 50074f5d680SKonstantin Belousov bhdr->msg_iov = PTRIN(lhdr->msg_iov); 50174f5d680SKonstantin Belousov bhdr->msg_iovlen = lhdr->msg_iovlen; 50274f5d680SKonstantin Belousov bhdr->msg_control = PTRIN(lhdr->msg_control); 503605da56bSAndriy Gapon 504605da56bSAndriy Gapon /* 505605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 506605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 507605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 508605da56bSAndriy Gapon * 509605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 510605da56bSAndriy Gapon * control messages. 511605da56bSAndriy Gapon */ 512605da56bSAndriy Gapon 51374f5d680SKonstantin Belousov bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 51474f5d680SKonstantin Belousov return (0); 51574f5d680SKonstantin Belousov } 51674f5d680SKonstantin Belousov 51774f5d680SKonstantin Belousov static int 51874f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 51974f5d680SKonstantin Belousov { 52074f5d680SKonstantin Belousov lhdr->msg_name = PTROUT(bhdr->msg_name); 52174f5d680SKonstantin Belousov lhdr->msg_namelen = bhdr->msg_namelen; 52274f5d680SKonstantin Belousov lhdr->msg_iov = PTROUT(bhdr->msg_iov); 52374f5d680SKonstantin Belousov lhdr->msg_iovlen = bhdr->msg_iovlen; 52474f5d680SKonstantin Belousov lhdr->msg_control = PTROUT(bhdr->msg_control); 525605da56bSAndriy Gapon 526605da56bSAndriy Gapon /* 527605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages 528605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used 529605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system). 530605da56bSAndriy Gapon * 531605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the 532605da56bSAndriy Gapon * control messages. 533605da56bSAndriy Gapon */ 534605da56bSAndriy Gapon 53574f5d680SKonstantin Belousov /* msg_flags skipped */ 53674f5d680SKonstantin Belousov return (0); 53774f5d680SKonstantin Belousov } 53874f5d680SKonstantin Belousov 53974f5d680SKonstantin Belousov static int 5404cf10e29SDmitry Chagin linux_set_socket_flags(int lflags, int *flags) 54138a18e97SDmitry Chagin { 54238a18e97SDmitry Chagin 5434cf10e29SDmitry Chagin if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 5444cf10e29SDmitry Chagin return (EINVAL); 5454cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_NONBLOCK) 5464cf10e29SDmitry Chagin *flags |= SOCK_NONBLOCK; 5474cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_CLOEXEC) 5484cf10e29SDmitry Chagin *flags |= SOCK_CLOEXEC; 54938a18e97SDmitry Chagin return (0); 55038a18e97SDmitry Chagin } 55138a18e97SDmitry Chagin 55238a18e97SDmitry Chagin static int 55374f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 55474f5d680SKonstantin Belousov struct mbuf *control, enum uio_seg segflg) 55574f5d680SKonstantin Belousov { 5565a8a13e0SDavid Malone struct sockaddr *to; 5575a8a13e0SDavid Malone int error; 5585a8a13e0SDavid Malone 5595a8a13e0SDavid Malone if (mp->msg_name != NULL) { 5605a8a13e0SDavid Malone error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 5615a8a13e0SDavid Malone if (error) 5625a8a13e0SDavid Malone return (error); 5635a8a13e0SDavid Malone mp->msg_name = to; 5645a8a13e0SDavid Malone } else 5655a8a13e0SDavid Malone to = NULL; 5665a8a13e0SDavid Malone 567a6886ef1SMaxim Sobolev error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 568a6886ef1SMaxim Sobolev segflg); 5695a8a13e0SDavid Malone 5705a8a13e0SDavid Malone if (to) 5711ede983cSDag-Erling Smørgrav free(to, M_SONAME); 5725a8a13e0SDavid Malone return (error); 5735a8a13e0SDavid Malone } 5745a8a13e0SDavid Malone 5753f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */ 576f2477ae1SMike Smith static int 577e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s) 578f2477ae1SMike Smith { 579857ad5a3SDmitry Chagin int error, optval; 580857ad5a3SDmitry Chagin socklen_t size_val; 581f2477ae1SMike Smith 582e140eb43SDavid Malone size_val = sizeof(optval); 583e140eb43SDavid Malone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 584e140eb43SDavid Malone &optval, UIO_SYSSPACE, &size_val); 585e140eb43SDavid Malone if (error) 5863f3a4815SMarcel Moolenaar return (error); 5873f3a4815SMarcel Moolenaar 5883f3a4815SMarcel Moolenaar return (optval == 0); 589f2477ae1SMike Smith } 590f2477ae1SMike Smith 591f2477ae1SMike Smith /* 592f2477ae1SMike Smith * Updated sendto() when IP_HDRINCL is set: 593f2477ae1SMike Smith * tweak endian-dependent fields in the IP packet. 594f2477ae1SMike Smith */ 595f2477ae1SMike Smith static int 59638da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 597f2477ae1SMike Smith { 598f2477ae1SMike Smith /* 599f2477ae1SMike Smith * linux_ip_copysize defines how many bytes we should copy 600f2477ae1SMike Smith * from the beginning of the IP packet before we customize it for BSD. 601a6886ef1SMaxim Sobolev * It should include all the fields we modify (ip_len and ip_off). 602f2477ae1SMike Smith */ 603f2477ae1SMike Smith #define linux_ip_copysize 8 604f2477ae1SMike Smith 605f2477ae1SMike Smith struct ip *packet; 6065a8a13e0SDavid Malone struct msghdr msg; 607a6886ef1SMaxim Sobolev struct iovec aiov[1]; 608f2477ae1SMike Smith int error; 609f2477ae1SMike Smith 610aa675b57SDavid Schultz /* Check that the packet isn't too big or too small. */ 611aa675b57SDavid Schultz if (linux_args->len < linux_ip_copysize || 612aa675b57SDavid Schultz linux_args->len > IP_MAXPACKET) 6133f3a4815SMarcel Moolenaar return (EINVAL); 614f2477ae1SMike Smith 615e0d3ea8cSDmitry Chagin packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); 616f2477ae1SMike Smith 617a6886ef1SMaxim Sobolev /* Make kernel copy of the packet to be sent */ 6184af27623STim J. Robbins if ((error = copyin(PTRIN(linux_args->msg), packet, 619a6886ef1SMaxim Sobolev linux_args->len))) 620a6886ef1SMaxim Sobolev goto goout; 621f2477ae1SMike Smith 622f2477ae1SMike Smith /* Convert fields from Linux to BSD raw IP socket format */ 6235a8a13e0SDavid Malone packet->ip_len = linux_args->len; 624f2477ae1SMike Smith packet->ip_off = ntohs(packet->ip_off); 625f2477ae1SMike Smith 626f2477ae1SMike Smith /* Prepare the msghdr and iovec structures describing the new packet */ 6274af27623STim J. Robbins msg.msg_name = PTRIN(linux_args->to); 6285a8a13e0SDavid Malone msg.msg_namelen = linux_args->tolen; 6295a8a13e0SDavid Malone msg.msg_iov = aiov; 630a6886ef1SMaxim Sobolev msg.msg_iovlen = 1; 6315a8a13e0SDavid Malone msg.msg_control = NULL; 6325a8a13e0SDavid Malone msg.msg_flags = 0; 6335a8a13e0SDavid Malone aiov[0].iov_base = (char *)packet; 634a6886ef1SMaxim Sobolev aiov[0].iov_len = linux_args->len; 635a6886ef1SMaxim Sobolev error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 63674f5d680SKonstantin Belousov NULL, UIO_SYSSPACE); 637a6886ef1SMaxim Sobolev goout: 638e0d3ea8cSDmitry Chagin free(packet, M_LINUX); 6395a8a13e0SDavid Malone return (error); 640f2477ae1SMike Smith } 641f2477ae1SMike Smith 642a12b9b3dSDmitry Chagin int 643b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args) 644c21dee17SSøren Schmidt { 645ef04503dSPeter Wemm struct socket_args /* { 646c21dee17SSøren Schmidt int domain; 647c21dee17SSøren Schmidt int type; 648c21dee17SSøren Schmidt int protocol; 649ef04503dSPeter Wemm } */ bsd_args; 6504cf10e29SDmitry Chagin int retval_socket; 651c21dee17SSøren Schmidt 652745aaef5SKonstantin Belousov bsd_args.protocol = args->protocol; 6533933bde2SDmitry Chagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 654eeb63e51SDmitry Chagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 655eeb63e51SDmitry Chagin return (EINVAL); 6564cf10e29SDmitry Chagin retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 6574cf10e29SDmitry Chagin &bsd_args.type); 6584cf10e29SDmitry Chagin if (retval_socket != 0) 6594cf10e29SDmitry Chagin return (retval_socket); 660745aaef5SKonstantin Belousov bsd_args.domain = linux_to_bsd_domain(args->domain); 661c21dee17SSøren Schmidt if (bsd_args.domain == -1) 662d9b063ccSDmitry Chagin return (EAFNOSUPPORT); 663f2477ae1SMike Smith 6648451d0ddSKip Macy retval_socket = sys_socket(td, &bsd_args); 6656994ea54SDmitry Chagin if (retval_socket) 6666994ea54SDmitry Chagin return (retval_socket); 6676994ea54SDmitry Chagin 668f2477ae1SMike Smith if (bsd_args.type == SOCK_RAW 669f2477ae1SMike Smith && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 6706994ea54SDmitry Chagin && bsd_args.domain == PF_INET) { 671f2477ae1SMike Smith /* It's a raw IP socket: set the IP_HDRINCL option. */ 672e140eb43SDavid Malone int hdrincl; 673f2477ae1SMike Smith 674e140eb43SDavid Malone hdrincl = 1; 675e140eb43SDavid Malone /* We ignore any error returned by kern_setsockopt() */ 676e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 677e140eb43SDavid Malone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 678f2477ae1SMike Smith } 679ca26842eSHajimu UMEMOTO #ifdef INET6 680ca26842eSHajimu UMEMOTO /* 681d97bee3eSBjoern A. Zeeb * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default 682d97bee3eSBjoern A. Zeeb * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. 683d97bee3eSBjoern A. Zeeb * For simplicity we do this unconditionally of the net.inet6.ip6.v6only 684d97bee3eSBjoern A. Zeeb * sysctl value. 685ca26842eSHajimu UMEMOTO */ 686d97bee3eSBjoern A. Zeeb if (bsd_args.domain == PF_INET6) { 687e140eb43SDavid Malone int v6only; 688ca26842eSHajimu UMEMOTO 689e140eb43SDavid Malone v6only = 0; 690ca26842eSHajimu UMEMOTO /* We ignore any error returned by setsockopt() */ 691e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 692e140eb43SDavid Malone &v6only, UIO_SYSSPACE, sizeof(v6only)); 693ca26842eSHajimu UMEMOTO } 694ca26842eSHajimu UMEMOTO #endif 6953f3a4815SMarcel Moolenaar 6963f3a4815SMarcel Moolenaar return (retval_socket); 697c21dee17SSøren Schmidt } 698c21dee17SSøren Schmidt 699a12b9b3dSDmitry Chagin int 700b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args) 701c21dee17SSøren Schmidt { 702ca26842eSHajimu UMEMOTO struct sockaddr *sa; 703c21dee17SSøren Schmidt int error; 704c21dee17SSøren Schmidt 705745aaef5SKonstantin Belousov error = linux_getsockaddr(&sa, PTRIN(args->name), 706745aaef5SKonstantin Belousov args->namelen); 707ca26842eSHajimu UMEMOTO if (error) 708ca26842eSHajimu UMEMOTO return (error); 709ca26842eSHajimu UMEMOTO 7106e646651SKonstantin Belousov error = kern_bindat(td, AT_FDCWD, args->s, sa); 711b33887eaSJohn Baldwin free(sa, M_SONAME); 712745aaef5SKonstantin Belousov if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 713d4b7423fSAlexander Leidinger return (EINVAL); 714b33887eaSJohn Baldwin return (error); 715c21dee17SSøren Schmidt } 716c21dee17SSøren Schmidt 717930a65feSAndrew Gallatin int 718b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args) 719c21dee17SSøren Schmidt { 7207008be5bSPawel Jakub Dawidek cap_rights_t rights; 7210bf301c0SJonathan Lemon struct socket *so; 722ca26842eSHajimu UMEMOTO struct sockaddr *sa; 72339c95b83SMatthew Dillon u_int fflag; 724c21dee17SSøren Schmidt int error; 725c21dee17SSøren Schmidt 726745aaef5SKonstantin Belousov error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), 727745aaef5SKonstantin Belousov args->namelen); 728ca26842eSHajimu UMEMOTO if (error) 729ca26842eSHajimu UMEMOTO return (error); 730ca26842eSHajimu UMEMOTO 7316e646651SKonstantin Belousov error = kern_connectat(td, AT_FDCWD, args->s, sa); 732b33887eaSJohn Baldwin free(sa, M_SONAME); 7330bf301c0SJonathan Lemon if (error != EISCONN) 7340bf301c0SJonathan Lemon return (error); 7350bf301c0SJonathan Lemon 736dad3b88aSMike Smith /* 737dad3b88aSMike Smith * Linux doesn't return EISCONN the first time it occurs, 738dad3b88aSMike Smith * when on a non-blocking socket. Instead it returns the 739dad3b88aSMike Smith * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 740f7f45ac8SRobert Watson * 741f7f45ac8SRobert Watson * XXXRW: Instead of using fgetsock(), check that it is a 742f7f45ac8SRobert Watson * socket and use the file descriptor reference instead of 743f7f45ac8SRobert Watson * creating a new one. 744dad3b88aSMike Smith */ 7457008be5bSPawel Jakub Dawidek error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT), 7467008be5bSPawel Jakub Dawidek &so, &fflag); 7474641373fSJohn Baldwin if (error == 0) { 7480bf301c0SJonathan Lemon error = EISCONN; 74939c95b83SMatthew Dillon if (fflag & FNONBLOCK) { 7504641373fSJohn Baldwin SOCK_LOCK(so); 7515002a60fSMarcel Moolenaar if (so->so_emuldata == 0) 7520bf301c0SJonathan Lemon error = so->so_error; 7530bf301c0SJonathan Lemon so->so_emuldata = (void *)1; 7544641373fSJohn Baldwin SOCK_UNLOCK(so); 755dad3b88aSMike Smith } 75639c95b83SMatthew Dillon fputsock(so); 7574641373fSJohn Baldwin } 7583f3a4815SMarcel Moolenaar return (error); 759c21dee17SSøren Schmidt } 760c21dee17SSøren Schmidt 761a12b9b3dSDmitry Chagin int 762b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args) 763c21dee17SSøren Schmidt { 764ef04503dSPeter Wemm struct listen_args /* { 765c21dee17SSøren Schmidt int s; 766c21dee17SSøren Schmidt int backlog; 767ef04503dSPeter Wemm } */ bsd_args; 768c21dee17SSøren Schmidt 769745aaef5SKonstantin Belousov bsd_args.s = args->s; 770745aaef5SKonstantin Belousov bsd_args.backlog = args->backlog; 7718451d0ddSKip Macy return (sys_listen(td, &bsd_args)); 772c21dee17SSøren Schmidt } 773c21dee17SSøren Schmidt 77401e0ffbaSAlexander Leidinger static int 775c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr, 776f83427b8SDmitry Chagin l_uintptr_t namelen, int flags) 777c21dee17SSøren Schmidt { 7784cf10e29SDmitry Chagin struct accept4_args /* { 779c21dee17SSøren Schmidt int s; 7803db2a843SBruce Evans struct sockaddr * __restrict name; 7813db2a843SBruce Evans socklen_t * __restrict anamelen; 7824cf10e29SDmitry Chagin int flags; 783ef04503dSPeter Wemm } */ bsd_args; 78493e694c9SDmitry Chagin int error; 78593e694c9SDmitry Chagin 786c8f37d61SDmitry Chagin bsd_args.s = s; 7873db2a843SBruce Evans /* XXX: */ 788c8f37d61SDmitry Chagin bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr); 789c8f37d61SDmitry Chagin bsd_args.anamelen = PTRIN(namelen);/* XXX */ 7904cf10e29SDmitry Chagin error = linux_set_socket_flags(flags, &bsd_args.flags); 7914cf10e29SDmitry Chagin if (error != 0) 7924cf10e29SDmitry Chagin return (error); 7934cf10e29SDmitry Chagin error = sys_accept4(td, &bsd_args); 7945c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); 795d4b7423fSAlexander Leidinger if (error) { 796c8f37d61SDmitry Chagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 797d4b7423fSAlexander Leidinger return (EINVAL); 798dba5ab66SMarcel Moolenaar return (error); 799d4b7423fSAlexander Leidinger } 80093e694c9SDmitry Chagin if (addr) 80193e694c9SDmitry Chagin error = linux_sa_put(PTRIN(addr)); 80293e694c9SDmitry Chagin if (error) { 80393e694c9SDmitry Chagin (void)kern_close(td, td->td_retval[0]); 80493e694c9SDmitry Chagin td->td_retval[0] = 0; 80593e694c9SDmitry Chagin } 80693e694c9SDmitry Chagin return (error); 807c21dee17SSøren Schmidt } 808c21dee17SSøren Schmidt 809a12b9b3dSDmitry Chagin int 810c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args) 811c8f37d61SDmitry Chagin { 812c8f37d61SDmitry Chagin 813c8f37d61SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 814f83427b8SDmitry Chagin args->namelen, 0)); 815c8f37d61SDmitry Chagin } 816c8f37d61SDmitry Chagin 817a12b9b3dSDmitry Chagin int 818f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args) 819f8cd0af2SDmitry Chagin { 820f8cd0af2SDmitry Chagin 821f8cd0af2SDmitry Chagin return (linux_accept_common(td, args->s, args->addr, 822f8cd0af2SDmitry Chagin args->namelen, args->flags)); 823f8cd0af2SDmitry Chagin } 824f8cd0af2SDmitry Chagin 825a12b9b3dSDmitry Chagin int 826b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args) 827c21dee17SSøren Schmidt { 828ef04503dSPeter Wemm struct getsockname_args /* { 829c21dee17SSøren Schmidt int fdes; 8303db2a843SBruce Evans struct sockaddr * __restrict asa; 8313db2a843SBruce Evans socklen_t * __restrict alen; 832ef04503dSPeter Wemm } */ bsd_args; 833c21dee17SSøren Schmidt int error; 834c21dee17SSøren Schmidt 835745aaef5SKonstantin Belousov bsd_args.fdes = args->s; 8363db2a843SBruce Evans /* XXX: */ 837745aaef5SKonstantin Belousov bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); 838745aaef5SKonstantin Belousov bsd_args.alen = PTRIN(args->namelen); /* XXX */ 8398451d0ddSKip Macy error = sys_getsockname(td, &bsd_args); 8405c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 841ca26842eSHajimu UMEMOTO if (error) 842ca26842eSHajimu UMEMOTO return (error); 843745aaef5SKonstantin Belousov error = linux_sa_put(PTRIN(args->addr)); 844ca26842eSHajimu UMEMOTO if (error) 845ca26842eSHajimu UMEMOTO return (error); 846ca26842eSHajimu UMEMOTO return (0); 847c21dee17SSøren Schmidt } 848c21dee17SSøren Schmidt 849a12b9b3dSDmitry Chagin int 850b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args) 851c21dee17SSøren Schmidt { 8525c8919adSAlexander Leidinger struct getpeername_args /* { 853c21dee17SSøren Schmidt int fdes; 854c21dee17SSøren Schmidt caddr_t asa; 855c21dee17SSøren Schmidt int *alen; 856ef04503dSPeter Wemm } */ bsd_args; 857c21dee17SSøren Schmidt int error; 858c21dee17SSøren Schmidt 859745aaef5SKonstantin Belousov bsd_args.fdes = args->s; 860745aaef5SKonstantin Belousov bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); 861857ad5a3SDmitry Chagin bsd_args.alen = (socklen_t *)PTRIN(args->namelen); 8628451d0ddSKip Macy error = sys_getpeername(td, &bsd_args); 8635c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 864ca26842eSHajimu UMEMOTO if (error) 865ca26842eSHajimu UMEMOTO return (error); 866745aaef5SKonstantin Belousov error = linux_sa_put(PTRIN(args->addr)); 867ca26842eSHajimu UMEMOTO if (error) 868ca26842eSHajimu UMEMOTO return (error); 869ca26842eSHajimu UMEMOTO return (0); 870c21dee17SSøren Schmidt } 871c21dee17SSøren Schmidt 872a12b9b3dSDmitry Chagin int 873b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args) 874c21dee17SSøren Schmidt { 875ef04503dSPeter Wemm struct socketpair_args /* { 876c21dee17SSøren Schmidt int domain; 877c21dee17SSøren Schmidt int type; 878c21dee17SSøren Schmidt int protocol; 879c21dee17SSøren Schmidt int *rsv; 880ef04503dSPeter Wemm } */ bsd_args; 8814cf10e29SDmitry Chagin int error; 882c21dee17SSøren Schmidt 883745aaef5SKonstantin Belousov bsd_args.domain = linux_to_bsd_domain(args->domain); 8841a52a4abSDmitry Chagin if (bsd_args.domain != PF_LOCAL) 8851a52a4abSDmitry Chagin return (EAFNOSUPPORT); 88639253cf9SDmitry Chagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 88739253cf9SDmitry Chagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 88839253cf9SDmitry Chagin return (EINVAL); 8894cf10e29SDmitry Chagin error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 8904cf10e29SDmitry Chagin &bsd_args.type); 8914cf10e29SDmitry Chagin if (error != 0) 8924cf10e29SDmitry Chagin return (error); 8931a52a4abSDmitry Chagin if (args->protocol != 0 && args->protocol != PF_UNIX) 8941a52a4abSDmitry Chagin 8951a52a4abSDmitry Chagin /* 8961a52a4abSDmitry Chagin * Use of PF_UNIX as protocol argument is not right, 8971a52a4abSDmitry Chagin * but Linux does it. 8981a52a4abSDmitry Chagin * Do not map PF_UNIX as its Linux value is identical 8991a52a4abSDmitry Chagin * to FreeBSD one. 9001a52a4abSDmitry Chagin */ 9011a52a4abSDmitry Chagin return (EPROTONOSUPPORT); 90240092d93SDmitry Chagin else 9031a52a4abSDmitry Chagin bsd_args.protocol = 0; 904745aaef5SKonstantin Belousov bsd_args.rsv = (int *)PTRIN(args->rsv); 9054cf10e29SDmitry Chagin return (sys_socketpair(td, &bsd_args)); 906c21dee17SSøren Schmidt } 907c21dee17SSøren Schmidt 908a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 90901e0ffbaSAlexander Leidinger struct linux_send_args { 910c21dee17SSøren Schmidt int s; 9114af27623STim J. Robbins l_uintptr_t msg; 912c21dee17SSøren Schmidt int len; 913c21dee17SSøren Schmidt int flags; 914c21dee17SSøren Schmidt }; 915c21dee17SSøren Schmidt 91601e0ffbaSAlexander Leidinger static int 917b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args) 918c21dee17SSøren Schmidt { 91987d72a8fSPoul-Henning Kamp struct sendto_args /* { 920c21dee17SSøren Schmidt int s; 921c21dee17SSøren Schmidt caddr_t buf; 922044af7c3SJonathan Mini int len; 923c21dee17SSøren Schmidt int flags; 92487d72a8fSPoul-Henning Kamp caddr_t to; 92587d72a8fSPoul-Henning Kamp int tolen; 926ef04503dSPeter Wemm } */ bsd_args; 927c21dee17SSøren Schmidt 928745aaef5SKonstantin Belousov bsd_args.s = args->s; 929745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 930745aaef5SKonstantin Belousov bsd_args.len = args->len; 931745aaef5SKonstantin Belousov bsd_args.flags = args->flags; 93287d72a8fSPoul-Henning Kamp bsd_args.to = NULL; 93387d72a8fSPoul-Henning Kamp bsd_args.tolen = 0; 9348451d0ddSKip Macy return sys_sendto(td, &bsd_args); 935c21dee17SSøren Schmidt } 936c21dee17SSøren Schmidt 93701e0ffbaSAlexander Leidinger struct linux_recv_args { 938c21dee17SSøren Schmidt int s; 9394af27623STim J. Robbins l_uintptr_t msg; 940c21dee17SSøren Schmidt int len; 941c21dee17SSøren Schmidt int flags; 942c21dee17SSøren Schmidt }; 943c21dee17SSøren Schmidt 94401e0ffbaSAlexander Leidinger static int 945b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args) 946c21dee17SSøren Schmidt { 94787d72a8fSPoul-Henning Kamp struct recvfrom_args /* { 948c21dee17SSøren Schmidt int s; 949c21dee17SSøren Schmidt caddr_t buf; 950c21dee17SSøren Schmidt int len; 951c21dee17SSøren Schmidt int flags; 95287d72a8fSPoul-Henning Kamp struct sockaddr *from; 95387d72a8fSPoul-Henning Kamp socklen_t fromlenaddr; 954ef04503dSPeter Wemm } */ bsd_args; 955c21dee17SSøren Schmidt 956745aaef5SKonstantin Belousov bsd_args.s = args->s; 957745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg); 958745aaef5SKonstantin Belousov bsd_args.len = args->len; 9593980a435SDmitry Chagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 96087d72a8fSPoul-Henning Kamp bsd_args.from = NULL; 96187d72a8fSPoul-Henning Kamp bsd_args.fromlenaddr = 0; 9628451d0ddSKip Macy return (sys_recvfrom(td, &bsd_args)); 963c21dee17SSøren Schmidt } 964a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 965c21dee17SSøren Schmidt 966a12b9b3dSDmitry Chagin int 967b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args) 968c21dee17SSøren Schmidt { 9695a8a13e0SDavid Malone struct msghdr msg; 9705a8a13e0SDavid Malone struct iovec aiov; 9715a8a13e0SDavid Malone int error; 972c21dee17SSøren Schmidt 973745aaef5SKonstantin Belousov if (linux_check_hdrincl(td, args->s) == 0) 974f2477ae1SMike Smith /* IP_HDRINCL set, tweak the packet before sending */ 975745aaef5SKonstantin Belousov return (linux_sendto_hdrincl(td, args)); 976f2477ae1SMike Smith 977745aaef5SKonstantin Belousov msg.msg_name = PTRIN(args->to); 978745aaef5SKonstantin Belousov msg.msg_namelen = args->tolen; 9795a8a13e0SDavid Malone msg.msg_iov = &aiov; 9805a8a13e0SDavid Malone msg.msg_iovlen = 1; 9815a8a13e0SDavid Malone msg.msg_control = NULL; 9825a8a13e0SDavid Malone msg.msg_flags = 0; 983745aaef5SKonstantin Belousov aiov.iov_base = PTRIN(args->msg); 984745aaef5SKonstantin Belousov aiov.iov_len = args->len; 98574f5d680SKonstantin Belousov error = linux_sendit(td, args->s, &msg, args->flags, NULL, 98674f5d680SKonstantin Belousov UIO_USERSPACE); 9875a8a13e0SDavid Malone return (error); 988c21dee17SSøren Schmidt } 989c21dee17SSøren Schmidt 990a12b9b3dSDmitry Chagin int 991b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 992c21dee17SSøren Schmidt { 9939599b0ecSDmitry Chagin struct msghdr msg; 9949599b0ecSDmitry Chagin struct iovec aiov; 995c21dee17SSøren Schmidt int error; 996c21dee17SSøren Schmidt 9979599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL) { 9989599b0ecSDmitry Chagin error = copyin(PTRIN(args->fromlen), &msg.msg_namelen, 9999599b0ecSDmitry Chagin sizeof(msg.msg_namelen)); 10009599b0ecSDmitry Chagin if (error != 0) 10013f3a4815SMarcel Moolenaar return (error); 10023f3a4815SMarcel Moolenaar 10039599b0ecSDmitry Chagin error = linux_to_bsd_sockaddr((struct sockaddr *)PTRIN(args->from), 10049599b0ecSDmitry Chagin msg.msg_namelen); 10059599b0ecSDmitry Chagin if (error != 0) 1006ca26842eSHajimu UMEMOTO return (error); 10079599b0ecSDmitry Chagin } else 10089599b0ecSDmitry Chagin msg.msg_namelen = 0; 10099599b0ecSDmitry Chagin 10109599b0ecSDmitry Chagin msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from); 10119599b0ecSDmitry Chagin msg.msg_iov = &aiov; 10129599b0ecSDmitry Chagin msg.msg_iovlen = 1; 10139599b0ecSDmitry Chagin aiov.iov_base = PTRIN(args->buf); 10149599b0ecSDmitry Chagin aiov.iov_len = args->len; 10159599b0ecSDmitry Chagin msg.msg_control = 0; 10169599b0ecSDmitry Chagin msg.msg_flags = linux_to_bsd_msg_flags(args->flags); 10179599b0ecSDmitry Chagin 10189599b0ecSDmitry Chagin error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL); 10199599b0ecSDmitry Chagin if (error != 0) 10209599b0ecSDmitry Chagin return (error); 10219599b0ecSDmitry Chagin 10229599b0ecSDmitry Chagin if (PTRIN(args->from) != NULL) { 10239599b0ecSDmitry Chagin error = bsd_to_linux_sockaddr((struct sockaddr *) 10249599b0ecSDmitry Chagin PTRIN(args->from)); 10259599b0ecSDmitry Chagin if (error != 0) 10269599b0ecSDmitry Chagin return (error); 10279599b0ecSDmitry Chagin 10284af27623STim J. Robbins error = linux_sa_put((struct osockaddr *) 1029745aaef5SKonstantin Belousov PTRIN(args->from)); 1030ca26842eSHajimu UMEMOTO } 10319599b0ecSDmitry Chagin 10329599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL) 10339599b0ecSDmitry Chagin error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), 10349599b0ecSDmitry Chagin sizeof(msg.msg_namelen)); 10359599b0ecSDmitry Chagin 10369599b0ecSDmitry Chagin return (error); 1037ca26842eSHajimu UMEMOTO } 1038ca26842eSHajimu UMEMOTO 1039e1ff74c0SDmitry Chagin static int 1040e1ff74c0SDmitry Chagin linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1041e1ff74c0SDmitry Chagin l_uint flags) 1042ca26842eSHajimu UMEMOTO { 104374f5d680SKonstantin Belousov struct cmsghdr *cmsg; 1044605da56bSAndriy Gapon struct cmsgcred cmcred; 104574f5d680SKonstantin Belousov struct mbuf *control; 1046ca26842eSHajimu UMEMOTO struct msghdr msg; 104774f5d680SKonstantin Belousov struct l_cmsghdr linux_cmsg; 104874f5d680SKonstantin Belousov struct l_cmsghdr *ptr_cmsg; 104974f5d680SKonstantin Belousov struct l_msghdr linux_msg; 1050552afd9cSPoul-Henning Kamp struct iovec *iov; 105174f5d680SKonstantin Belousov socklen_t datalen; 1052605da56bSAndriy Gapon struct sockaddr *sa; 1053605da56bSAndriy Gapon sa_family_t sa_family; 105474f5d680SKonstantin Belousov void *data; 1055ca26842eSHajimu UMEMOTO int error; 1056ca26842eSHajimu UMEMOTO 1057e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1058e1ff74c0SDmitry Chagin if (error != 0) 105974f5d680SKonstantin Belousov return (error); 1060d72a6158SRobert Watson 1061d72a6158SRobert Watson /* 1062d72a6158SRobert Watson * Some Linux applications (ping) define a non-NULL control data 1063d72a6158SRobert Watson * pointer, but a msg_controllen of 0, which is not allowed in the 1064d72a6158SRobert Watson * FreeBSD system call interface. NULL the msg_control pointer in 1065d72a6158SRobert Watson * order to handle this case. This should be checked, but allows the 1066d72a6158SRobert Watson * Linux ping to work. 1067d72a6158SRobert Watson */ 1068605da56bSAndriy Gapon if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) 1069605da56bSAndriy Gapon linux_msg.msg_control = PTROUT(NULL); 1070605da56bSAndriy Gapon 1071605da56bSAndriy Gapon error = linux_to_bsd_msghdr(&msg, &linux_msg); 1072e1ff74c0SDmitry Chagin if (error != 0) 1073605da56bSAndriy Gapon return (error); 107474f5d680SKonstantin Belousov 107574f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 107674f5d680SKonstantin Belousov error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 107774f5d680SKonstantin Belousov &iov, EMSGSIZE); 107874f5d680SKonstantin Belousov #else 1079552afd9cSPoul-Henning Kamp error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 108074f5d680SKonstantin Belousov #endif 1081e1ff74c0SDmitry Chagin if (error != 0) 1082552afd9cSPoul-Henning Kamp return (error); 108374f5d680SKonstantin Belousov 1084605da56bSAndriy Gapon control = NULL; 1085605da56bSAndriy Gapon cmsg = NULL; 1086605da56bSAndriy Gapon 1087605da56bSAndriy Gapon if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { 1088e1ff74c0SDmitry Chagin error = kern_getsockname(td, s, &sa, &datalen); 1089e1ff74c0SDmitry Chagin if (error != 0) 1090605da56bSAndriy Gapon goto bad; 1091605da56bSAndriy Gapon sa_family = sa->sa_family; 1092605da56bSAndriy Gapon free(sa, M_SONAME); 1093605da56bSAndriy Gapon 109474f5d680SKonstantin Belousov error = ENOBUFS; 1095e0d3ea8cSDmitry Chagin cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO); 1096eb1b1807SGleb Smirnoff control = m_get(M_WAITOK, MT_CONTROL); 109774f5d680SKonstantin Belousov 109874f5d680SKonstantin Belousov do { 109974f5d680SKonstantin Belousov error = copyin(ptr_cmsg, &linux_cmsg, 110074f5d680SKonstantin Belousov sizeof(struct l_cmsghdr)); 1101e1ff74c0SDmitry Chagin if (error != 0) 110274f5d680SKonstantin Belousov goto bad; 110374f5d680SKonstantin Belousov 110474f5d680SKonstantin Belousov error = EINVAL; 110574f5d680SKonstantin Belousov if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) 110674f5d680SKonstantin Belousov goto bad; 110774f5d680SKonstantin Belousov 110874f5d680SKonstantin Belousov /* 1109605da56bSAndriy Gapon * Now we support only SCM_RIGHTS and SCM_CRED, 1110605da56bSAndriy Gapon * so return EINVAL in any other cmsg_type 111174f5d680SKonstantin Belousov */ 1112605da56bSAndriy Gapon cmsg->cmsg_type = 1113605da56bSAndriy Gapon linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); 111474f5d680SKonstantin Belousov cmsg->cmsg_level = 111574f5d680SKonstantin Belousov linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1116605da56bSAndriy Gapon if (cmsg->cmsg_type == -1 1117605da56bSAndriy Gapon || cmsg->cmsg_level != SOL_SOCKET) 1118605da56bSAndriy Gapon goto bad; 111974f5d680SKonstantin Belousov 1120605da56bSAndriy Gapon /* 1121605da56bSAndriy Gapon * Some applications (e.g. pulseaudio) attempt to 1122605da56bSAndriy Gapon * send ancillary data even if the underlying protocol 1123605da56bSAndriy Gapon * doesn't support it which is not allowed in the 1124605da56bSAndriy Gapon * FreeBSD system call interface. 1125605da56bSAndriy Gapon */ 1126605da56bSAndriy Gapon if (sa_family != AF_UNIX) 1127605da56bSAndriy Gapon continue; 1128605da56bSAndriy Gapon 112974f5d680SKonstantin Belousov data = LINUX_CMSG_DATA(ptr_cmsg); 1130605da56bSAndriy Gapon datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1131605da56bSAndriy Gapon 1132605da56bSAndriy Gapon switch (cmsg->cmsg_type) 1133605da56bSAndriy Gapon { 1134605da56bSAndriy Gapon case SCM_RIGHTS: 1135605da56bSAndriy Gapon break; 1136605da56bSAndriy Gapon 1137605da56bSAndriy Gapon case SCM_CREDS: 1138605da56bSAndriy Gapon data = &cmcred; 1139605da56bSAndriy Gapon datalen = sizeof(cmcred); 1140605da56bSAndriy Gapon 1141605da56bSAndriy Gapon /* 1142605da56bSAndriy Gapon * The lower levels will fill in the structure 1143605da56bSAndriy Gapon */ 1144605da56bSAndriy Gapon bzero(data, datalen); 1145605da56bSAndriy Gapon break; 1146605da56bSAndriy Gapon } 1147605da56bSAndriy Gapon 1148605da56bSAndriy Gapon cmsg->cmsg_len = CMSG_LEN(datalen); 114974f5d680SKonstantin Belousov 115074f5d680SKonstantin Belousov error = ENOBUFS; 115174f5d680SKonstantin Belousov if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg)) 115274f5d680SKonstantin Belousov goto bad; 115374f5d680SKonstantin Belousov if (!m_append(control, datalen, (c_caddr_t)data)) 115474f5d680SKonstantin Belousov goto bad; 1155605da56bSAndriy Gapon } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); 1156605da56bSAndriy Gapon 1157605da56bSAndriy Gapon if (m_length(control, NULL) == 0) { 1158605da56bSAndriy Gapon m_freem(control); 115974f5d680SKonstantin Belousov control = NULL; 1160605da56bSAndriy Gapon } 116174f5d680SKonstantin Belousov } 116274f5d680SKonstantin Belousov 11635a8a13e0SDavid Malone msg.msg_iov = iov; 11645a8a13e0SDavid Malone msg.msg_flags = 0; 1165e1ff74c0SDmitry Chagin error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); 116674f5d680SKonstantin Belousov 116774f5d680SKonstantin Belousov bad: 11684f65e9cfSDmitry Chagin m_freem(control); 1169552afd9cSPoul-Henning Kamp free(iov, M_IOV); 117074f5d680SKonstantin Belousov if (cmsg) 1171e0d3ea8cSDmitry Chagin free(cmsg, M_LINUX); 1172ca26842eSHajimu UMEMOTO return (error); 1173c21dee17SSøren Schmidt } 1174c21dee17SSøren Schmidt 1175a12b9b3dSDmitry Chagin int 1176e1ff74c0SDmitry Chagin linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1177e1ff74c0SDmitry Chagin { 1178e1ff74c0SDmitry Chagin 1179e1ff74c0SDmitry Chagin return (linux_sendmsg_common(td, args->s, PTRIN(args->msg), 1180e1ff74c0SDmitry Chagin args->flags)); 1181e1ff74c0SDmitry Chagin } 1182e1ff74c0SDmitry Chagin 1183e1ff74c0SDmitry Chagin int 1184e1ff74c0SDmitry Chagin linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) 1185e1ff74c0SDmitry Chagin { 1186e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1187e1ff74c0SDmitry Chagin l_uint retval; 1188e1ff74c0SDmitry Chagin int error, datagrams; 1189e1ff74c0SDmitry Chagin 1190e1ff74c0SDmitry Chagin if (args->vlen > UIO_MAXIOV) 1191e1ff74c0SDmitry Chagin args->vlen = UIO_MAXIOV; 1192e1ff74c0SDmitry Chagin 1193e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1194e1ff74c0SDmitry Chagin datagrams = 0; 1195e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1196e1ff74c0SDmitry Chagin error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, 1197e1ff74c0SDmitry Chagin args->flags); 1198e1ff74c0SDmitry Chagin if (error != 0) 1199e1ff74c0SDmitry Chagin break; 1200e1ff74c0SDmitry Chagin 1201e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1202e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1203e1ff74c0SDmitry Chagin if (error != 0) 1204e1ff74c0SDmitry Chagin break; 1205e1ff74c0SDmitry Chagin ++msg; 1206e1ff74c0SDmitry Chagin ++datagrams; 1207e1ff74c0SDmitry Chagin } 1208e1ff74c0SDmitry Chagin if (error == 0) 1209e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1210e1ff74c0SDmitry Chagin return (error); 1211e1ff74c0SDmitry Chagin } 1212e1ff74c0SDmitry Chagin 1213e1ff74c0SDmitry Chagin static int 1214e1ff74c0SDmitry Chagin linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1215e1ff74c0SDmitry Chagin l_uint flags, struct msghdr *msg) 121640dbba57SAssar Westerlund { 121774f5d680SKonstantin Belousov struct cmsghdr *cm; 1218605da56bSAndriy Gapon struct cmsgcred *cmcred; 121974f5d680SKonstantin Belousov struct l_cmsghdr *linux_cmsg = NULL; 1220605da56bSAndriy Gapon struct l_ucred linux_ucred; 1221605da56bSAndriy Gapon socklen_t datalen, outlen; 122274f5d680SKonstantin Belousov struct l_msghdr linux_msg; 122374f5d680SKonstantin Belousov struct iovec *iov, *uiov; 122474f5d680SKonstantin Belousov struct mbuf *control = NULL; 122574f5d680SKonstantin Belousov struct mbuf **controlp; 1226*bbf392d5SDmitry Chagin struct timeval *ftmvl; 1227*bbf392d5SDmitry Chagin l_timeval ltmvl; 122874f5d680SKonstantin Belousov caddr_t outbuf; 122974f5d680SKonstantin Belousov void *data; 12303a72bf04SDmitry Chagin int error, i, fd, fds, *fdp; 123140dbba57SAssar Westerlund 1232e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1233e1ff74c0SDmitry Chagin if (error != 0) 1234ca26842eSHajimu UMEMOTO return (error); 1235ca26842eSHajimu UMEMOTO 1236e1ff74c0SDmitry Chagin error = linux_to_bsd_msghdr(msg, &linux_msg); 1237e1ff74c0SDmitry Chagin if (error != 0) 123874f5d680SKonstantin Belousov return (error); 123974f5d680SKonstantin Belousov 124074f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32 1241e1ff74c0SDmitry Chagin error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, 124274f5d680SKonstantin Belousov &iov, EMSGSIZE); 124374f5d680SKonstantin Belousov #else 1244e1ff74c0SDmitry Chagin error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); 124574f5d680SKonstantin Belousov #endif 1246e1ff74c0SDmitry Chagin if (error != 0) 124774f5d680SKonstantin Belousov return (error); 124874f5d680SKonstantin Belousov 1249e1ff74c0SDmitry Chagin if (msg->msg_name) { 1250e1ff74c0SDmitry Chagin error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name, 1251e1ff74c0SDmitry Chagin msg->msg_namelen); 1252e1ff74c0SDmitry Chagin if (error != 0) 125374f5d680SKonstantin Belousov goto bad; 125484b11cd8SMitsuru IWASAKI } 125584b11cd8SMitsuru IWASAKI 1256e1ff74c0SDmitry Chagin uiov = msg->msg_iov; 1257e1ff74c0SDmitry Chagin msg->msg_iov = iov; 1258e1ff74c0SDmitry Chagin controlp = (msg->msg_control != NULL) ? &control : NULL; 1259e1ff74c0SDmitry Chagin error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp); 1260e1ff74c0SDmitry Chagin msg->msg_iov = uiov; 1261e1ff74c0SDmitry Chagin if (error != 0) 126274f5d680SKonstantin Belousov goto bad; 126374f5d680SKonstantin Belousov 1264e1ff74c0SDmitry Chagin error = bsd_to_linux_msghdr(msg, &linux_msg); 1265e1ff74c0SDmitry Chagin if (error != 0) 126674f5d680SKonstantin Belousov goto bad; 126774f5d680SKonstantin Belousov 126874f5d680SKonstantin Belousov if (linux_msg.msg_name) { 126974f5d680SKonstantin Belousov error = bsd_to_linux_sockaddr((struct sockaddr *) 127074f5d680SKonstantin Belousov PTRIN(linux_msg.msg_name)); 1271e1ff74c0SDmitry Chagin if (error != 0) 127274f5d680SKonstantin Belousov goto bad; 127374f5d680SKonstantin Belousov } 127474f5d680SKonstantin Belousov if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { 127574f5d680SKonstantin Belousov error = linux_sa_put(PTRIN(linux_msg.msg_name)); 1276e1ff74c0SDmitry Chagin if (error != 0) 127774f5d680SKonstantin Belousov goto bad; 127874f5d680SKonstantin Belousov } 127974f5d680SKonstantin Belousov 128074f5d680SKonstantin Belousov outbuf = PTRIN(linux_msg.msg_control); 128174f5d680SKonstantin Belousov outlen = 0; 1282605da56bSAndriy Gapon 1283605da56bSAndriy Gapon if (control) { 1284e0d3ea8cSDmitry Chagin linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); 1285605da56bSAndriy Gapon 1286e1ff74c0SDmitry Chagin msg->msg_control = mtod(control, struct cmsghdr *); 1287e1ff74c0SDmitry Chagin msg->msg_controllen = control->m_len; 1288605da56bSAndriy Gapon 1289e1ff74c0SDmitry Chagin cm = CMSG_FIRSTHDR(msg); 129074f5d680SKonstantin Belousov 129174f5d680SKonstantin Belousov while (cm != NULL) { 1292605da56bSAndriy Gapon linux_cmsg->cmsg_type = 1293605da56bSAndriy Gapon bsd_to_linux_cmsg_type(cm->cmsg_type); 1294605da56bSAndriy Gapon linux_cmsg->cmsg_level = 1295605da56bSAndriy Gapon bsd_to_linux_sockopt_level(cm->cmsg_level); 1296605da56bSAndriy Gapon if (linux_cmsg->cmsg_type == -1 1297605da56bSAndriy Gapon || cm->cmsg_level != SOL_SOCKET) 129874f5d680SKonstantin Belousov { 129974f5d680SKonstantin Belousov error = EINVAL; 130074f5d680SKonstantin Belousov goto bad; 130174f5d680SKonstantin Belousov } 1302605da56bSAndriy Gapon 130374f5d680SKonstantin Belousov data = CMSG_DATA(cm); 130474f5d680SKonstantin Belousov datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 130574f5d680SKonstantin Belousov 1306605da56bSAndriy Gapon switch (cm->cmsg_type) 13073a72bf04SDmitry Chagin { 1308605da56bSAndriy Gapon case SCM_RIGHTS: 1309e1ff74c0SDmitry Chagin if (flags & LINUX_MSG_CMSG_CLOEXEC) { 1310605da56bSAndriy Gapon fds = datalen / sizeof(int); 1311605da56bSAndriy Gapon fdp = data; 1312605da56bSAndriy Gapon for (i = 0; i < fds; i++) { 1313605da56bSAndriy Gapon fd = *fdp++; 1314605da56bSAndriy Gapon (void)kern_fcntl(td, fd, 1315605da56bSAndriy Gapon F_SETFD, FD_CLOEXEC); 1316605da56bSAndriy Gapon } 1317605da56bSAndriy Gapon } 1318605da56bSAndriy Gapon break; 1319605da56bSAndriy Gapon 1320605da56bSAndriy Gapon case SCM_CREDS: 1321605da56bSAndriy Gapon /* 1322605da56bSAndriy Gapon * Currently LOCAL_CREDS is never in 1323605da56bSAndriy Gapon * effect for Linux so no need to worry 1324605da56bSAndriy Gapon * about sockcred 1325605da56bSAndriy Gapon */ 1326605da56bSAndriy Gapon if (datalen != sizeof(*cmcred)) { 1327605da56bSAndriy Gapon error = EMSGSIZE; 1328605da56bSAndriy Gapon goto bad; 1329605da56bSAndriy Gapon } 1330605da56bSAndriy Gapon cmcred = (struct cmsgcred *)data; 1331605da56bSAndriy Gapon bzero(&linux_ucred, sizeof(linux_ucred)); 1332605da56bSAndriy Gapon linux_ucred.pid = cmcred->cmcred_pid; 1333605da56bSAndriy Gapon linux_ucred.uid = cmcred->cmcred_uid; 1334605da56bSAndriy Gapon linux_ucred.gid = cmcred->cmcred_gid; 1335605da56bSAndriy Gapon data = &linux_ucred; 1336605da56bSAndriy Gapon datalen = sizeof(linux_ucred); 1337605da56bSAndriy Gapon break; 1338*bbf392d5SDmitry Chagin 1339*bbf392d5SDmitry Chagin case SCM_TIMESTAMP: 1340*bbf392d5SDmitry Chagin if (datalen != sizeof(struct timeval)) { 1341*bbf392d5SDmitry Chagin error = EMSGSIZE; 1342*bbf392d5SDmitry Chagin goto bad; 1343*bbf392d5SDmitry Chagin } 1344*bbf392d5SDmitry Chagin ftmvl = (struct timeval *)data; 1345*bbf392d5SDmitry Chagin ltmvl.tv_sec = ftmvl->tv_sec; 1346*bbf392d5SDmitry Chagin ltmvl.tv_usec = ftmvl->tv_usec; 1347*bbf392d5SDmitry Chagin data = <mvl; 1348*bbf392d5SDmitry Chagin datalen = sizeof(ltmvl); 1349*bbf392d5SDmitry Chagin break; 1350605da56bSAndriy Gapon } 1351605da56bSAndriy Gapon 135274f5d680SKonstantin Belousov if (outlen + LINUX_CMSG_LEN(datalen) > 135374f5d680SKonstantin Belousov linux_msg.msg_controllen) { 135474f5d680SKonstantin Belousov if (outlen == 0) { 135574f5d680SKonstantin Belousov error = EMSGSIZE; 135674f5d680SKonstantin Belousov goto bad; 135774f5d680SKonstantin Belousov } else { 13583a72bf04SDmitry Chagin linux_msg.msg_flags |= 13593a72bf04SDmitry Chagin LINUX_MSG_CTRUNC; 136074f5d680SKonstantin Belousov goto out; 136174f5d680SKonstantin Belousov } 136274f5d680SKonstantin Belousov } 136374f5d680SKonstantin Belousov 136474f5d680SKonstantin Belousov linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 136574f5d680SKonstantin Belousov 136674f5d680SKonstantin Belousov error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 136774f5d680SKonstantin Belousov if (error) 136874f5d680SKonstantin Belousov goto bad; 136974f5d680SKonstantin Belousov outbuf += L_CMSG_HDRSZ; 137074f5d680SKonstantin Belousov 137174f5d680SKonstantin Belousov error = copyout(data, outbuf, datalen); 137274f5d680SKonstantin Belousov if (error) 137374f5d680SKonstantin Belousov goto bad; 137474f5d680SKonstantin Belousov 137574f5d680SKonstantin Belousov outbuf += LINUX_CMSG_ALIGN(datalen); 137674f5d680SKonstantin Belousov outlen += LINUX_CMSG_LEN(datalen); 137774f5d680SKonstantin Belousov 1378e1ff74c0SDmitry Chagin cm = CMSG_NXTHDR(msg, cm); 137974f5d680SKonstantin Belousov } 138074f5d680SKonstantin Belousov } 138174f5d680SKonstantin Belousov 138274f5d680SKonstantin Belousov out: 1383605da56bSAndriy Gapon linux_msg.msg_controllen = outlen; 1384e1ff74c0SDmitry Chagin error = copyout(&linux_msg, msghdr, sizeof(linux_msg)); 138574f5d680SKonstantin Belousov 138674f5d680SKonstantin Belousov bad: 138774f5d680SKonstantin Belousov free(iov, M_IOV); 138874f5d680SKonstantin Belousov m_freem(control); 1389e0d3ea8cSDmitry Chagin free(linux_cmsg, M_LINUX); 139074f5d680SKonstantin Belousov 1391ca26842eSHajimu UMEMOTO return (error); 139240dbba57SAssar Westerlund } 139340dbba57SAssar Westerlund 1394a12b9b3dSDmitry Chagin int 1395e1ff74c0SDmitry Chagin linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1396e1ff74c0SDmitry Chagin { 1397e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1398e1ff74c0SDmitry Chagin 1399e1ff74c0SDmitry Chagin return (linux_recvmsg_common(td, args->s, PTRIN(args->msg), 1400e1ff74c0SDmitry Chagin args->flags, &bsd_msg)); 1401e1ff74c0SDmitry Chagin } 1402e1ff74c0SDmitry Chagin 1403e1ff74c0SDmitry Chagin int 1404e1ff74c0SDmitry Chagin linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) 1405e1ff74c0SDmitry Chagin { 1406e1ff74c0SDmitry Chagin struct l_mmsghdr *msg; 1407e1ff74c0SDmitry Chagin struct msghdr bsd_msg; 1408e1ff74c0SDmitry Chagin struct l_timespec lts; 1409e1ff74c0SDmitry Chagin struct timespec ts, tts; 1410e1ff74c0SDmitry Chagin l_uint retval; 1411e1ff74c0SDmitry Chagin int error, datagrams; 1412e1ff74c0SDmitry Chagin 1413e1ff74c0SDmitry Chagin if (args->timeout) { 1414e1ff74c0SDmitry Chagin error = copyin(args->timeout, <s, sizeof(struct l_timespec)); 1415e1ff74c0SDmitry Chagin if (error != 0) 1416e1ff74c0SDmitry Chagin return (error); 1417e1ff74c0SDmitry Chagin error = linux_to_native_timespec(&ts, <s); 1418e1ff74c0SDmitry Chagin if (error != 0) 1419e1ff74c0SDmitry Chagin return (error); 1420e1ff74c0SDmitry Chagin getnanotime(&tts); 1421e1ff74c0SDmitry Chagin timespecadd(&tts, &ts); 1422e1ff74c0SDmitry Chagin } 1423e1ff74c0SDmitry Chagin 1424e1ff74c0SDmitry Chagin msg = PTRIN(args->msg); 1425e1ff74c0SDmitry Chagin datagrams = 0; 1426e1ff74c0SDmitry Chagin while (datagrams < args->vlen) { 1427e1ff74c0SDmitry Chagin error = linux_recvmsg_common(td, args->s, &msg->msg_hdr, 1428e1ff74c0SDmitry Chagin args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); 1429e1ff74c0SDmitry Chagin if (error != 0) 1430e1ff74c0SDmitry Chagin break; 1431e1ff74c0SDmitry Chagin 1432e1ff74c0SDmitry Chagin retval = td->td_retval[0]; 1433e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1434e1ff74c0SDmitry Chagin if (error != 0) 1435e1ff74c0SDmitry Chagin break; 1436e1ff74c0SDmitry Chagin ++msg; 1437e1ff74c0SDmitry Chagin ++datagrams; 1438e1ff74c0SDmitry Chagin 1439e1ff74c0SDmitry Chagin /* 1440e1ff74c0SDmitry Chagin * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. 1441e1ff74c0SDmitry Chagin */ 1442e1ff74c0SDmitry Chagin if (args->flags & LINUX_MSG_WAITFORONE) 1443e1ff74c0SDmitry Chagin args->flags |= LINUX_MSG_DONTWAIT; 1444e1ff74c0SDmitry Chagin 1445e1ff74c0SDmitry Chagin /* 1446e1ff74c0SDmitry Chagin * See BUGS section of recvmmsg(2). 1447e1ff74c0SDmitry Chagin */ 1448e1ff74c0SDmitry Chagin if (args->timeout) { 1449e1ff74c0SDmitry Chagin getnanotime(&ts); 1450e1ff74c0SDmitry Chagin timespecsub(&ts, &tts); 1451e1ff74c0SDmitry Chagin if (!timespecisset(&ts) || ts.tv_sec > 0) 1452e1ff74c0SDmitry Chagin break; 1453e1ff74c0SDmitry Chagin } 1454e1ff74c0SDmitry Chagin /* Out of band data, return right away. */ 1455e1ff74c0SDmitry Chagin if (bsd_msg.msg_flags & MSG_OOB) 1456e1ff74c0SDmitry Chagin break; 1457e1ff74c0SDmitry Chagin } 1458e1ff74c0SDmitry Chagin if (error == 0) 1459e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams; 1460e1ff74c0SDmitry Chagin return (error); 1461e1ff74c0SDmitry Chagin } 1462e1ff74c0SDmitry Chagin 1463e1ff74c0SDmitry Chagin int 1464b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1465c21dee17SSøren Schmidt { 1466ef04503dSPeter Wemm struct shutdown_args /* { 1467c21dee17SSøren Schmidt int s; 1468c21dee17SSøren Schmidt int how; 1469ef04503dSPeter Wemm } */ bsd_args; 1470c21dee17SSøren Schmidt 1471745aaef5SKonstantin Belousov bsd_args.s = args->s; 1472745aaef5SKonstantin Belousov bsd_args.how = args->how; 14738451d0ddSKip Macy return (sys_shutdown(td, &bsd_args)); 1474c21dee17SSøren Schmidt } 1475c21dee17SSøren Schmidt 1476a12b9b3dSDmitry Chagin int 1477b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1478c21dee17SSøren Schmidt { 1479ef04503dSPeter Wemm struct setsockopt_args /* { 1480c21dee17SSøren Schmidt int s; 1481c21dee17SSøren Schmidt int level; 1482c21dee17SSøren Schmidt int name; 1483c21dee17SSøren Schmidt caddr_t val; 1484c21dee17SSøren Schmidt int valsize; 1485ef04503dSPeter Wemm } */ bsd_args; 148603cc95d2SDmitry Chagin l_timeval linux_tv; 148703cc95d2SDmitry Chagin struct timeval tv; 1488c21dee17SSøren Schmidt int error, name; 1489c21dee17SSøren Schmidt 1490745aaef5SKonstantin Belousov bsd_args.s = args->s; 1491745aaef5SKonstantin Belousov bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1492c21dee17SSøren Schmidt switch (bsd_args.level) { 1493c21dee17SSøren Schmidt case SOL_SOCKET: 1494745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 149503cc95d2SDmitry Chagin switch (name) { 149603cc95d2SDmitry Chagin case SO_RCVTIMEO: 149703cc95d2SDmitry Chagin /* FALLTHROUGH */ 149803cc95d2SDmitry Chagin case SO_SNDTIMEO: 149903cc95d2SDmitry Chagin error = copyin(PTRIN(args->optval), &linux_tv, 150003cc95d2SDmitry Chagin sizeof(linux_tv)); 150103cc95d2SDmitry Chagin if (error) 150203cc95d2SDmitry Chagin return (error); 150303cc95d2SDmitry Chagin tv.tv_sec = linux_tv.tv_sec; 150403cc95d2SDmitry Chagin tv.tv_usec = linux_tv.tv_usec; 150503cc95d2SDmitry Chagin return (kern_setsockopt(td, args->s, bsd_args.level, 150603cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, sizeof(tv))); 150703cc95d2SDmitry Chagin /* NOTREACHED */ 150803cc95d2SDmitry Chagin break; 150903cc95d2SDmitry Chagin default: 151003cc95d2SDmitry Chagin break; 151103cc95d2SDmitry Chagin } 1512c21dee17SSøren Schmidt break; 1513c21dee17SSøren Schmidt case IPPROTO_IP: 1514745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1515c21dee17SSøren Schmidt break; 1516dad3b88aSMike Smith case IPPROTO_TCP: 1517fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1518dad3b88aSMike Smith break; 1519c21dee17SSøren Schmidt default: 15203f3a4815SMarcel Moolenaar name = -1; 15213f3a4815SMarcel Moolenaar break; 1522c21dee17SSøren Schmidt } 1523c21dee17SSøren Schmidt if (name == -1) 1524d4b7423fSAlexander Leidinger return (ENOPROTOOPT); 15253f3a4815SMarcel Moolenaar 1526c21dee17SSøren Schmidt bsd_args.name = name; 1527745aaef5SKonstantin Belousov bsd_args.val = PTRIN(args->optval); 1528745aaef5SKonstantin Belousov bsd_args.valsize = args->optlen; 15295c8919adSAlexander Leidinger 15305c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) { 15315c8919adSAlexander Leidinger linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, 15325c8919adSAlexander Leidinger bsd_args.valsize); 15338451d0ddSKip Macy error = sys_setsockopt(td, &bsd_args); 15345c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 15355c8919adSAlexander Leidinger } else 15368451d0ddSKip Macy error = sys_setsockopt(td, &bsd_args); 15375c8919adSAlexander Leidinger 15385c8919adSAlexander Leidinger return (error); 1539c21dee17SSøren Schmidt } 1540c21dee17SSøren Schmidt 1541a12b9b3dSDmitry Chagin int 1542b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1543c21dee17SSøren Schmidt { 1544ef04503dSPeter Wemm struct getsockopt_args /* { 1545c21dee17SSøren Schmidt int s; 1546c21dee17SSøren Schmidt int level; 1547c21dee17SSøren Schmidt int name; 1548c21dee17SSøren Schmidt caddr_t val; 1549c21dee17SSøren Schmidt int *avalsize; 1550ef04503dSPeter Wemm } */ bsd_args; 155103cc95d2SDmitry Chagin l_timeval linux_tv; 155203cc95d2SDmitry Chagin struct timeval tv; 1553d4dd69c4SDmitry Chagin socklen_t tv_len, xulen; 1554d4dd69c4SDmitry Chagin struct xucred xu; 1555d4dd69c4SDmitry Chagin struct l_ucred lxu; 1556c21dee17SSøren Schmidt int error, name; 1557c21dee17SSøren Schmidt 1558745aaef5SKonstantin Belousov bsd_args.s = args->s; 1559745aaef5SKonstantin Belousov bsd_args.level = linux_to_bsd_sockopt_level(args->level); 1560c21dee17SSøren Schmidt switch (bsd_args.level) { 1561c21dee17SSøren Schmidt case SOL_SOCKET: 1562745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname); 156303cc95d2SDmitry Chagin switch (name) { 156403cc95d2SDmitry Chagin case SO_RCVTIMEO: 156503cc95d2SDmitry Chagin /* FALLTHROUGH */ 156603cc95d2SDmitry Chagin case SO_SNDTIMEO: 156703cc95d2SDmitry Chagin tv_len = sizeof(tv); 156803cc95d2SDmitry Chagin error = kern_getsockopt(td, args->s, bsd_args.level, 156903cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, &tv_len); 157003cc95d2SDmitry Chagin if (error) 157103cc95d2SDmitry Chagin return (error); 157203cc95d2SDmitry Chagin linux_tv.tv_sec = tv.tv_sec; 157303cc95d2SDmitry Chagin linux_tv.tv_usec = tv.tv_usec; 157403cc95d2SDmitry Chagin return (copyout(&linux_tv, PTRIN(args->optval), 157503cc95d2SDmitry Chagin sizeof(linux_tv))); 157603cc95d2SDmitry Chagin /* NOTREACHED */ 157703cc95d2SDmitry Chagin break; 1578d4dd69c4SDmitry Chagin case LOCAL_PEERCRED: 1579d4dd69c4SDmitry Chagin if (args->optlen != sizeof(lxu)) 1580d4dd69c4SDmitry Chagin return (EINVAL); 1581d4dd69c4SDmitry Chagin xulen = sizeof(xu); 1582d4dd69c4SDmitry Chagin error = kern_getsockopt(td, args->s, bsd_args.level, 1583d4dd69c4SDmitry Chagin name, &xu, UIO_SYSSPACE, &xulen); 1584d4dd69c4SDmitry Chagin if (error) 1585d4dd69c4SDmitry Chagin return (error); 1586d4dd69c4SDmitry Chagin /* 1587d4dd69c4SDmitry Chagin * XXX Use 0 for pid as the FreeBSD does not cache peer pid. 1588d4dd69c4SDmitry Chagin */ 1589d4dd69c4SDmitry Chagin lxu.pid = 0; 1590d4dd69c4SDmitry Chagin lxu.uid = xu.cr_uid; 1591d4dd69c4SDmitry Chagin lxu.gid = xu.cr_gid; 1592d4dd69c4SDmitry Chagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1593d4dd69c4SDmitry Chagin /* NOTREACHED */ 1594d4dd69c4SDmitry Chagin break; 159503cc95d2SDmitry Chagin default: 159603cc95d2SDmitry Chagin break; 159703cc95d2SDmitry Chagin } 1598c21dee17SSøren Schmidt break; 1599c21dee17SSøren Schmidt case IPPROTO_IP: 1600745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname); 1601c21dee17SSøren Schmidt break; 1602dad3b88aSMike Smith case IPPROTO_TCP: 1603fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname); 1604dad3b88aSMike Smith break; 1605c21dee17SSøren Schmidt default: 16063f3a4815SMarcel Moolenaar name = -1; 16073f3a4815SMarcel Moolenaar break; 1608c21dee17SSøren Schmidt } 1609c21dee17SSøren Schmidt if (name == -1) 16103f3a4815SMarcel Moolenaar return (EINVAL); 16113f3a4815SMarcel Moolenaar 1612f2477ae1SMike Smith bsd_args.name = name; 1613745aaef5SKonstantin Belousov bsd_args.val = PTRIN(args->optval); 1614745aaef5SKonstantin Belousov bsd_args.avalsize = PTRIN(args->optlen); 16155c8919adSAlexander Leidinger 16165c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) { 16178451d0ddSKip Macy error = sys_getsockopt(td, &bsd_args); 16185c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 16195c8919adSAlexander Leidinger } else 16208451d0ddSKip Macy error = sys_getsockopt(td, &bsd_args); 16215c8919adSAlexander Leidinger 16225c8919adSAlexander Leidinger return (error); 1623c21dee17SSøren Schmidt } 1624c21dee17SSøren Schmidt 16257f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 16267f8f1d7fSDmitry Chagin 1627ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */ 1628ea7b81d2SDmitry Chagin 1629ea7b81d2SDmitry Chagin #define LINUX_AL(x) ((x) * sizeof(l_ulong)) 1630ea7b81d2SDmitry Chagin 1631ea7b81d2SDmitry Chagin static const unsigned char lxs_args[] = { 1632ea7b81d2SDmitry Chagin LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, 1633ea7b81d2SDmitry Chagin LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, 1634ea7b81d2SDmitry Chagin LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, 1635ea7b81d2SDmitry Chagin LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, 1636ea7b81d2SDmitry Chagin LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, 1637ea7b81d2SDmitry Chagin LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, 1638ea7b81d2SDmitry Chagin LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, 1639ea7b81d2SDmitry Chagin LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, 1640f8cd0af2SDmitry Chagin LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */, 1641e1ff74c0SDmitry Chagin LINUX_AL(4) /* accept4 */, LINUX_AL(5) /* recvmmsg */, 1642e1ff74c0SDmitry Chagin LINUX_AL(4) /* sendmmsg */ 1643ea7b81d2SDmitry Chagin }; 1644ea7b81d2SDmitry Chagin 1645ea7b81d2SDmitry Chagin #define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 1646ea7b81d2SDmitry Chagin 1647c21dee17SSøren Schmidt int 1648b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1649c21dee17SSøren Schmidt { 1650ea7b81d2SDmitry Chagin l_ulong a[6]; 1651ea7b81d2SDmitry Chagin void *arg; 1652ea7b81d2SDmitry Chagin int error; 16533f3a4815SMarcel Moolenaar 1654ea7b81d2SDmitry Chagin if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) 1655ea7b81d2SDmitry Chagin return (EINVAL); 1656ea7b81d2SDmitry Chagin error = copyin(PTRIN(args->args), a, lxs_args[args->what]); 1657ea7b81d2SDmitry Chagin if (error) 1658ea7b81d2SDmitry Chagin return (error); 1659ea7b81d2SDmitry Chagin 1660ea7b81d2SDmitry Chagin arg = a; 1661c21dee17SSøren Schmidt switch (args->what) { 1662c21dee17SSøren Schmidt case LINUX_SOCKET: 1663b40ce416SJulian Elischer return (linux_socket(td, arg)); 1664c21dee17SSøren Schmidt case LINUX_BIND: 1665b40ce416SJulian Elischer return (linux_bind(td, arg)); 1666c21dee17SSøren Schmidt case LINUX_CONNECT: 1667b40ce416SJulian Elischer return (linux_connect(td, arg)); 1668c21dee17SSøren Schmidt case LINUX_LISTEN: 1669b40ce416SJulian Elischer return (linux_listen(td, arg)); 1670c21dee17SSøren Schmidt case LINUX_ACCEPT: 1671b40ce416SJulian Elischer return (linux_accept(td, arg)); 1672c21dee17SSøren Schmidt case LINUX_GETSOCKNAME: 1673b40ce416SJulian Elischer return (linux_getsockname(td, arg)); 1674c21dee17SSøren Schmidt case LINUX_GETPEERNAME: 1675b40ce416SJulian Elischer return (linux_getpeername(td, arg)); 1676c21dee17SSøren Schmidt case LINUX_SOCKETPAIR: 1677b40ce416SJulian Elischer return (linux_socketpair(td, arg)); 1678c21dee17SSøren Schmidt case LINUX_SEND: 1679b40ce416SJulian Elischer return (linux_send(td, arg)); 1680c21dee17SSøren Schmidt case LINUX_RECV: 1681b40ce416SJulian Elischer return (linux_recv(td, arg)); 1682c21dee17SSøren Schmidt case LINUX_SENDTO: 1683b40ce416SJulian Elischer return (linux_sendto(td, arg)); 1684c21dee17SSøren Schmidt case LINUX_RECVFROM: 1685b40ce416SJulian Elischer return (linux_recvfrom(td, arg)); 1686c21dee17SSøren Schmidt case LINUX_SHUTDOWN: 1687b40ce416SJulian Elischer return (linux_shutdown(td, arg)); 1688c21dee17SSøren Schmidt case LINUX_SETSOCKOPT: 1689b40ce416SJulian Elischer return (linux_setsockopt(td, arg)); 1690c21dee17SSøren Schmidt case LINUX_GETSOCKOPT: 1691b40ce416SJulian Elischer return (linux_getsockopt(td, arg)); 1692e76bba09SSøren Schmidt case LINUX_SENDMSG: 1693ca26842eSHajimu UMEMOTO return (linux_sendmsg(td, arg)); 1694e76bba09SSøren Schmidt case LINUX_RECVMSG: 1695b40ce416SJulian Elischer return (linux_recvmsg(td, arg)); 1696f8cd0af2SDmitry Chagin case LINUX_ACCEPT4: 1697f8cd0af2SDmitry Chagin return (linux_accept4(td, arg)); 1698e1ff74c0SDmitry Chagin case LINUX_RECVMMSG: 1699e1ff74c0SDmitry Chagin return (linux_recvmmsg(td, arg)); 1700e1ff74c0SDmitry Chagin case LINUX_SENDMMSG: 1701e1ff74c0SDmitry Chagin return (linux_sendmmsg(td, arg)); 1702c21dee17SSøren Schmidt } 17033f3a4815SMarcel Moolenaar 17043f3a4815SMarcel Moolenaar uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 17053f3a4815SMarcel Moolenaar return (ENOSYS); 1706c21dee17SSøren Schmidt } 1707a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1708