19313Ssos/*- 2230132Suqs * Copyright (c) 1995 S��ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 9111798Sdes * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos */ 289313Ssos 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_socket.c 321022 2017-07-15 17:44:29Z dchagin $"); 31116173Sobrien 3212458Sbde/* XXX we use functions that might not exist. */ 33156874Sru#include "opt_compat.h" 34110295Sume#include "opt_inet6.h" 3512458Sbde 369313Ssos#include <sys/param.h> 3731711Smsmith#include <sys/proc.h> 389313Ssos#include <sys/systm.h> 3912458Sbde#include <sys/sysproto.h> 40280258Srwatson#include <sys/capsicum.h> 4133148Smsmith#include <sys/fcntl.h> 4273288Sjlemon#include <sys/file.h> 43114216Skan#include <sys/limits.h> 44147853Sjhb#include <sys/lock.h> 45110295Sume#include <sys/malloc.h> 46147853Sjhb#include <sys/mutex.h> 47122358Sdwmalone#include <sys/mbuf.h> 489313Ssos#include <sys/socket.h> 4973288Sjlemon#include <sys/socketvar.h> 50110295Sume#include <sys/syscallsubr.h> 5134924Sbde#include <sys/uio.h> 52110295Sume#include <sys/syslog.h> 53166398Skib#include <sys/un.h> 5412458Sbde 55185571Sbz#include <net/if.h> 569313Ssos#include <netinet/in.h> 5731711Smsmith#include <netinet/in_systm.h> 5831711Smsmith#include <netinet/ip.h> 59245849Sjhb#include <netinet/tcp.h> 60110295Sume#ifdef INET6 61110295Sume#include <netinet/ip6.h> 62110295Sume#include <netinet6/ip6_var.h> 63185571Sbz#include <netinet6/in6_var.h> 64110295Sume#endif 659313Ssos 66140214Sobrien#ifdef COMPAT_LINUX32 67140214Sobrien#include <machine/../linux32/linux.h> 68140214Sobrien#include <machine/../linux32/linux32_proto.h> 69140214Sobrien#else 7064913Smarcel#include <machine/../linux/linux.h> 7168583Smarcel#include <machine/../linux/linux_proto.h> 72133816Stjr#endif 73293541Sdchagin#include <compat/linux/linux_file.h> 7470178Sassar#include <compat/linux/linux_socket.h> 75293588Sdchagin#include <compat/linux/linux_timer.h> 7664913Smarcel#include <compat/linux/linux_util.h> 779313Ssos 78110295Sumestatic int linux_to_bsd_domain(int); 79293588Sdchaginstatic int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *, 80293588Sdchagin l_uint); 81293588Sdchaginstatic int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *, 82293588Sdchagin l_uint, struct msghdr *); 83293590Sdchaginstatic int linux_set_socket_flags(int, int *); 84110295Sume 8585569Sfenner/* 86110295Sume * Reads a linux sockaddr and does any necessary translation. 87110295Sume * Linux sockaddrs don't have a length field, only a family. 88110295Sume * Copy the osockaddr structure pointed to by osa to kernel, adjust 89110295Sume * family and convert to sockaddr. 90110295Sume */ 91110295Sumestatic int 92226078Sjkimlinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen) 93110295Sume{ 94110295Sume struct sockaddr *sa; 95110295Sume struct osockaddr *kosa; 96110295Sume#ifdef INET6 97226074Sjkim struct sockaddr_in6 *sin6; 98110295Sume int oldv6size; 99110295Sume#endif 100226073Sjkim char *name; 101226078Sjkim int bdom, error, hdrlen, namelen; 102110295Sume 103226078Sjkim if (salen < 2 || salen > UCHAR_MAX || !osa) 104110295Sume return (EINVAL); 105110295Sume 106110295Sume#ifdef INET6 107110295Sume oldv6size = 0; 108110295Sume /* 109110295Sume * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 110110295Sume * if it's a v4-mapped address, so reserve the proper space 111110295Sume * for it. 112110295Sume */ 113226078Sjkim if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { 114226078Sjkim salen += sizeof(uint32_t); 115110295Sume oldv6size = 1; 11685569Sfenner } 117110295Sume#endif 118110295Sume 119226078Sjkim kosa = malloc(salen, M_SONAME, M_WAITOK); 120110295Sume 121226078Sjkim if ((error = copyin(osa, kosa, salen))) 122110295Sume goto out; 123110295Sume 124110295Sume bdom = linux_to_bsd_domain(kosa->sa_family); 125110295Sume if (bdom == -1) { 126203728Sdelphij error = EAFNOSUPPORT; 127110295Sume goto out; 128110295Sume } 129110295Sume 130110295Sume#ifdef INET6 131110295Sume /* 132110295Sume * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 133110295Sume * which lacks the scope id compared with RFC2553 one. If we detect 134110295Sume * the situation, reject the address and write a message to system log. 135110295Sume * 136110295Sume * Still accept addresses for which the scope id is not used. 137110295Sume */ 138226072Sjkim if (oldv6size) { 139226072Sjkim if (bdom == AF_INET6) { 140226072Sjkim sin6 = (struct sockaddr_in6 *)kosa; 141226072Sjkim if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 142226072Sjkim (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 143226072Sjkim !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 144226072Sjkim !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 145226072Sjkim !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 146226072Sjkim !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 147226072Sjkim sin6->sin6_scope_id = 0; 148226072Sjkim } else { 149226072Sjkim log(LOG_DEBUG, 150226072Sjkim "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); 151226072Sjkim error = EINVAL; 152226072Sjkim goto out; 153226072Sjkim } 154226072Sjkim } else 155226078Sjkim salen -= sizeof(uint32_t); 156226072Sjkim } 157110295Sume#endif 158203728Sdelphij if (bdom == AF_INET) { 159226078Sjkim if (salen < sizeof(struct sockaddr_in)) { 160203728Sdelphij error = EINVAL; 161203728Sdelphij goto out; 162203728Sdelphij } 163226078Sjkim salen = sizeof(struct sockaddr_in); 164203728Sdelphij } 165110295Sume 166226078Sjkim if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) { 167226068Sjkim hdrlen = offsetof(struct sockaddr_un, sun_path); 168226073Sjkim name = ((struct sockaddr_un *)kosa)->sun_path; 169226073Sjkim if (*name == '\0') { 170226073Sjkim /* 171226073Sjkim * Linux abstract namespace starts with a NULL byte. 172226073Sjkim * XXX We do not support abstract namespace yet. 173226073Sjkim */ 174226078Sjkim namelen = strnlen(name + 1, salen - hdrlen - 1) + 1; 175226073Sjkim } else 176226078Sjkim namelen = strnlen(name, salen - hdrlen); 177226079Sjkim salen = hdrlen + namelen; 178226079Sjkim if (salen > sizeof(struct sockaddr_un)) { 179226071Sjkim error = ENAMETOOLONG; 180226023Scperciva goto out; 181226023Scperciva } 182226023Scperciva } 183226023Scperciva 184226074Sjkim sa = (struct sockaddr *)kosa; 185110295Sume sa->sa_family = bdom; 186226078Sjkim sa->sa_len = salen; 187110295Sume 188110295Sume *sap = sa; 189110295Sume return (0); 190110295Sume 191110295Sumeout: 192226069Sjkim free(kosa, M_SONAME); 193110295Sume return (error); 19485569Sfenner} 19585569Sfenner 1969313Ssosstatic int 1979313Ssoslinux_to_bsd_domain(int domain) 1989313Ssos{ 19965108Smarcel 20065108Smarcel switch (domain) { 20165108Smarcel case LINUX_AF_UNSPEC: 20265108Smarcel return (AF_UNSPEC); 20365108Smarcel case LINUX_AF_UNIX: 20465108Smarcel return (AF_LOCAL); 20565108Smarcel case LINUX_AF_INET: 20665108Smarcel return (AF_INET); 207110295Sume case LINUX_AF_INET6: 208110295Sume return (AF_INET6); 20965108Smarcel case LINUX_AF_AX25: 21065108Smarcel return (AF_CCITT); 21165108Smarcel case LINUX_AF_IPX: 21265108Smarcel return (AF_IPX); 21365108Smarcel case LINUX_AF_APPLETALK: 21465108Smarcel return (AF_APPLETALK); 21565108Smarcel } 21665108Smarcel return (-1); 2179313Ssos} 2189313Ssos 2199313Ssosstatic int 220110295Sumebsd_to_linux_domain(int domain) 221110295Sume{ 222110295Sume 223110295Sume switch (domain) { 224110295Sume case AF_UNSPEC: 225110295Sume return (LINUX_AF_UNSPEC); 226110295Sume case AF_LOCAL: 227110295Sume return (LINUX_AF_UNIX); 228110295Sume case AF_INET: 229110295Sume return (LINUX_AF_INET); 230110295Sume case AF_INET6: 231110295Sume return (LINUX_AF_INET6); 232110295Sume case AF_CCITT: 233110295Sume return (LINUX_AF_AX25); 234110295Sume case AF_IPX: 235110295Sume return (LINUX_AF_IPX); 236110295Sume case AF_APPLETALK: 237110295Sume return (LINUX_AF_APPLETALK); 238110295Sume } 239110295Sume return (-1); 240110295Sume} 241110295Sume 242110295Sumestatic int 2439313Ssoslinux_to_bsd_sockopt_level(int level) 2449313Ssos{ 24565108Smarcel 24665108Smarcel switch (level) { 24765108Smarcel case LINUX_SOL_SOCKET: 24865108Smarcel return (SOL_SOCKET); 24965108Smarcel } 25065108Smarcel return (level); 2519313Ssos} 2529313Ssos 25365108Smarcelstatic int 254121008Siwasakibsd_to_linux_sockopt_level(int level) 255121008Siwasaki{ 256121008Siwasaki 257121008Siwasaki switch (level) { 258121008Siwasaki case SOL_SOCKET: 259121008Siwasaki return (LINUX_SOL_SOCKET); 260121008Siwasaki } 261121008Siwasaki return (level); 262121008Siwasaki} 263121008Siwasaki 264121008Siwasakistatic int 26565108Smarcellinux_to_bsd_ip_sockopt(int opt) 2669313Ssos{ 26765108Smarcel 26865108Smarcel switch (opt) { 26965108Smarcel case LINUX_IP_TOS: 27065108Smarcel return (IP_TOS); 27165108Smarcel case LINUX_IP_TTL: 27265108Smarcel return (IP_TTL); 27365108Smarcel case LINUX_IP_OPTIONS: 27465108Smarcel return (IP_OPTIONS); 27565108Smarcel case LINUX_IP_MULTICAST_IF: 27665108Smarcel return (IP_MULTICAST_IF); 27765108Smarcel case LINUX_IP_MULTICAST_TTL: 27865108Smarcel return (IP_MULTICAST_TTL); 27965108Smarcel case LINUX_IP_MULTICAST_LOOP: 28065108Smarcel return (IP_MULTICAST_LOOP); 28165108Smarcel case LINUX_IP_ADD_MEMBERSHIP: 28265108Smarcel return (IP_ADD_MEMBERSHIP); 28365108Smarcel case LINUX_IP_DROP_MEMBERSHIP: 28465108Smarcel return (IP_DROP_MEMBERSHIP); 28565108Smarcel case LINUX_IP_HDRINCL: 28665108Smarcel return (IP_HDRINCL); 28765108Smarcel } 28865108Smarcel return (-1); 2899313Ssos} 2909313Ssos 2919313Ssosstatic int 292297211Saelinux_to_bsd_ip6_sockopt(int opt) 293297211Sae{ 294297211Sae 295297211Sae switch (opt) { 296297211Sae case LINUX_IPV6_NEXTHOP: 297297211Sae return (IPV6_NEXTHOP); 298297211Sae case LINUX_IPV6_UNICAST_HOPS: 299297211Sae return (IPV6_UNICAST_HOPS); 300297211Sae case LINUX_IPV6_MULTICAST_IF: 301297211Sae return (IPV6_MULTICAST_IF); 302297211Sae case LINUX_IPV6_MULTICAST_HOPS: 303297211Sae return (IPV6_MULTICAST_HOPS); 304297211Sae case LINUX_IPV6_MULTICAST_LOOP: 305297211Sae return (IPV6_MULTICAST_LOOP); 306297211Sae case LINUX_IPV6_ADD_MEMBERSHIP: 307297211Sae return (IPV6_JOIN_GROUP); 308297211Sae case LINUX_IPV6_DROP_MEMBERSHIP: 309297211Sae return (IPV6_LEAVE_GROUP); 310297211Sae case LINUX_IPV6_V6ONLY: 311297211Sae return (IPV6_V6ONLY); 312297211Sae case LINUX_IPV6_DONTFRAG: 313297211Sae return (IPV6_DONTFRAG); 314297211Sae#if 0 315297211Sae case LINUX_IPV6_CHECKSUM: 316297211Sae return (IPV6_CHECKSUM); 317297211Sae case LINUX_IPV6_RECVPKTINFO: 318297211Sae return (IPV6_RECVPKTINFO); 319297211Sae case LINUX_IPV6_PKTINFO: 320297211Sae return (IPV6_PKTINFO); 321297211Sae case LINUX_IPV6_RECVHOPLIMIT: 322297211Sae return (IPV6_RECVHOPLIMIT); 323297211Sae case LINUX_IPV6_HOPLIMIT: 324297211Sae return (IPV6_HOPLIMIT); 325297211Sae case LINUX_IPV6_RECVHOPOPTS: 326297211Sae return (IPV6_RECVHOPOPTS); 327297211Sae case LINUX_IPV6_HOPOPTS: 328297211Sae return (IPV6_HOPOPTS); 329297211Sae case LINUX_IPV6_RTHDRDSTOPTS: 330297211Sae return (IPV6_RTHDRDSTOPTS); 331297211Sae case LINUX_IPV6_RECVRTHDR: 332297211Sae return (IPV6_RECVRTHDR); 333297211Sae case LINUX_IPV6_RTHDR: 334297211Sae return (IPV6_RTHDR); 335297211Sae case LINUX_IPV6_RECVDSTOPTS: 336297211Sae return (IPV6_RECVDSTOPTS); 337297211Sae case LINUX_IPV6_DSTOPTS: 338297211Sae return (IPV6_DSTOPTS); 339297211Sae case LINUX_IPV6_RECVPATHMTU: 340297211Sae return (IPV6_RECVPATHMTU); 341297211Sae case LINUX_IPV6_PATHMTU: 342297211Sae return (IPV6_PATHMTU); 343297211Sae#endif 344297211Sae } 345297211Sae return (-1); 346297211Sae} 347297211Sae 348297211Saestatic int 3499313Ssoslinux_to_bsd_so_sockopt(int opt) 3509313Ssos{ 35165108Smarcel 35265108Smarcel switch (opt) { 35365108Smarcel case LINUX_SO_DEBUG: 35465108Smarcel return (SO_DEBUG); 35565108Smarcel case LINUX_SO_REUSEADDR: 35665108Smarcel return (SO_REUSEADDR); 35765108Smarcel case LINUX_SO_TYPE: 35865108Smarcel return (SO_TYPE); 35965108Smarcel case LINUX_SO_ERROR: 36065108Smarcel return (SO_ERROR); 36165108Smarcel case LINUX_SO_DONTROUTE: 36265108Smarcel return (SO_DONTROUTE); 36365108Smarcel case LINUX_SO_BROADCAST: 36465108Smarcel return (SO_BROADCAST); 36565108Smarcel case LINUX_SO_SNDBUF: 36665108Smarcel return (SO_SNDBUF); 36765108Smarcel case LINUX_SO_RCVBUF: 36865108Smarcel return (SO_RCVBUF); 36965108Smarcel case LINUX_SO_KEEPALIVE: 37065108Smarcel return (SO_KEEPALIVE); 37165108Smarcel case LINUX_SO_OOBINLINE: 37265108Smarcel return (SO_OOBINLINE); 37365108Smarcel case LINUX_SO_LINGER: 37465108Smarcel return (SO_LINGER); 375166398Skib case LINUX_SO_PEERCRED: 376166398Skib return (LOCAL_PEERCRED); 377166398Skib case LINUX_SO_RCVLOWAT: 378166398Skib return (SO_RCVLOWAT); 379166398Skib case LINUX_SO_SNDLOWAT: 380166398Skib return (SO_SNDLOWAT); 381166398Skib case LINUX_SO_RCVTIMEO: 382166398Skib return (SO_RCVTIMEO); 383166398Skib case LINUX_SO_SNDTIMEO: 384166398Skib return (SO_SNDTIMEO); 385166398Skib case LINUX_SO_TIMESTAMP: 386166398Skib return (SO_TIMESTAMP); 387166398Skib case LINUX_SO_ACCEPTCONN: 388166398Skib return (SO_ACCEPTCONN); 38965108Smarcel } 39065108Smarcel return (-1); 3919313Ssos} 3929313Ssos 39370178Sassarstatic int 394245849Sjhblinux_to_bsd_tcp_sockopt(int opt) 395245849Sjhb{ 396245849Sjhb 397245849Sjhb switch (opt) { 398245849Sjhb case LINUX_TCP_NODELAY: 399245849Sjhb return (TCP_NODELAY); 400245849Sjhb case LINUX_TCP_MAXSEG: 401245849Sjhb return (TCP_MAXSEG); 402245849Sjhb case LINUX_TCP_KEEPIDLE: 403245849Sjhb return (TCP_KEEPIDLE); 404245849Sjhb case LINUX_TCP_KEEPINTVL: 405245849Sjhb return (TCP_KEEPINTVL); 406245849Sjhb case LINUX_TCP_KEEPCNT: 407245849Sjhb return (TCP_KEEPCNT); 408245849Sjhb case LINUX_TCP_MD5SIG: 409245849Sjhb return (TCP_MD5SIG); 410245849Sjhb } 411245849Sjhb return (-1); 412245849Sjhb} 413245849Sjhb 414245849Sjhbstatic int 41570178Sassarlinux_to_bsd_msg_flags(int flags) 41670178Sassar{ 41770178Sassar int ret_flags = 0; 41870178Sassar 41970178Sassar if (flags & LINUX_MSG_OOB) 42070178Sassar ret_flags |= MSG_OOB; 42170178Sassar if (flags & LINUX_MSG_PEEK) 42270178Sassar ret_flags |= MSG_PEEK; 42370178Sassar if (flags & LINUX_MSG_DONTROUTE) 42470178Sassar ret_flags |= MSG_DONTROUTE; 42570178Sassar if (flags & LINUX_MSG_CTRUNC) 42670178Sassar ret_flags |= MSG_CTRUNC; 42770178Sassar if (flags & LINUX_MSG_TRUNC) 42870178Sassar ret_flags |= MSG_TRUNC; 42970178Sassar if (flags & LINUX_MSG_DONTWAIT) 43070178Sassar ret_flags |= MSG_DONTWAIT; 43170178Sassar if (flags & LINUX_MSG_EOR) 43270178Sassar ret_flags |= MSG_EOR; 43370178Sassar if (flags & LINUX_MSG_WAITALL) 43470178Sassar ret_flags |= MSG_WAITALL; 435143295Ssobomax if (flags & LINUX_MSG_NOSIGNAL) 436143295Ssobomax ret_flags |= MSG_NOSIGNAL; 43770178Sassar#if 0 /* not handled */ 43870178Sassar if (flags & LINUX_MSG_PROXY) 43970178Sassar ; 44070178Sassar if (flags & LINUX_MSG_FIN) 44170178Sassar ; 44270178Sassar if (flags & LINUX_MSG_SYN) 44370178Sassar ; 44470178Sassar if (flags & LINUX_MSG_CONFIRM) 44570178Sassar ; 44670178Sassar if (flags & LINUX_MSG_RST) 44770178Sassar ; 44870178Sassar if (flags & LINUX_MSG_ERRQUEUE) 44970178Sassar ; 45070178Sassar#endif 451297518Sdchagin return (ret_flags); 45270178Sassar} 45370178Sassar 454156842Snetchild/* 455156842Snetchild* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the 456156842Snetchild* native syscall will fault. Thus, we don't really need to check the 457156842Snetchild* return values for these functions. 458156842Snetchild*/ 459156842Snetchild 460110295Sumestatic int 461156842Snetchildbsd_to_linux_sockaddr(struct sockaddr *arg) 462156842Snetchild{ 463156842Snetchild struct sockaddr sa; 464156842Snetchild size_t sa_len = sizeof(struct sockaddr); 465301431Sdchagin int error, bdom; 466297518Sdchagin 467156842Snetchild if ((error = copyin(arg, &sa, sa_len))) 468156842Snetchild return (error); 469297518Sdchagin 470301431Sdchagin bdom = bsd_to_linux_domain(sa.sa_family); 471301431Sdchagin if (bdom == -1) 472301431Sdchagin return (EAFNOSUPPORT); 473301431Sdchagin 474301431Sdchagin *(u_short *)&sa = bdom; 475297518Sdchagin return (copyout(&sa, arg, sa_len)); 476156842Snetchild} 477156842Snetchild 478156842Snetchildstatic int 479156842Snetchildlinux_to_bsd_sockaddr(struct sockaddr *arg, int len) 480156842Snetchild{ 481156842Snetchild struct sockaddr sa; 482156842Snetchild size_t sa_len = sizeof(struct sockaddr); 483301431Sdchagin int error, bdom; 484156842Snetchild 485156842Snetchild if ((error = copyin(arg, &sa, sa_len))) 486156842Snetchild return (error); 487156842Snetchild 488301431Sdchagin bdom = linux_to_bsd_domain(*(sa_family_t *)&sa); 489301431Sdchagin if (bdom == -1) 490301431Sdchagin return (EAFNOSUPPORT); 491301431Sdchagin 492301431Sdchagin sa.sa_family = bdom; 493156842Snetchild sa.sa_len = len; 494297518Sdchagin return (copyout(&sa, arg, sa_len)); 495156842Snetchild} 496156842Snetchild 497156842Snetchildstatic int 498110295Sumelinux_sa_put(struct osockaddr *osa) 499110295Sume{ 500110295Sume struct osockaddr sa; 501110295Sume int error, bdom; 502110295Sume 503110295Sume /* 504110295Sume * Only read/write the osockaddr family part, the rest is 505110295Sume * not changed. 506110295Sume */ 507111797Sdes error = copyin(osa, &sa, sizeof(sa.sa_family)); 508110295Sume if (error) 509110295Sume return (error); 510110295Sume 511110295Sume bdom = bsd_to_linux_domain(sa.sa_family); 512110295Sume if (bdom == -1) 513110295Sume return (EINVAL); 514110295Sume 515110295Sume sa.sa_family = bdom; 516297518Sdchagin return (copyout(&sa, osa, sizeof(sa.sa_family))); 517110295Sume} 518110295Sume 519122358Sdwmalonestatic int 520185442Skiblinux_to_bsd_cmsg_type(int cmsg_type) 521185442Skib{ 522185442Skib 523185442Skib switch (cmsg_type) { 524185442Skib case LINUX_SCM_RIGHTS: 525185442Skib return (SCM_RIGHTS); 526220031Savg case LINUX_SCM_CREDENTIALS: 527220031Savg return (SCM_CREDS); 528185442Skib } 529185442Skib return (-1); 530185442Skib} 531185442Skib 532185442Skibstatic int 533185442Skibbsd_to_linux_cmsg_type(int cmsg_type) 534185442Skib{ 535185442Skib 536185442Skib switch (cmsg_type) { 537185442Skib case SCM_RIGHTS: 538185442Skib return (LINUX_SCM_RIGHTS); 539220031Savg case SCM_CREDS: 540220031Savg return (LINUX_SCM_CREDENTIALS); 541293597Sdchagin case SCM_TIMESTAMP: 542293597Sdchagin return (LINUX_SCM_TIMESTAMP); 543185442Skib } 544185442Skib return (-1); 545185442Skib} 546185442Skib 547185442Skibstatic int 548185442Skiblinux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 549185442Skib{ 550185442Skib if (lhdr->msg_controllen > INT_MAX) 551185442Skib return (ENOBUFS); 552185442Skib 553185442Skib bhdr->msg_name = PTRIN(lhdr->msg_name); 554185442Skib bhdr->msg_namelen = lhdr->msg_namelen; 555185442Skib bhdr->msg_iov = PTRIN(lhdr->msg_iov); 556185442Skib bhdr->msg_iovlen = lhdr->msg_iovlen; 557185442Skib bhdr->msg_control = PTRIN(lhdr->msg_control); 558220031Savg 559220031Savg /* 560220031Savg * msg_controllen is skipped since BSD and LINUX control messages 561220031Savg * are potentially different sizes (e.g. the cred structure used 562220031Savg * by SCM_CREDS is different between the two operating system). 563220031Savg * 564220031Savg * The caller can set it (if necessary) after converting all the 565220031Savg * control messages. 566220031Savg */ 567220031Savg 568185442Skib bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 569185442Skib return (0); 570185442Skib} 571185442Skib 572185442Skibstatic int 573185442Skibbsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 574185442Skib{ 575185442Skib lhdr->msg_name = PTROUT(bhdr->msg_name); 576185442Skib lhdr->msg_namelen = bhdr->msg_namelen; 577185442Skib lhdr->msg_iov = PTROUT(bhdr->msg_iov); 578185442Skib lhdr->msg_iovlen = bhdr->msg_iovlen; 579185442Skib lhdr->msg_control = PTROUT(bhdr->msg_control); 580220031Savg 581220031Savg /* 582220031Savg * msg_controllen is skipped since BSD and LINUX control messages 583220031Savg * are potentially different sizes (e.g. the cred structure used 584220031Savg * by SCM_CREDS is different between the two operating system). 585220031Savg * 586220031Savg * The caller can set it (if necessary) after converting all the 587220031Savg * control messages. 588220031Savg */ 589220031Savg 590185442Skib /* msg_flags skipped */ 591185442Skib return (0); 592185442Skib} 593185442Skib 594185442Skibstatic int 595293590Sdchaginlinux_set_socket_flags(int lflags, int *flags) 596193165Sdchagin{ 597193165Sdchagin 598293590Sdchagin if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 599293590Sdchagin return (EINVAL); 600293590Sdchagin if (lflags & LINUX_SOCK_NONBLOCK) 601293590Sdchagin *flags |= SOCK_NONBLOCK; 602293590Sdchagin if (lflags & LINUX_SOCK_CLOEXEC) 603293590Sdchagin *flags |= SOCK_CLOEXEC; 604193165Sdchagin return (0); 605193165Sdchagin} 606193165Sdchagin 607193165Sdchaginstatic int 608141029Ssobomaxlinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 609185442Skib struct mbuf *control, enum uio_seg segflg) 610122358Sdwmalone{ 611122358Sdwmalone struct sockaddr *to; 612122358Sdwmalone int error; 613122358Sdwmalone 614122358Sdwmalone if (mp->msg_name != NULL) { 615122358Sdwmalone error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 616122358Sdwmalone if (error) 617122358Sdwmalone return (error); 618122358Sdwmalone mp->msg_name = to; 619122358Sdwmalone } else 620122358Sdwmalone to = NULL; 621122358Sdwmalone 622141029Ssobomax error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 623141029Ssobomax segflg); 624122358Sdwmalone 625122358Sdwmalone if (to) 626184205Sdes free(to, M_SONAME); 627122358Sdwmalone return (error); 628122358Sdwmalone} 629122358Sdwmalone 63065108Smarcel/* Return 0 if IP_HDRINCL is set for the given socket. */ 63131711Smsmithstatic int 632132313Sdwmalonelinux_check_hdrincl(struct thread *td, int s) 63331711Smsmith{ 634276813Sdchagin int error, optval; 635276813Sdchagin socklen_t size_val; 63631711Smsmith 637132313Sdwmalone size_val = sizeof(optval); 638132313Sdwmalone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 639132313Sdwmalone &optval, UIO_SYSSPACE, &size_val); 640132313Sdwmalone if (error) 64165108Smarcel return (error); 64265108Smarcel 64365108Smarcel return (optval == 0); 64431711Smsmith} 64531711Smsmith 64631711Smsmith/* 64731711Smsmith * Updated sendto() when IP_HDRINCL is set: 64831711Smsmith * tweak endian-dependent fields in the IP packet. 64931711Smsmith */ 65031711Smsmithstatic int 651132331Srwatsonlinux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 65231711Smsmith{ 65331711Smsmith/* 65431711Smsmith * linux_ip_copysize defines how many bytes we should copy 65531711Smsmith * from the beginning of the IP packet before we customize it for BSD. 656141029Ssobomax * It should include all the fields we modify (ip_len and ip_off). 65731711Smsmith */ 65831711Smsmith#define linux_ip_copysize 8 65931711Smsmith 66065108Smarcel struct ip *packet; 661122358Sdwmalone struct msghdr msg; 662141029Ssobomax struct iovec aiov[1]; 66365108Smarcel int error; 66431711Smsmith 665144012Sdas /* Check that the packet isn't too big or too small. */ 666144012Sdas if (linux_args->len < linux_ip_copysize || 667144012Sdas linux_args->len > IP_MAXPACKET) 66865108Smarcel return (EINVAL); 66931711Smsmith 670293532Sdchagin packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK); 67131711Smsmith 672141029Ssobomax /* Make kernel copy of the packet to be sent */ 673133816Stjr if ((error = copyin(PTRIN(linux_args->msg), packet, 674141029Ssobomax linux_args->len))) 675141029Ssobomax goto goout; 67631711Smsmith 67765108Smarcel /* Convert fields from Linux to BSD raw IP socket format */ 678122358Sdwmalone packet->ip_len = linux_args->len; 67965108Smarcel packet->ip_off = ntohs(packet->ip_off); 68031711Smsmith 68165108Smarcel /* Prepare the msghdr and iovec structures describing the new packet */ 682133816Stjr msg.msg_name = PTRIN(linux_args->to); 683122358Sdwmalone msg.msg_namelen = linux_args->tolen; 684122358Sdwmalone msg.msg_iov = aiov; 685141029Ssobomax msg.msg_iovlen = 1; 686122358Sdwmalone msg.msg_control = NULL; 687122358Sdwmalone msg.msg_flags = 0; 688122358Sdwmalone aiov[0].iov_base = (char *)packet; 689141029Ssobomax aiov[0].iov_len = linux_args->len; 690141029Ssobomax error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 691185442Skib NULL, UIO_SYSSPACE); 692141029Ssobomaxgoout: 693293532Sdchagin free(packet, M_LINUX); 694122358Sdwmalone return (error); 69531711Smsmith} 69631711Smsmith 697293519Sdchaginint 69883366Sjulianlinux_socket(struct thread *td, struct linux_socket_args *args) 6999313Ssos{ 70065108Smarcel struct socket_args /* { 70165108Smarcel int domain; 70265108Smarcel int type; 70365108Smarcel int protocol; 70465108Smarcel } */ bsd_args; 705293590Sdchagin int retval_socket; 7069313Ssos 707182890Skib bsd_args.protocol = args->protocol; 708192206Sdchagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 709192205Sdchagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 710192205Sdchagin return (EINVAL); 711293590Sdchagin retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 712293590Sdchagin &bsd_args.type); 713293590Sdchagin if (retval_socket != 0) 714293590Sdchagin return (retval_socket); 715182890Skib bsd_args.domain = linux_to_bsd_domain(args->domain); 71665108Smarcel if (bsd_args.domain == -1) 717191875Sdchagin return (EAFNOSUPPORT); 71831711Smsmith 719225617Skmacy retval_socket = sys_socket(td, &bsd_args); 720192204Sdchagin if (retval_socket) 721192204Sdchagin return (retval_socket); 722192204Sdchagin 72365108Smarcel if (bsd_args.type == SOCK_RAW 72465108Smarcel && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 725192204Sdchagin && bsd_args.domain == PF_INET) { 72665108Smarcel /* It's a raw IP socket: set the IP_HDRINCL option. */ 727132313Sdwmalone int hdrincl; 72865108Smarcel 729132313Sdwmalone hdrincl = 1; 730132313Sdwmalone /* We ignore any error returned by kern_setsockopt() */ 731132313Sdwmalone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 732132313Sdwmalone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 73365108Smarcel } 734110295Sume#ifdef INET6 735110295Sume /* 736198467Sbz * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default 737198467Sbz * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. 738198467Sbz * For simplicity we do this unconditionally of the net.inet6.ip6.v6only 739198467Sbz * sysctl value. 740110295Sume */ 741198467Sbz if (bsd_args.domain == PF_INET6) { 742132313Sdwmalone int v6only; 74365108Smarcel 744132313Sdwmalone v6only = 0; 745110295Sume /* We ignore any error returned by setsockopt() */ 746132313Sdwmalone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 747132313Sdwmalone &v6only, UIO_SYSSPACE, sizeof(v6only)); 748110295Sume } 749110295Sume#endif 750110295Sume 75165108Smarcel return (retval_socket); 7529313Ssos} 7539313Ssos 754293519Sdchaginint 75583366Sjulianlinux_bind(struct thread *td, struct linux_bind_args *args) 7569313Ssos{ 757110295Sume struct sockaddr *sa; 75865108Smarcel int error; 7599313Ssos 760182890Skib error = linux_getsockaddr(&sa, PTRIN(args->name), 761182890Skib args->namelen); 762110295Sume if (error) 763110295Sume return (error); 764110295Sume 765182890Skib error = kern_bind(td, args->s, sa); 766160506Sjhb free(sa, M_SONAME); 767182890Skib if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 768162585Snetchild return (EINVAL); 769160506Sjhb return (error); 7709313Ssos} 7719313Ssos 77268803Sgallatinint 77383366Sjulianlinux_connect(struct thread *td, struct linux_connect_args *args) 7749313Ssos{ 775255219Spjd cap_rights_t rights; 77673288Sjlemon struct socket *so; 777110295Sume struct sockaddr *sa; 77886504Sdillon u_int fflag; 77965108Smarcel int error; 7809313Ssos 781182890Skib error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), 782182890Skib args->namelen); 783110295Sume if (error) 784110295Sume return (error); 785110295Sume 786182890Skib error = kern_connect(td, args->s, sa); 787160506Sjhb free(sa, M_SONAME); 78873288Sjlemon if (error != EISCONN) 78973288Sjlemon return (error); 79033148Smsmith 79173288Sjlemon /* 79273288Sjlemon * Linux doesn't return EISCONN the first time it occurs, 79373288Sjlemon * when on a non-blocking socket. Instead it returns the 79473288Sjlemon * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 795157369Srwatson * 796157369Srwatson * XXXRW: Instead of using fgetsock(), check that it is a 797157369Srwatson * socket and use the file descriptor reference instead of 798157369Srwatson * creating a new one. 79973288Sjlemon */ 800255219Spjd error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT), 801255219Spjd &so, &fflag); 802147853Sjhb if (error == 0) { 803147853Sjhb error = EISCONN; 804147853Sjhb if (fflag & FNONBLOCK) { 805147853Sjhb SOCK_LOCK(so); 806147853Sjhb if (so->so_emuldata == 0) 807147853Sjhb error = so->so_error; 808147853Sjhb so->so_emuldata = (void *)1; 809147853Sjhb SOCK_UNLOCK(so); 810147853Sjhb } 811147853Sjhb fputsock(so); 81233148Smsmith } 81365108Smarcel return (error); 8149313Ssos} 8159313Ssos 816293519Sdchaginint 81783366Sjulianlinux_listen(struct thread *td, struct linux_listen_args *args) 8189313Ssos{ 81965108Smarcel struct listen_args /* { 82065108Smarcel int s; 82165108Smarcel int backlog; 82265108Smarcel } */ bsd_args; 8239313Ssos 824182890Skib bsd_args.s = args->s; 825182890Skib bsd_args.backlog = args->backlog; 826225617Skmacy return (sys_listen(td, &bsd_args)); 8279313Ssos} 8289313Ssos 829158415Snetchildstatic int 830193262Sdchaginlinux_accept_common(struct thread *td, int s, l_uintptr_t addr, 831193265Sdchagin l_uintptr_t namelen, int flags) 8329313Ssos{ 833293590Sdchagin struct accept4_args /* { 834123828Sbde int s; 835123828Sbde struct sockaddr * __restrict name; 836123828Sbde socklen_t * __restrict anamelen; 837293590Sdchagin int flags; 83865108Smarcel } */ bsd_args; 839321022Sdchagin cap_rights_t rights; 840321022Sdchagin struct socket *so; 841321022Sdchagin struct file *fp; 842321022Sdchagin int error, error1; 8439313Ssos 844193262Sdchagin bsd_args.s = s; 845123828Sbde /* XXX: */ 846193262Sdchagin bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr); 847193262Sdchagin bsd_args.anamelen = PTRIN(namelen);/* XXX */ 848293605Sdchagin bsd_args.flags = 0; 849293590Sdchagin error = linux_set_socket_flags(flags, &bsd_args.flags); 850293590Sdchagin if (error != 0) 851293590Sdchagin return (error); 852293590Sdchagin error = sys_accept4(td, &bsd_args); 853156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); 854162585Snetchild if (error) { 855193262Sdchagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 856182890Skib return (EINVAL); 857321022Sdchagin if (error == EINVAL) { 858321022Sdchagin error1 = getsock_cap(td, s, 859321022Sdchagin cap_rights_init(&rights, CAP_ACCEPT), &fp, NULL); 860321022Sdchagin if (error1 != 0) 861321022Sdchagin return (error1); 862321022Sdchagin so = fp->f_data; 863321022Sdchagin if (so->so_type == SOCK_DGRAM) { 864321022Sdchagin fdrop(fp, td); 865321022Sdchagin return (EOPNOTSUPP); 866321022Sdchagin } 867321022Sdchagin fdrop(fp, td); 868321022Sdchagin } 86965108Smarcel return (error); 870162585Snetchild } 871193263Sdchagin if (addr) 872193263Sdchagin error = linux_sa_put(PTRIN(addr)); 873193263Sdchagin if (error) { 874193263Sdchagin (void)kern_close(td, td->td_retval[0]); 875193263Sdchagin td->td_retval[0] = 0; 876193263Sdchagin } 877193263Sdchagin return (error); 8789313Ssos} 8799313Ssos 880293519Sdchaginint 881193262Sdchaginlinux_accept(struct thread *td, struct linux_accept_args *args) 882193262Sdchagin{ 883193262Sdchagin 884193262Sdchagin return (linux_accept_common(td, args->s, args->addr, 885193265Sdchagin args->namelen, 0)); 886193262Sdchagin} 887193262Sdchagin 888293519Sdchaginint 889193264Sdchaginlinux_accept4(struct thread *td, struct linux_accept4_args *args) 890193264Sdchagin{ 891193264Sdchagin 892193264Sdchagin return (linux_accept_common(td, args->s, args->addr, 893193264Sdchagin args->namelen, args->flags)); 894193264Sdchagin} 895193264Sdchagin 896293519Sdchaginint 89783366Sjulianlinux_getsockname(struct thread *td, struct linux_getsockname_args *args) 8989313Ssos{ 89965108Smarcel struct getsockname_args /* { 900123828Sbde int fdes; 901123828Sbde struct sockaddr * __restrict asa; 902123828Sbde socklen_t * __restrict alen; 90365108Smarcel } */ bsd_args; 90465108Smarcel int error; 9059313Ssos 906182890Skib bsd_args.fdes = args->s; 907123828Sbde /* XXX: */ 908182890Skib bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); 909182890Skib bsd_args.alen = PTRIN(args->namelen); /* XXX */ 910225617Skmacy error = sys_getsockname(td, &bsd_args); 911156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 912110295Sume if (error) 913110295Sume return (error); 914297518Sdchagin return (linux_sa_put(PTRIN(args->addr))); 9159313Ssos} 9169313Ssos 917293519Sdchaginint 91883366Sjulianlinux_getpeername(struct thread *td, struct linux_getpeername_args *args) 9199313Ssos{ 920156842Snetchild struct getpeername_args /* { 92165108Smarcel int fdes; 92265108Smarcel caddr_t asa; 92365108Smarcel int *alen; 92465108Smarcel } */ bsd_args; 92565108Smarcel int error; 9269313Ssos 927182890Skib bsd_args.fdes = args->s; 928182890Skib bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); 929276813Sdchagin bsd_args.alen = (socklen_t *)PTRIN(args->namelen); 930225617Skmacy error = sys_getpeername(td, &bsd_args); 931156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 932110295Sume if (error) 933110295Sume return (error); 934297518Sdchagin return (linux_sa_put(PTRIN(args->addr))); 9359313Ssos} 9369313Ssos 937293519Sdchaginint 93883366Sjulianlinux_socketpair(struct thread *td, struct linux_socketpair_args *args) 9399313Ssos{ 94065108Smarcel struct socketpair_args /* { 94165108Smarcel int domain; 94265108Smarcel int type; 94365108Smarcel int protocol; 94465108Smarcel int *rsv; 94565108Smarcel } */ bsd_args; 946293590Sdchagin int error; 9479313Ssos 948182890Skib bsd_args.domain = linux_to_bsd_domain(args->domain); 949191871Sdchagin if (bsd_args.domain != PF_LOCAL) 950191871Sdchagin return (EAFNOSUPPORT); 951193168Sdchagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 952193168Sdchagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 953193168Sdchagin return (EINVAL); 954293590Sdchagin error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK, 955293590Sdchagin &bsd_args.type); 956293590Sdchagin if (error != 0) 957293590Sdchagin return (error); 958191871Sdchagin if (args->protocol != 0 && args->protocol != PF_UNIX) 959191871Sdchagin 960191871Sdchagin /* 961191871Sdchagin * Use of PF_UNIX as protocol argument is not right, 962191871Sdchagin * but Linux does it. 963191871Sdchagin * Do not map PF_UNIX as its Linux value is identical 964191871Sdchagin * to FreeBSD one. 965191871Sdchagin */ 966191871Sdchagin return (EPROTONOSUPPORT); 967191871Sdchagin else 968191742Sdchagin bsd_args.protocol = 0; 969182890Skib bsd_args.rsv = (int *)PTRIN(args->rsv); 970293590Sdchagin return (sys_socketpair(td, &bsd_args)); 9719313Ssos} 9729313Ssos 973293519Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 974158415Snetchildstruct linux_send_args { 97565108Smarcel int s; 976133816Stjr l_uintptr_t msg; 97765108Smarcel int len; 97865108Smarcel int flags; 9799313Ssos}; 9809313Ssos 981158415Snetchildstatic int 98283366Sjulianlinux_send(struct thread *td, struct linux_send_args *args) 9839313Ssos{ 984131796Sphk struct sendto_args /* { 985103886Smini int s; 98665108Smarcel caddr_t buf; 987103886Smini int len; 98865108Smarcel int flags; 989131796Sphk caddr_t to; 990131796Sphk int tolen; 99165108Smarcel } */ bsd_args; 9929313Ssos 993182890Skib bsd_args.s = args->s; 994182890Skib bsd_args.buf = (caddr_t)PTRIN(args->msg); 995182890Skib bsd_args.len = args->len; 996182890Skib bsd_args.flags = args->flags; 997131796Sphk bsd_args.to = NULL; 998131796Sphk bsd_args.tolen = 0; 999297518Sdchagin return (sys_sendto(td, &bsd_args)); 10009313Ssos} 10019313Ssos 1002158415Snetchildstruct linux_recv_args { 100365108Smarcel int s; 1004133816Stjr l_uintptr_t msg; 100565108Smarcel int len; 100665108Smarcel int flags; 10079313Ssos}; 10089313Ssos 1009158415Snetchildstatic int 101083366Sjulianlinux_recv(struct thread *td, struct linux_recv_args *args) 10119313Ssos{ 1012131796Sphk struct recvfrom_args /* { 101365108Smarcel int s; 101465108Smarcel caddr_t buf; 101565108Smarcel int len; 101665108Smarcel int flags; 1017131796Sphk struct sockaddr *from; 1018131796Sphk socklen_t fromlenaddr; 101965108Smarcel } */ bsd_args; 10209313Ssos 1021182890Skib bsd_args.s = args->s; 1022182890Skib bsd_args.buf = (caddr_t)PTRIN(args->msg); 1023182890Skib bsd_args.len = args->len; 1024191988Sdchagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 1025131796Sphk bsd_args.from = NULL; 1026131796Sphk bsd_args.fromlenaddr = 0; 1027225617Skmacy return (sys_recvfrom(td, &bsd_args)); 10289313Ssos} 1029293519Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 10309313Ssos 1031293519Sdchaginint 103283366Sjulianlinux_sendto(struct thread *td, struct linux_sendto_args *args) 10339313Ssos{ 1034122358Sdwmalone struct msghdr msg; 1035122358Sdwmalone struct iovec aiov; 10369313Ssos 1037182890Skib if (linux_check_hdrincl(td, args->s) == 0) 103865108Smarcel /* IP_HDRINCL set, tweak the packet before sending */ 1039182890Skib return (linux_sendto_hdrincl(td, args)); 104065108Smarcel 1041182890Skib msg.msg_name = PTRIN(args->to); 1042182890Skib msg.msg_namelen = args->tolen; 1043122358Sdwmalone msg.msg_iov = &aiov; 1044122358Sdwmalone msg.msg_iovlen = 1; 1045122358Sdwmalone msg.msg_control = NULL; 1046122358Sdwmalone msg.msg_flags = 0; 1047182890Skib aiov.iov_base = PTRIN(args->msg); 1048182890Skib aiov.iov_len = args->len; 1049297518Sdchagin return (linux_sendit(td, args->s, &msg, args->flags, NULL, 1050297518Sdchagin UIO_USERSPACE)); 10519313Ssos} 10529313Ssos 1053293519Sdchaginint 105483366Sjulianlinux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 10559313Ssos{ 1056293537Sdchagin struct msghdr msg; 1057293537Sdchagin struct iovec aiov; 1058302259Sdchagin int error, fromlen; 10599313Ssos 1060293537Sdchagin if (PTRIN(args->fromlen) != NULL) { 1061302259Sdchagin error = copyin(PTRIN(args->fromlen), &fromlen, 1062302259Sdchagin sizeof(fromlen)); 1063293537Sdchagin if (error != 0) 1064293537Sdchagin return (error); 1065302259Sdchagin if (fromlen < 0) 1066302259Sdchagin return (EINVAL); 1067302259Sdchagin msg.msg_namelen = fromlen; 1068293537Sdchagin } else 1069293537Sdchagin msg.msg_namelen = 0; 1070293537Sdchagin 1071293537Sdchagin msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from); 1072293537Sdchagin msg.msg_iov = &aiov; 1073293537Sdchagin msg.msg_iovlen = 1; 1074293537Sdchagin aiov.iov_base = PTRIN(args->buf); 1075293537Sdchagin aiov.iov_len = args->len; 1076293537Sdchagin msg.msg_control = 0; 1077293537Sdchagin msg.msg_flags = linux_to_bsd_msg_flags(args->flags); 1078293537Sdchagin 1079293537Sdchagin error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL); 1080293537Sdchagin if (error != 0) 108165108Smarcel return (error); 108265108Smarcel 1083293537Sdchagin if (PTRIN(args->from) != NULL) { 1084293537Sdchagin error = bsd_to_linux_sockaddr((struct sockaddr *) 1085293537Sdchagin PTRIN(args->from)); 1086293537Sdchagin if (error != 0) 1087293537Sdchagin return (error); 1088293537Sdchagin 1089133816Stjr error = linux_sa_put((struct osockaddr *) 1090182890Skib PTRIN(args->from)); 1091110295Sume } 1092293537Sdchagin 1093293537Sdchagin if (PTRIN(args->fromlen) != NULL) 1094293537Sdchagin error = copyout(&msg.msg_namelen, PTRIN(args->fromlen), 1095293537Sdchagin sizeof(msg.msg_namelen)); 1096293537Sdchagin 1097293537Sdchagin return (error); 10989313Ssos} 10999313Ssos 1100293588Sdchaginstatic int 1101293588Sdchaginlinux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1102293588Sdchagin l_uint flags) 1103110295Sume{ 1104185442Skib struct cmsghdr *cmsg; 1105220031Savg struct cmsgcred cmcred; 1106185442Skib struct mbuf *control; 1107110295Sume struct msghdr msg; 1108185442Skib struct l_cmsghdr linux_cmsg; 1109185442Skib struct l_cmsghdr *ptr_cmsg; 1110185442Skib struct l_msghdr linux_msg; 1111131897Sphk struct iovec *iov; 1112185442Skib socklen_t datalen; 1113220031Savg struct sockaddr *sa; 1114220031Savg sa_family_t sa_family; 1115185442Skib void *data; 1116110295Sume int error; 1117110295Sume 1118293588Sdchagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1119293588Sdchagin if (error != 0) 1120110295Sume return (error); 1121168711Srwatson 1122168711Srwatson /* 1123168711Srwatson * Some Linux applications (ping) define a non-NULL control data 1124168711Srwatson * pointer, but a msg_controllen of 0, which is not allowed in the 1125168711Srwatson * FreeBSD system call interface. NULL the msg_control pointer in 1126168711Srwatson * order to handle this case. This should be checked, but allows the 1127168711Srwatson * Linux ping to work. 1128168711Srwatson */ 1129220031Savg if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) 1130220031Savg linux_msg.msg_control = PTROUT(NULL); 1131185442Skib 1132220031Savg error = linux_to_bsd_msghdr(&msg, &linux_msg); 1133293588Sdchagin if (error != 0) 1134220031Savg return (error); 1135220031Savg 1136185442Skib#ifdef COMPAT_LINUX32 1137185442Skib error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1138185442Skib &iov, EMSGSIZE); 1139185442Skib#else 1140131897Sphk error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1141185442Skib#endif 1142293588Sdchagin if (error != 0) 1143131897Sphk return (error); 1144185442Skib 1145220031Savg control = NULL; 1146220031Savg cmsg = NULL; 1147220031Savg 1148220031Savg if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { 1149293588Sdchagin error = kern_getsockname(td, s, &sa, &datalen); 1150293588Sdchagin if (error != 0) 1151220031Savg goto bad; 1152220031Savg sa_family = sa->sa_family; 1153220031Savg free(sa, M_SONAME); 1154220031Savg 1155185442Skib error = ENOBUFS; 1156293588Sdchagin cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO); 1157243882Sglebius control = m_get(M_WAITOK, MT_CONTROL); 1158185442Skib 1159185442Skib do { 1160185442Skib error = copyin(ptr_cmsg, &linux_cmsg, 1161185442Skib sizeof(struct l_cmsghdr)); 1162293588Sdchagin if (error != 0) 1163185442Skib goto bad; 1164185442Skib 1165185442Skib error = EINVAL; 1166185442Skib if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) 1167185442Skib goto bad; 1168185442Skib 1169185442Skib /* 1170220031Savg * Now we support only SCM_RIGHTS and SCM_CRED, 1171220031Savg * so return EINVAL in any other cmsg_type 1172185442Skib */ 1173220031Savg cmsg->cmsg_type = 1174220031Savg linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); 1175185442Skib cmsg->cmsg_level = 1176185442Skib linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1177220031Savg if (cmsg->cmsg_type == -1 1178220031Savg || cmsg->cmsg_level != SOL_SOCKET) 1179220031Savg goto bad; 1180185442Skib 1181220031Savg /* 1182220031Savg * Some applications (e.g. pulseaudio) attempt to 1183220031Savg * send ancillary data even if the underlying protocol 1184220031Savg * doesn't support it which is not allowed in the 1185220031Savg * FreeBSD system call interface. 1186220031Savg */ 1187220031Savg if (sa_family != AF_UNIX) 1188220031Savg continue; 1189220031Savg 1190220031Savg data = LINUX_CMSG_DATA(ptr_cmsg); 1191185442Skib datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1192220031Savg 1193220031Savg switch (cmsg->cmsg_type) 1194220031Savg { 1195220031Savg case SCM_RIGHTS: 1196220031Savg break; 1197220031Savg 1198220031Savg case SCM_CREDS: 1199220031Savg data = &cmcred; 1200220031Savg datalen = sizeof(cmcred); 1201220031Savg 1202220031Savg /* 1203220031Savg * The lower levels will fill in the structure 1204220031Savg */ 1205220031Savg bzero(data, datalen); 1206220031Savg break; 1207220031Savg } 1208220031Savg 1209185442Skib cmsg->cmsg_len = CMSG_LEN(datalen); 1210185442Skib 1211185442Skib error = ENOBUFS; 1212226074Sjkim if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg)) 1213185442Skib goto bad; 1214226074Sjkim if (!m_append(control, datalen, (c_caddr_t)data)) 1215185442Skib goto bad; 1216220031Savg } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); 1217220031Savg 1218220031Savg if (m_length(control, NULL) == 0) { 1219220031Savg m_freem(control); 1220220031Savg control = NULL; 1221220031Savg } 1222185442Skib } 1223185442Skib 1224122358Sdwmalone msg.msg_iov = iov; 1225122358Sdwmalone msg.msg_flags = 0; 1226293588Sdchagin error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE); 1227294529Sdchagin control = NULL; 1228185442Skib 1229185442Skibbad: 1230293594Sdchagin m_freem(control); 1231131897Sphk free(iov, M_IOV); 1232185442Skib if (cmsg) 1233293532Sdchagin free(cmsg, M_LINUX); 1234122358Sdwmalone return (error); 1235110295Sume} 1236110295Sume 1237293519Sdchaginint 1238293588Sdchaginlinux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 123970178Sassar{ 1240293588Sdchagin 1241293588Sdchagin return (linux_sendmsg_common(td, args->s, PTRIN(args->msg), 1242293588Sdchagin args->flags)); 1243293588Sdchagin} 1244293588Sdchagin 1245293588Sdchaginint 1246293588Sdchaginlinux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args) 1247293588Sdchagin{ 1248293588Sdchagin struct l_mmsghdr *msg; 1249293588Sdchagin l_uint retval; 1250293588Sdchagin int error, datagrams; 1251293588Sdchagin 1252293588Sdchagin if (args->vlen > UIO_MAXIOV) 1253293588Sdchagin args->vlen = UIO_MAXIOV; 1254293588Sdchagin 1255293588Sdchagin msg = PTRIN(args->msg); 1256293588Sdchagin datagrams = 0; 1257293588Sdchagin while (datagrams < args->vlen) { 1258293588Sdchagin error = linux_sendmsg_common(td, args->s, &msg->msg_hdr, 1259293588Sdchagin args->flags); 1260293588Sdchagin if (error != 0) 1261293588Sdchagin break; 1262293588Sdchagin 1263293588Sdchagin retval = td->td_retval[0]; 1264293588Sdchagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1265293588Sdchagin if (error != 0) 1266293588Sdchagin break; 1267293588Sdchagin ++msg; 1268293588Sdchagin ++datagrams; 1269293588Sdchagin } 1270293588Sdchagin if (error == 0) 1271293588Sdchagin td->td_retval[0] = datagrams; 1272293588Sdchagin return (error); 1273293588Sdchagin} 1274293588Sdchagin 1275293588Sdchaginstatic int 1276293588Sdchaginlinux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr, 1277293588Sdchagin l_uint flags, struct msghdr *msg) 1278293588Sdchagin{ 1279185442Skib struct cmsghdr *cm; 1280220031Savg struct cmsgcred *cmcred; 1281185442Skib struct l_cmsghdr *linux_cmsg = NULL; 1282220031Savg struct l_ucred linux_ucred; 1283220031Savg socklen_t datalen, outlen; 1284185442Skib struct l_msghdr linux_msg; 1285185442Skib struct iovec *iov, *uiov; 1286185442Skib struct mbuf *control = NULL; 1287185442Skib struct mbuf **controlp; 1288293597Sdchagin struct timeval *ftmvl; 1289293597Sdchagin l_timeval ltmvl; 1290185442Skib caddr_t outbuf; 1291185442Skib void *data; 1292192284Sdchagin int error, i, fd, fds, *fdp; 129370178Sassar 1294293588Sdchagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg)); 1295293588Sdchagin if (error != 0) 1296185442Skib return (error); 1297133816Stjr 1298293588Sdchagin error = linux_to_bsd_msghdr(msg, &linux_msg); 1299293588Sdchagin if (error != 0) 1300166398Skib return (error); 1301166398Skib 1302185442Skib#ifdef COMPAT_LINUX32 1303293588Sdchagin error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen, 1304185442Skib &iov, EMSGSIZE); 1305185442Skib#else 1306293588Sdchagin error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE); 1307185442Skib#endif 1308293588Sdchagin if (error != 0) 1309110295Sume return (error); 1310110295Sume 1311293588Sdchagin if (msg->msg_name) { 1312293588Sdchagin error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name, 1313293588Sdchagin msg->msg_namelen); 1314293588Sdchagin if (error != 0) 1315185442Skib goto bad; 1316121008Siwasaki } 1317121008Siwasaki 1318293588Sdchagin uiov = msg->msg_iov; 1319293588Sdchagin msg->msg_iov = iov; 1320293588Sdchagin controlp = (msg->msg_control != NULL) ? &control : NULL; 1321293588Sdchagin error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp); 1322293588Sdchagin msg->msg_iov = uiov; 1323293588Sdchagin if (error != 0) 1324185442Skib goto bad; 1325185442Skib 1326293588Sdchagin error = bsd_to_linux_msghdr(msg, &linux_msg); 1327293588Sdchagin if (error != 0) 1328185442Skib goto bad; 1329185442Skib 1330185442Skib if (linux_msg.msg_name) { 1331185442Skib error = bsd_to_linux_sockaddr((struct sockaddr *) 1332185442Skib PTRIN(linux_msg.msg_name)); 1333293588Sdchagin if (error != 0) 1334185442Skib goto bad; 1335185442Skib } 1336185442Skib if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { 1337185442Skib error = linux_sa_put(PTRIN(linux_msg.msg_name)); 1338293588Sdchagin if (error != 0) 1339185442Skib goto bad; 1340185442Skib } 1341185442Skib 1342220031Savg outbuf = PTRIN(linux_msg.msg_control); 1343220031Savg outlen = 0; 1344220031Savg 1345185442Skib if (control) { 1346293532Sdchagin linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO); 1347185442Skib 1348293588Sdchagin msg->msg_control = mtod(control, struct cmsghdr *); 1349293588Sdchagin msg->msg_controllen = control->m_len; 1350220031Savg 1351293588Sdchagin cm = CMSG_FIRSTHDR(msg); 1352220031Savg 1353185442Skib while (cm != NULL) { 1354220031Savg linux_cmsg->cmsg_type = 1355220031Savg bsd_to_linux_cmsg_type(cm->cmsg_type); 1356220031Savg linux_cmsg->cmsg_level = 1357220031Savg bsd_to_linux_sockopt_level(cm->cmsg_level); 1358220031Savg if (linux_cmsg->cmsg_type == -1 1359220031Savg || cm->cmsg_level != SOL_SOCKET) 1360185442Skib { 1361185442Skib error = EINVAL; 1362185442Skib goto bad; 1363185442Skib } 1364220031Savg 1365185442Skib data = CMSG_DATA(cm); 1366185442Skib datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1367185442Skib 1368220031Savg switch (cm->cmsg_type) 1369192284Sdchagin { 1370220031Savg case SCM_RIGHTS: 1371293588Sdchagin if (flags & LINUX_MSG_CMSG_CLOEXEC) { 1372192284Sdchagin fds = datalen / sizeof(int); 1373192284Sdchagin fdp = data; 1374192284Sdchagin for (i = 0; i < fds; i++) { 1375192284Sdchagin fd = *fdp++; 1376192284Sdchagin (void)kern_fcntl(td, fd, 1377192284Sdchagin F_SETFD, FD_CLOEXEC); 1378192284Sdchagin } 1379192284Sdchagin } 1380192284Sdchagin break; 1381220031Savg 1382220031Savg case SCM_CREDS: 1383220031Savg /* 1384220031Savg * Currently LOCAL_CREDS is never in 1385220031Savg * effect for Linux so no need to worry 1386220031Savg * about sockcred 1387220031Savg */ 1388226074Sjkim if (datalen != sizeof(*cmcred)) { 1389220031Savg error = EMSGSIZE; 1390220031Savg goto bad; 1391220031Savg } 1392220031Savg cmcred = (struct cmsgcred *)data; 1393220031Savg bzero(&linux_ucred, sizeof(linux_ucred)); 1394220031Savg linux_ucred.pid = cmcred->cmcred_pid; 1395220031Savg linux_ucred.uid = cmcred->cmcred_uid; 1396220031Savg linux_ucred.gid = cmcred->cmcred_gid; 1397220031Savg data = &linux_ucred; 1398220031Savg datalen = sizeof(linux_ucred); 1399220031Savg break; 1400293597Sdchagin 1401293597Sdchagin case SCM_TIMESTAMP: 1402293597Sdchagin if (datalen != sizeof(struct timeval)) { 1403293597Sdchagin error = EMSGSIZE; 1404293597Sdchagin goto bad; 1405293597Sdchagin } 1406293597Sdchagin ftmvl = (struct timeval *)data; 1407293597Sdchagin ltmvl.tv_sec = ftmvl->tv_sec; 1408293597Sdchagin ltmvl.tv_usec = ftmvl->tv_usec; 1409293597Sdchagin data = <mvl; 1410293597Sdchagin datalen = sizeof(ltmvl); 1411293597Sdchagin break; 1412185442Skib } 1413185442Skib 1414220031Savg if (outlen + LINUX_CMSG_LEN(datalen) > 1415220031Savg linux_msg.msg_controllen) { 1416220031Savg if (outlen == 0) { 1417220031Savg error = EMSGSIZE; 1418220031Savg goto bad; 1419220031Savg } else { 1420220031Savg linux_msg.msg_flags |= 1421220031Savg LINUX_MSG_CTRUNC; 1422220031Savg goto out; 1423220031Savg } 1424220031Savg } 1425220031Savg 1426185442Skib linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 1427185442Skib 1428185442Skib error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1429185442Skib if (error) 1430185442Skib goto bad; 1431185442Skib outbuf += L_CMSG_HDRSZ; 1432185442Skib 1433185442Skib error = copyout(data, outbuf, datalen); 1434185442Skib if (error) 1435185442Skib goto bad; 1436185442Skib 1437185442Skib outbuf += LINUX_CMSG_ALIGN(datalen); 1438185442Skib outlen += LINUX_CMSG_LEN(datalen); 1439185442Skib 1440293588Sdchagin cm = CMSG_NXTHDR(msg, cm); 1441185442Skib } 1442185442Skib } 1443185442Skib 1444185442Skibout: 1445220031Savg linux_msg.msg_controllen = outlen; 1446293588Sdchagin error = copyout(&linux_msg, msghdr, sizeof(linux_msg)); 1447185442Skib 1448185442Skibbad: 1449185442Skib free(iov, M_IOV); 1450247764Seadler m_freem(control); 1451293532Sdchagin free(linux_cmsg, M_LINUX); 1452185442Skib 1453110295Sume return (error); 145470178Sassar} 145570178Sassar 1456293519Sdchaginint 1457293588Sdchaginlinux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 1458293588Sdchagin{ 1459293588Sdchagin struct msghdr bsd_msg; 1460293588Sdchagin 1461293588Sdchagin return (linux_recvmsg_common(td, args->s, PTRIN(args->msg), 1462293588Sdchagin args->flags, &bsd_msg)); 1463293588Sdchagin} 1464293588Sdchagin 1465293588Sdchaginint 1466293588Sdchaginlinux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args) 1467293588Sdchagin{ 1468293588Sdchagin struct l_mmsghdr *msg; 1469293588Sdchagin struct msghdr bsd_msg; 1470293588Sdchagin struct l_timespec lts; 1471293588Sdchagin struct timespec ts, tts; 1472293588Sdchagin l_uint retval; 1473293588Sdchagin int error, datagrams; 1474293588Sdchagin 1475293588Sdchagin if (args->timeout) { 1476293588Sdchagin error = copyin(args->timeout, <s, sizeof(struct l_timespec)); 1477293588Sdchagin if (error != 0) 1478293588Sdchagin return (error); 1479293588Sdchagin error = linux_to_native_timespec(&ts, <s); 1480293588Sdchagin if (error != 0) 1481293588Sdchagin return (error); 1482293588Sdchagin getnanotime(&tts); 1483293588Sdchagin timespecadd(&tts, &ts); 1484293588Sdchagin } 1485293588Sdchagin 1486293588Sdchagin msg = PTRIN(args->msg); 1487293588Sdchagin datagrams = 0; 1488293588Sdchagin while (datagrams < args->vlen) { 1489293588Sdchagin error = linux_recvmsg_common(td, args->s, &msg->msg_hdr, 1490293588Sdchagin args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg); 1491293588Sdchagin if (error != 0) 1492293588Sdchagin break; 1493293588Sdchagin 1494293588Sdchagin retval = td->td_retval[0]; 1495293588Sdchagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len)); 1496293588Sdchagin if (error != 0) 1497293588Sdchagin break; 1498293588Sdchagin ++msg; 1499293588Sdchagin ++datagrams; 1500293588Sdchagin 1501293588Sdchagin /* 1502293588Sdchagin * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet. 1503293588Sdchagin */ 1504293588Sdchagin if (args->flags & LINUX_MSG_WAITFORONE) 1505293588Sdchagin args->flags |= LINUX_MSG_DONTWAIT; 1506293588Sdchagin 1507293588Sdchagin /* 1508293588Sdchagin * See BUGS section of recvmmsg(2). 1509293588Sdchagin */ 1510293588Sdchagin if (args->timeout) { 1511293588Sdchagin getnanotime(&ts); 1512293588Sdchagin timespecsub(&ts, &tts); 1513293588Sdchagin if (!timespecisset(&ts) || ts.tv_sec > 0) 1514293588Sdchagin break; 1515293588Sdchagin } 1516293588Sdchagin /* Out of band data, return right away. */ 1517293588Sdchagin if (bsd_msg.msg_flags & MSG_OOB) 1518293588Sdchagin break; 1519293588Sdchagin } 1520293588Sdchagin if (error == 0) 1521293588Sdchagin td->td_retval[0] = datagrams; 1522293588Sdchagin return (error); 1523293588Sdchagin} 1524293588Sdchagin 1525293588Sdchaginint 152683366Sjulianlinux_shutdown(struct thread *td, struct linux_shutdown_args *args) 15279313Ssos{ 152865108Smarcel struct shutdown_args /* { 152965108Smarcel int s; 153065108Smarcel int how; 153165108Smarcel } */ bsd_args; 15329313Ssos 1533182890Skib bsd_args.s = args->s; 1534182890Skib bsd_args.how = args->how; 1535225617Skmacy return (sys_shutdown(td, &bsd_args)); 15369313Ssos} 15379313Ssos 1538293519Sdchaginint 153983366Sjulianlinux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 15409313Ssos{ 154165108Smarcel struct setsockopt_args /* { 154265108Smarcel int s; 154365108Smarcel int level; 154465108Smarcel int name; 154565108Smarcel caddr_t val; 154665108Smarcel int valsize; 154765108Smarcel } */ bsd_args; 1548191989Sdchagin l_timeval linux_tv; 1549191989Sdchagin struct timeval tv; 155065108Smarcel int error, name; 15519313Ssos 1552182890Skib bsd_args.s = args->s; 1553182890Skib bsd_args.level = linux_to_bsd_sockopt_level(args->level); 155465108Smarcel switch (bsd_args.level) { 155565108Smarcel case SOL_SOCKET: 1556182890Skib name = linux_to_bsd_so_sockopt(args->optname); 1557191989Sdchagin switch (name) { 1558191989Sdchagin case SO_RCVTIMEO: 1559191989Sdchagin /* FALLTHROUGH */ 1560191989Sdchagin case SO_SNDTIMEO: 1561191989Sdchagin error = copyin(PTRIN(args->optval), &linux_tv, 1562191989Sdchagin sizeof(linux_tv)); 1563191989Sdchagin if (error) 1564191989Sdchagin return (error); 1565191989Sdchagin tv.tv_sec = linux_tv.tv_sec; 1566191989Sdchagin tv.tv_usec = linux_tv.tv_usec; 1567191989Sdchagin return (kern_setsockopt(td, args->s, bsd_args.level, 1568191989Sdchagin name, &tv, UIO_SYSSPACE, sizeof(tv))); 1569191989Sdchagin /* NOTREACHED */ 1570191989Sdchagin break; 1571191989Sdchagin default: 1572191989Sdchagin break; 1573191989Sdchagin } 157465108Smarcel break; 157565108Smarcel case IPPROTO_IP: 1576182890Skib name = linux_to_bsd_ip_sockopt(args->optname); 157765108Smarcel break; 1578297211Sae case IPPROTO_IPV6: 1579297211Sae name = linux_to_bsd_ip6_sockopt(args->optname); 1580297211Sae break; 158165108Smarcel case IPPROTO_TCP: 1582245849Sjhb name = linux_to_bsd_tcp_sockopt(args->optname); 158365108Smarcel break; 158465108Smarcel default: 158565108Smarcel name = -1; 158665108Smarcel break; 158765108Smarcel } 158865108Smarcel if (name == -1) 1589162585Snetchild return (ENOPROTOOPT); 159065108Smarcel 159165108Smarcel bsd_args.name = name; 1592182890Skib bsd_args.val = PTRIN(args->optval); 1593182890Skib bsd_args.valsize = args->optlen; 1594156842Snetchild 1595156842Snetchild if (name == IPV6_NEXTHOP) { 1596156842Snetchild linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, 1597156842Snetchild bsd_args.valsize); 1598225617Skmacy error = sys_setsockopt(td, &bsd_args); 1599156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1600156842Snetchild } else 1601225617Skmacy error = sys_setsockopt(td, &bsd_args); 1602156842Snetchild 1603156842Snetchild return (error); 16049313Ssos} 16059313Ssos 1606293519Sdchaginint 160783366Sjulianlinux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 16089313Ssos{ 160965108Smarcel struct getsockopt_args /* { 161065108Smarcel int s; 161165108Smarcel int level; 161265108Smarcel int name; 161365108Smarcel caddr_t val; 161465108Smarcel int *avalsize; 161565108Smarcel } */ bsd_args; 1616191989Sdchagin l_timeval linux_tv; 1617191989Sdchagin struct timeval tv; 1618301429Sdchagin socklen_t tv_len, xulen, len; 1619192203Sdchagin struct xucred xu; 1620192203Sdchagin struct l_ucred lxu; 1621301429Sdchagin int error, name, newval; 16229313Ssos 1623182890Skib bsd_args.s = args->s; 1624182890Skib bsd_args.level = linux_to_bsd_sockopt_level(args->level); 162565108Smarcel switch (bsd_args.level) { 162665108Smarcel case SOL_SOCKET: 1627182890Skib name = linux_to_bsd_so_sockopt(args->optname); 1628191989Sdchagin switch (name) { 1629191989Sdchagin case SO_RCVTIMEO: 1630191989Sdchagin /* FALLTHROUGH */ 1631191989Sdchagin case SO_SNDTIMEO: 1632191989Sdchagin tv_len = sizeof(tv); 1633191989Sdchagin error = kern_getsockopt(td, args->s, bsd_args.level, 1634191989Sdchagin name, &tv, UIO_SYSSPACE, &tv_len); 1635191989Sdchagin if (error) 1636191989Sdchagin return (error); 1637191989Sdchagin linux_tv.tv_sec = tv.tv_sec; 1638191989Sdchagin linux_tv.tv_usec = tv.tv_usec; 1639191989Sdchagin return (copyout(&linux_tv, PTRIN(args->optval), 1640191989Sdchagin sizeof(linux_tv))); 1641191989Sdchagin /* NOTREACHED */ 1642191989Sdchagin break; 1643192203Sdchagin case LOCAL_PEERCRED: 1644192203Sdchagin if (args->optlen != sizeof(lxu)) 1645192203Sdchagin return (EINVAL); 1646192203Sdchagin xulen = sizeof(xu); 1647192203Sdchagin error = kern_getsockopt(td, args->s, bsd_args.level, 1648192203Sdchagin name, &xu, UIO_SYSSPACE, &xulen); 1649192203Sdchagin if (error) 1650192203Sdchagin return (error); 1651192203Sdchagin /* 1652192203Sdchagin * XXX Use 0 for pid as the FreeBSD does not cache peer pid. 1653192203Sdchagin */ 1654192203Sdchagin lxu.pid = 0; 1655192203Sdchagin lxu.uid = xu.cr_uid; 1656192203Sdchagin lxu.gid = xu.cr_gid; 1657192203Sdchagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1658192203Sdchagin /* NOTREACHED */ 1659192203Sdchagin break; 1660301429Sdchagin case SO_ERROR: 1661301429Sdchagin len = sizeof(newval); 1662301429Sdchagin error = kern_getsockopt(td, args->s, bsd_args.level, 1663301429Sdchagin name, &newval, UIO_SYSSPACE, &len); 1664301429Sdchagin if (error) 1665301429Sdchagin return (error); 1666301429Sdchagin newval = -SV_ABI_ERRNO(td->td_proc, newval); 1667301429Sdchagin return (copyout(&newval, PTRIN(args->optval), len)); 1668301429Sdchagin /* NOTREACHED */ 1669191989Sdchagin default: 1670191989Sdchagin break; 1671191989Sdchagin } 167265108Smarcel break; 167365108Smarcel case IPPROTO_IP: 1674182890Skib name = linux_to_bsd_ip_sockopt(args->optname); 167565108Smarcel break; 1676297211Sae case IPPROTO_IPV6: 1677297211Sae name = linux_to_bsd_ip6_sockopt(args->optname); 1678297211Sae break; 167965108Smarcel case IPPROTO_TCP: 1680245849Sjhb name = linux_to_bsd_tcp_sockopt(args->optname); 168165108Smarcel break; 168265108Smarcel default: 168365108Smarcel name = -1; 168465108Smarcel break; 168565108Smarcel } 168665108Smarcel if (name == -1) 168765108Smarcel return (EINVAL); 168865108Smarcel 168965108Smarcel bsd_args.name = name; 1690182890Skib bsd_args.val = PTRIN(args->optval); 1691182890Skib bsd_args.avalsize = PTRIN(args->optlen); 1692156842Snetchild 1693156842Snetchild if (name == IPV6_NEXTHOP) { 1694225617Skmacy error = sys_getsockopt(td, &bsd_args); 1695156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1696156842Snetchild } else 1697225617Skmacy error = sys_getsockopt(td, &bsd_args); 1698156842Snetchild 1699156842Snetchild return (error); 17009313Ssos} 17019313Ssos 1702293521Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1703293521Sdchagin 1704192373Sdchagin/* Argument list sizes for linux_socketcall */ 1705192373Sdchagin 1706192373Sdchagin#define LINUX_AL(x) ((x) * sizeof(l_ulong)) 1707192373Sdchagin 1708192373Sdchaginstatic const unsigned char lxs_args[] = { 1709192373Sdchagin LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, 1710192373Sdchagin LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, 1711192373Sdchagin LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, 1712192373Sdchagin LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, 1713192373Sdchagin LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, 1714192373Sdchagin LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, 1715192373Sdchagin LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, 1716192373Sdchagin LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, 1717193264Sdchagin LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */, 1718293588Sdchagin LINUX_AL(4) /* accept4 */, LINUX_AL(5) /* recvmmsg */, 1719293588Sdchagin LINUX_AL(4) /* sendmmsg */ 1720192373Sdchagin}; 1721192373Sdchagin 1722192373Sdchagin#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 1723192373Sdchagin 17249313Ssosint 172583366Sjulianlinux_socketcall(struct thread *td, struct linux_socketcall_args *args) 17269313Ssos{ 1727192373Sdchagin l_ulong a[6]; 1728192373Sdchagin void *arg; 1729192373Sdchagin int error; 173042509Smsmith 1731192373Sdchagin if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) 1732192373Sdchagin return (EINVAL); 1733192373Sdchagin error = copyin(PTRIN(args->args), a, lxs_args[args->what]); 1734192373Sdchagin if (error) 1735192373Sdchagin return (error); 1736192373Sdchagin 1737192373Sdchagin arg = a; 173865108Smarcel switch (args->what) { 173965108Smarcel case LINUX_SOCKET: 174083366Sjulian return (linux_socket(td, arg)); 174165108Smarcel case LINUX_BIND: 174283366Sjulian return (linux_bind(td, arg)); 174365108Smarcel case LINUX_CONNECT: 174483366Sjulian return (linux_connect(td, arg)); 174565108Smarcel case LINUX_LISTEN: 174683366Sjulian return (linux_listen(td, arg)); 174765108Smarcel case LINUX_ACCEPT: 174883366Sjulian return (linux_accept(td, arg)); 174965108Smarcel case LINUX_GETSOCKNAME: 175083366Sjulian return (linux_getsockname(td, arg)); 175165108Smarcel case LINUX_GETPEERNAME: 175283366Sjulian return (linux_getpeername(td, arg)); 175365108Smarcel case LINUX_SOCKETPAIR: 175483366Sjulian return (linux_socketpair(td, arg)); 175565108Smarcel case LINUX_SEND: 175683366Sjulian return (linux_send(td, arg)); 175765108Smarcel case LINUX_RECV: 175883366Sjulian return (linux_recv(td, arg)); 175965108Smarcel case LINUX_SENDTO: 176083366Sjulian return (linux_sendto(td, arg)); 176165108Smarcel case LINUX_RECVFROM: 176283366Sjulian return (linux_recvfrom(td, arg)); 176365108Smarcel case LINUX_SHUTDOWN: 176483366Sjulian return (linux_shutdown(td, arg)); 176565108Smarcel case LINUX_SETSOCKOPT: 176683366Sjulian return (linux_setsockopt(td, arg)); 176765108Smarcel case LINUX_GETSOCKOPT: 176883366Sjulian return (linux_getsockopt(td, arg)); 176965108Smarcel case LINUX_SENDMSG: 1770110295Sume return (linux_sendmsg(td, arg)); 177165108Smarcel case LINUX_RECVMSG: 177283366Sjulian return (linux_recvmsg(td, arg)); 1773193264Sdchagin case LINUX_ACCEPT4: 1774193264Sdchagin return (linux_accept4(td, arg)); 1775293588Sdchagin case LINUX_RECVMMSG: 1776293588Sdchagin return (linux_recvmmsg(td, arg)); 1777293588Sdchagin case LINUX_SENDMMSG: 1778293588Sdchagin return (linux_sendmmsg(td, arg)); 177965108Smarcel } 178065108Smarcel 17819313Ssos uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 178265108Smarcel return (ENOSYS); 17839313Ssos} 1784293519Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1785