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$"); 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> 40224778Srwatson#include <sys/capability.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 7370178Sassar#include <compat/linux/linux_socket.h> 7464913Smarcel#include <compat/linux/linux_util.h> 759313Ssos 76110295Sumestatic int linux_to_bsd_domain(int); 77110295Sume 7885569Sfenner/* 79110295Sume * Reads a linux sockaddr and does any necessary translation. 80110295Sume * Linux sockaddrs don't have a length field, only a family. 81110295Sume * Copy the osockaddr structure pointed to by osa to kernel, adjust 82110295Sume * family and convert to sockaddr. 83110295Sume */ 84110295Sumestatic int 85226078Sjkimlinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen) 86110295Sume{ 87110295Sume struct sockaddr *sa; 88110295Sume struct osockaddr *kosa; 89110295Sume#ifdef INET6 90226074Sjkim struct sockaddr_in6 *sin6; 91110295Sume int oldv6size; 92110295Sume#endif 93226073Sjkim char *name; 94226078Sjkim int bdom, error, hdrlen, namelen; 95110295Sume 96226078Sjkim if (salen < 2 || salen > UCHAR_MAX || !osa) 97110295Sume return (EINVAL); 98110295Sume 99110295Sume#ifdef INET6 100110295Sume oldv6size = 0; 101110295Sume /* 102110295Sume * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 103110295Sume * if it's a v4-mapped address, so reserve the proper space 104110295Sume * for it. 105110295Sume */ 106226078Sjkim if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) { 107226078Sjkim salen += sizeof(uint32_t); 108110295Sume oldv6size = 1; 10985569Sfenner } 110110295Sume#endif 111110295Sume 112226078Sjkim kosa = malloc(salen, M_SONAME, M_WAITOK); 113110295Sume 114226078Sjkim if ((error = copyin(osa, kosa, salen))) 115110295Sume goto out; 116110295Sume 117110295Sume bdom = linux_to_bsd_domain(kosa->sa_family); 118110295Sume if (bdom == -1) { 119203728Sdelphij error = EAFNOSUPPORT; 120110295Sume goto out; 121110295Sume } 122110295Sume 123110295Sume#ifdef INET6 124110295Sume /* 125110295Sume * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 126110295Sume * which lacks the scope id compared with RFC2553 one. If we detect 127110295Sume * the situation, reject the address and write a message to system log. 128110295Sume * 129110295Sume * Still accept addresses for which the scope id is not used. 130110295Sume */ 131226072Sjkim if (oldv6size) { 132226072Sjkim if (bdom == AF_INET6) { 133226072Sjkim sin6 = (struct sockaddr_in6 *)kosa; 134226072Sjkim if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 135226072Sjkim (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 136226072Sjkim !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 137226072Sjkim !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 138226072Sjkim !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 139226072Sjkim !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 140226072Sjkim sin6->sin6_scope_id = 0; 141226072Sjkim } else { 142226072Sjkim log(LOG_DEBUG, 143226072Sjkim "obsolete pre-RFC2553 sockaddr_in6 rejected\n"); 144226072Sjkim error = EINVAL; 145226072Sjkim goto out; 146226072Sjkim } 147226072Sjkim } else 148226078Sjkim salen -= sizeof(uint32_t); 149226072Sjkim } 150110295Sume#endif 151203728Sdelphij if (bdom == AF_INET) { 152226078Sjkim if (salen < sizeof(struct sockaddr_in)) { 153203728Sdelphij error = EINVAL; 154203728Sdelphij goto out; 155203728Sdelphij } 156226078Sjkim salen = sizeof(struct sockaddr_in); 157203728Sdelphij } 158110295Sume 159226078Sjkim if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) { 160226068Sjkim hdrlen = offsetof(struct sockaddr_un, sun_path); 161226073Sjkim name = ((struct sockaddr_un *)kosa)->sun_path; 162226073Sjkim if (*name == '\0') { 163226073Sjkim /* 164226073Sjkim * Linux abstract namespace starts with a NULL byte. 165226073Sjkim * XXX We do not support abstract namespace yet. 166226073Sjkim */ 167226078Sjkim namelen = strnlen(name + 1, salen - hdrlen - 1) + 1; 168226073Sjkim } else 169226078Sjkim namelen = strnlen(name, salen - hdrlen); 170226079Sjkim salen = hdrlen + namelen; 171226079Sjkim if (salen > sizeof(struct sockaddr_un)) { 172226071Sjkim error = ENAMETOOLONG; 173226023Scperciva goto out; 174226023Scperciva } 175226023Scperciva } 176226023Scperciva 177226074Sjkim sa = (struct sockaddr *)kosa; 178110295Sume sa->sa_family = bdom; 179226078Sjkim sa->sa_len = salen; 180110295Sume 181110295Sume *sap = sa; 182110295Sume return (0); 183110295Sume 184110295Sumeout: 185226069Sjkim free(kosa, M_SONAME); 186110295Sume return (error); 18785569Sfenner} 18885569Sfenner 1899313Ssosstatic int 1909313Ssoslinux_to_bsd_domain(int domain) 1919313Ssos{ 19265108Smarcel 19365108Smarcel switch (domain) { 19465108Smarcel case LINUX_AF_UNSPEC: 19565108Smarcel return (AF_UNSPEC); 19665108Smarcel case LINUX_AF_UNIX: 19765108Smarcel return (AF_LOCAL); 19865108Smarcel case LINUX_AF_INET: 19965108Smarcel return (AF_INET); 200110295Sume case LINUX_AF_INET6: 201110295Sume return (AF_INET6); 20265108Smarcel case LINUX_AF_AX25: 20365108Smarcel return (AF_CCITT); 20465108Smarcel case LINUX_AF_IPX: 20565108Smarcel return (AF_IPX); 20665108Smarcel case LINUX_AF_APPLETALK: 20765108Smarcel return (AF_APPLETALK); 20865108Smarcel } 20965108Smarcel return (-1); 2109313Ssos} 2119313Ssos 2129313Ssosstatic int 213110295Sumebsd_to_linux_domain(int domain) 214110295Sume{ 215110295Sume 216110295Sume switch (domain) { 217110295Sume case AF_UNSPEC: 218110295Sume return (LINUX_AF_UNSPEC); 219110295Sume case AF_LOCAL: 220110295Sume return (LINUX_AF_UNIX); 221110295Sume case AF_INET: 222110295Sume return (LINUX_AF_INET); 223110295Sume case AF_INET6: 224110295Sume return (LINUX_AF_INET6); 225110295Sume case AF_CCITT: 226110295Sume return (LINUX_AF_AX25); 227110295Sume case AF_IPX: 228110295Sume return (LINUX_AF_IPX); 229110295Sume case AF_APPLETALK: 230110295Sume return (LINUX_AF_APPLETALK); 231110295Sume } 232110295Sume return (-1); 233110295Sume} 234110295Sume 235110295Sumestatic int 2369313Ssoslinux_to_bsd_sockopt_level(int level) 2379313Ssos{ 23865108Smarcel 23965108Smarcel switch (level) { 24065108Smarcel case LINUX_SOL_SOCKET: 24165108Smarcel return (SOL_SOCKET); 24265108Smarcel } 24365108Smarcel return (level); 2449313Ssos} 2459313Ssos 24665108Smarcelstatic int 247121008Siwasakibsd_to_linux_sockopt_level(int level) 248121008Siwasaki{ 249121008Siwasaki 250121008Siwasaki switch (level) { 251121008Siwasaki case SOL_SOCKET: 252121008Siwasaki return (LINUX_SOL_SOCKET); 253121008Siwasaki } 254121008Siwasaki return (level); 255121008Siwasaki} 256121008Siwasaki 257121008Siwasakistatic int 25865108Smarcellinux_to_bsd_ip_sockopt(int opt) 2599313Ssos{ 26065108Smarcel 26165108Smarcel switch (opt) { 26265108Smarcel case LINUX_IP_TOS: 26365108Smarcel return (IP_TOS); 26465108Smarcel case LINUX_IP_TTL: 26565108Smarcel return (IP_TTL); 26665108Smarcel case LINUX_IP_OPTIONS: 26765108Smarcel return (IP_OPTIONS); 26865108Smarcel case LINUX_IP_MULTICAST_IF: 26965108Smarcel return (IP_MULTICAST_IF); 27065108Smarcel case LINUX_IP_MULTICAST_TTL: 27165108Smarcel return (IP_MULTICAST_TTL); 27265108Smarcel case LINUX_IP_MULTICAST_LOOP: 27365108Smarcel return (IP_MULTICAST_LOOP); 27465108Smarcel case LINUX_IP_ADD_MEMBERSHIP: 27565108Smarcel return (IP_ADD_MEMBERSHIP); 27665108Smarcel case LINUX_IP_DROP_MEMBERSHIP: 27765108Smarcel return (IP_DROP_MEMBERSHIP); 27865108Smarcel case LINUX_IP_HDRINCL: 27965108Smarcel return (IP_HDRINCL); 28065108Smarcel } 28165108Smarcel return (-1); 2829313Ssos} 2839313Ssos 2849313Ssosstatic int 2859313Ssoslinux_to_bsd_so_sockopt(int opt) 2869313Ssos{ 28765108Smarcel 28865108Smarcel switch (opt) { 28965108Smarcel case LINUX_SO_DEBUG: 29065108Smarcel return (SO_DEBUG); 29165108Smarcel case LINUX_SO_REUSEADDR: 29265108Smarcel return (SO_REUSEADDR); 29365108Smarcel case LINUX_SO_TYPE: 29465108Smarcel return (SO_TYPE); 29565108Smarcel case LINUX_SO_ERROR: 29665108Smarcel return (SO_ERROR); 29765108Smarcel case LINUX_SO_DONTROUTE: 29865108Smarcel return (SO_DONTROUTE); 29965108Smarcel case LINUX_SO_BROADCAST: 30065108Smarcel return (SO_BROADCAST); 30165108Smarcel case LINUX_SO_SNDBUF: 30265108Smarcel return (SO_SNDBUF); 30365108Smarcel case LINUX_SO_RCVBUF: 30465108Smarcel return (SO_RCVBUF); 30565108Smarcel case LINUX_SO_KEEPALIVE: 30665108Smarcel return (SO_KEEPALIVE); 30765108Smarcel case LINUX_SO_OOBINLINE: 30865108Smarcel return (SO_OOBINLINE); 30965108Smarcel case LINUX_SO_LINGER: 31065108Smarcel return (SO_LINGER); 311166398Skib case LINUX_SO_PEERCRED: 312166398Skib return (LOCAL_PEERCRED); 313166398Skib case LINUX_SO_RCVLOWAT: 314166398Skib return (SO_RCVLOWAT); 315166398Skib case LINUX_SO_SNDLOWAT: 316166398Skib return (SO_SNDLOWAT); 317166398Skib case LINUX_SO_RCVTIMEO: 318166398Skib return (SO_RCVTIMEO); 319166398Skib case LINUX_SO_SNDTIMEO: 320166398Skib return (SO_SNDTIMEO); 321166398Skib case LINUX_SO_TIMESTAMP: 322166398Skib return (SO_TIMESTAMP); 323166398Skib case LINUX_SO_ACCEPTCONN: 324166398Skib return (SO_ACCEPTCONN); 32565108Smarcel } 32665108Smarcel return (-1); 3279313Ssos} 3289313Ssos 32970178Sassarstatic int 330245849Sjhblinux_to_bsd_tcp_sockopt(int opt) 331245849Sjhb{ 332245849Sjhb 333245849Sjhb switch (opt) { 334245849Sjhb case LINUX_TCP_NODELAY: 335245849Sjhb return (TCP_NODELAY); 336245849Sjhb case LINUX_TCP_MAXSEG: 337245849Sjhb return (TCP_MAXSEG); 338245849Sjhb case LINUX_TCP_KEEPIDLE: 339245849Sjhb return (TCP_KEEPIDLE); 340245849Sjhb case LINUX_TCP_KEEPINTVL: 341245849Sjhb return (TCP_KEEPINTVL); 342245849Sjhb case LINUX_TCP_KEEPCNT: 343245849Sjhb return (TCP_KEEPCNT); 344245849Sjhb case LINUX_TCP_MD5SIG: 345245849Sjhb return (TCP_MD5SIG); 346245849Sjhb } 347245849Sjhb return (-1); 348245849Sjhb} 349245849Sjhb 350245849Sjhbstatic int 35170178Sassarlinux_to_bsd_msg_flags(int flags) 35270178Sassar{ 35370178Sassar int ret_flags = 0; 35470178Sassar 35570178Sassar if (flags & LINUX_MSG_OOB) 35670178Sassar ret_flags |= MSG_OOB; 35770178Sassar if (flags & LINUX_MSG_PEEK) 35870178Sassar ret_flags |= MSG_PEEK; 35970178Sassar if (flags & LINUX_MSG_DONTROUTE) 36070178Sassar ret_flags |= MSG_DONTROUTE; 36170178Sassar if (flags & LINUX_MSG_CTRUNC) 36270178Sassar ret_flags |= MSG_CTRUNC; 36370178Sassar if (flags & LINUX_MSG_TRUNC) 36470178Sassar ret_flags |= MSG_TRUNC; 36570178Sassar if (flags & LINUX_MSG_DONTWAIT) 36670178Sassar ret_flags |= MSG_DONTWAIT; 36770178Sassar if (flags & LINUX_MSG_EOR) 36870178Sassar ret_flags |= MSG_EOR; 36970178Sassar if (flags & LINUX_MSG_WAITALL) 37070178Sassar ret_flags |= MSG_WAITALL; 371143295Ssobomax if (flags & LINUX_MSG_NOSIGNAL) 372143295Ssobomax ret_flags |= MSG_NOSIGNAL; 37370178Sassar#if 0 /* not handled */ 37470178Sassar if (flags & LINUX_MSG_PROXY) 37570178Sassar ; 37670178Sassar if (flags & LINUX_MSG_FIN) 37770178Sassar ; 37870178Sassar if (flags & LINUX_MSG_SYN) 37970178Sassar ; 38070178Sassar if (flags & LINUX_MSG_CONFIRM) 38170178Sassar ; 38270178Sassar if (flags & LINUX_MSG_RST) 38370178Sassar ; 38470178Sassar if (flags & LINUX_MSG_ERRQUEUE) 38570178Sassar ; 38670178Sassar#endif 38770178Sassar return ret_flags; 38870178Sassar} 38970178Sassar 390156842Snetchild/* 391156842Snetchild* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the 392156842Snetchild* native syscall will fault. Thus, we don't really need to check the 393156842Snetchild* return values for these functions. 394156842Snetchild*/ 395156842Snetchild 396110295Sumestatic int 397156842Snetchildbsd_to_linux_sockaddr(struct sockaddr *arg) 398156842Snetchild{ 399156842Snetchild struct sockaddr sa; 400156842Snetchild size_t sa_len = sizeof(struct sockaddr); 401156842Snetchild int error; 402156842Snetchild 403156842Snetchild if ((error = copyin(arg, &sa, sa_len))) 404156842Snetchild return (error); 405156842Snetchild 406156842Snetchild *(u_short *)&sa = sa.sa_family; 407156842Snetchild 408156842Snetchild error = copyout(&sa, arg, sa_len); 409156842Snetchild 410156842Snetchild return (error); 411156842Snetchild} 412156842Snetchild 413156842Snetchildstatic int 414156842Snetchildlinux_to_bsd_sockaddr(struct sockaddr *arg, int len) 415156842Snetchild{ 416156842Snetchild struct sockaddr sa; 417156842Snetchild size_t sa_len = sizeof(struct sockaddr); 418156842Snetchild int error; 419156842Snetchild 420156842Snetchild if ((error = copyin(arg, &sa, sa_len))) 421156842Snetchild return (error); 422156842Snetchild 423156842Snetchild sa.sa_family = *(sa_family_t *)&sa; 424156842Snetchild sa.sa_len = len; 425156842Snetchild 426156842Snetchild error = copyout(&sa, arg, sa_len); 427156842Snetchild 428156842Snetchild return (error); 429156842Snetchild} 430156842Snetchild 431156842Snetchild 432156842Snetchildstatic int 433110295Sumelinux_sa_put(struct osockaddr *osa) 434110295Sume{ 435110295Sume struct osockaddr sa; 436110295Sume int error, bdom; 437110295Sume 438110295Sume /* 439110295Sume * Only read/write the osockaddr family part, the rest is 440110295Sume * not changed. 441110295Sume */ 442111797Sdes error = copyin(osa, &sa, sizeof(sa.sa_family)); 443110295Sume if (error) 444110295Sume return (error); 445110295Sume 446110295Sume bdom = bsd_to_linux_domain(sa.sa_family); 447110295Sume if (bdom == -1) 448110295Sume return (EINVAL); 449110295Sume 450110295Sume sa.sa_family = bdom; 451110295Sume error = copyout(&sa, osa, sizeof(sa.sa_family)); 452110295Sume if (error) 453110295Sume return (error); 454110295Sume 455110295Sume return (0); 456110295Sume} 457110295Sume 458122358Sdwmalonestatic int 459185442Skiblinux_to_bsd_cmsg_type(int cmsg_type) 460185442Skib{ 461185442Skib 462185442Skib switch (cmsg_type) { 463185442Skib case LINUX_SCM_RIGHTS: 464185442Skib return (SCM_RIGHTS); 465220031Savg case LINUX_SCM_CREDENTIALS: 466220031Savg return (SCM_CREDS); 467185442Skib } 468185442Skib return (-1); 469185442Skib} 470185442Skib 471185442Skibstatic int 472185442Skibbsd_to_linux_cmsg_type(int cmsg_type) 473185442Skib{ 474185442Skib 475185442Skib switch (cmsg_type) { 476185442Skib case SCM_RIGHTS: 477185442Skib return (LINUX_SCM_RIGHTS); 478220031Savg case SCM_CREDS: 479220031Savg return (LINUX_SCM_CREDENTIALS); 480185442Skib } 481185442Skib return (-1); 482185442Skib} 483185442Skib 484185442Skibstatic int 485185442Skiblinux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr) 486185442Skib{ 487185442Skib if (lhdr->msg_controllen > INT_MAX) 488185442Skib return (ENOBUFS); 489185442Skib 490185442Skib bhdr->msg_name = PTRIN(lhdr->msg_name); 491185442Skib bhdr->msg_namelen = lhdr->msg_namelen; 492185442Skib bhdr->msg_iov = PTRIN(lhdr->msg_iov); 493185442Skib bhdr->msg_iovlen = lhdr->msg_iovlen; 494185442Skib bhdr->msg_control = PTRIN(lhdr->msg_control); 495220031Savg 496220031Savg /* 497220031Savg * msg_controllen is skipped since BSD and LINUX control messages 498220031Savg * are potentially different sizes (e.g. the cred structure used 499220031Savg * by SCM_CREDS is different between the two operating system). 500220031Savg * 501220031Savg * The caller can set it (if necessary) after converting all the 502220031Savg * control messages. 503220031Savg */ 504220031Savg 505185442Skib bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags); 506185442Skib return (0); 507185442Skib} 508185442Skib 509185442Skibstatic int 510185442Skibbsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr) 511185442Skib{ 512185442Skib lhdr->msg_name = PTROUT(bhdr->msg_name); 513185442Skib lhdr->msg_namelen = bhdr->msg_namelen; 514185442Skib lhdr->msg_iov = PTROUT(bhdr->msg_iov); 515185442Skib lhdr->msg_iovlen = bhdr->msg_iovlen; 516185442Skib lhdr->msg_control = PTROUT(bhdr->msg_control); 517220031Savg 518220031Savg /* 519220031Savg * msg_controllen is skipped since BSD and LINUX control messages 520220031Savg * are potentially different sizes (e.g. the cred structure used 521220031Savg * by SCM_CREDS is different between the two operating system). 522220031Savg * 523220031Savg * The caller can set it (if necessary) after converting all the 524220031Savg * control messages. 525220031Savg */ 526220031Savg 527185442Skib /* msg_flags skipped */ 528185442Skib return (0); 529185442Skib} 530185442Skib 531185442Skibstatic int 532193165Sdchaginlinux_set_socket_flags(struct thread *td, int s, int flags) 533193165Sdchagin{ 534193165Sdchagin int error; 535193165Sdchagin 536193165Sdchagin if (flags & LINUX_SOCK_NONBLOCK) { 537193165Sdchagin error = kern_fcntl(td, s, F_SETFL, O_NONBLOCK); 538193165Sdchagin if (error) 539193165Sdchagin return (error); 540193165Sdchagin } 541193165Sdchagin if (flags & LINUX_SOCK_CLOEXEC) { 542193165Sdchagin error = kern_fcntl(td, s, F_SETFD, FD_CLOEXEC); 543193165Sdchagin if (error) 544193165Sdchagin return (error); 545193165Sdchagin } 546193165Sdchagin return (0); 547193165Sdchagin} 548193165Sdchagin 549193165Sdchaginstatic int 550141029Ssobomaxlinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags, 551185442Skib struct mbuf *control, enum uio_seg segflg) 552122358Sdwmalone{ 553122358Sdwmalone struct sockaddr *to; 554122358Sdwmalone int error; 555122358Sdwmalone 556122358Sdwmalone if (mp->msg_name != NULL) { 557122358Sdwmalone error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 558122358Sdwmalone if (error) 559122358Sdwmalone return (error); 560122358Sdwmalone mp->msg_name = to; 561122358Sdwmalone } else 562122358Sdwmalone to = NULL; 563122358Sdwmalone 564141029Ssobomax error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control, 565141029Ssobomax segflg); 566122358Sdwmalone 567122358Sdwmalone if (to) 568184205Sdes free(to, M_SONAME); 569122358Sdwmalone return (error); 570122358Sdwmalone} 571122358Sdwmalone 57265108Smarcel/* Return 0 if IP_HDRINCL is set for the given socket. */ 57331711Smsmithstatic int 574132313Sdwmalonelinux_check_hdrincl(struct thread *td, int s) 57531711Smsmith{ 576123828Sbde int error, optval, size_val; 57731711Smsmith 578132313Sdwmalone size_val = sizeof(optval); 579132313Sdwmalone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 580132313Sdwmalone &optval, UIO_SYSSPACE, &size_val); 581132313Sdwmalone if (error) 58265108Smarcel return (error); 58365108Smarcel 58465108Smarcel return (optval == 0); 58531711Smsmith} 58631711Smsmith 587122358Sdwmalonestruct linux_sendto_args { 588122358Sdwmalone int s; 589133816Stjr l_uintptr_t msg; 590122358Sdwmalone int len; 591122358Sdwmalone int flags; 592133816Stjr l_uintptr_t to; 593122358Sdwmalone int tolen; 594122358Sdwmalone}; 595122358Sdwmalone 59631711Smsmith/* 59731711Smsmith * Updated sendto() when IP_HDRINCL is set: 59831711Smsmith * tweak endian-dependent fields in the IP packet. 59931711Smsmith */ 60031711Smsmithstatic int 601132331Srwatsonlinux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args) 60231711Smsmith{ 60331711Smsmith/* 60431711Smsmith * linux_ip_copysize defines how many bytes we should copy 60531711Smsmith * from the beginning of the IP packet before we customize it for BSD. 606141029Ssobomax * It should include all the fields we modify (ip_len and ip_off). 60731711Smsmith */ 60831711Smsmith#define linux_ip_copysize 8 60931711Smsmith 61065108Smarcel struct ip *packet; 611122358Sdwmalone struct msghdr msg; 612141029Ssobomax struct iovec aiov[1]; 61365108Smarcel int error; 61431711Smsmith 615144012Sdas /* Check that the packet isn't too big or too small. */ 616144012Sdas if (linux_args->len < linux_ip_copysize || 617144012Sdas linux_args->len > IP_MAXPACKET) 61865108Smarcel return (EINVAL); 61931711Smsmith 620141029Ssobomax packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK); 62131711Smsmith 622141029Ssobomax /* Make kernel copy of the packet to be sent */ 623133816Stjr if ((error = copyin(PTRIN(linux_args->msg), packet, 624141029Ssobomax linux_args->len))) 625141029Ssobomax goto goout; 62631711Smsmith 62765108Smarcel /* Convert fields from Linux to BSD raw IP socket format */ 628122358Sdwmalone packet->ip_len = linux_args->len; 62965108Smarcel packet->ip_off = ntohs(packet->ip_off); 63031711Smsmith 63165108Smarcel /* Prepare the msghdr and iovec structures describing the new packet */ 632133816Stjr msg.msg_name = PTRIN(linux_args->to); 633122358Sdwmalone msg.msg_namelen = linux_args->tolen; 634122358Sdwmalone msg.msg_iov = aiov; 635141029Ssobomax msg.msg_iovlen = 1; 636122358Sdwmalone msg.msg_control = NULL; 637122358Sdwmalone msg.msg_flags = 0; 638122358Sdwmalone aiov[0].iov_base = (char *)packet; 639141029Ssobomax aiov[0].iov_len = linux_args->len; 640141029Ssobomax error = linux_sendit(td, linux_args->s, &msg, linux_args->flags, 641185442Skib NULL, UIO_SYSSPACE); 642141029Ssobomaxgoout: 643141029Ssobomax free(packet, M_TEMP); 644122358Sdwmalone return (error); 64531711Smsmith} 64631711Smsmith 6479313Ssosstruct linux_socket_args { 64865108Smarcel int domain; 64965108Smarcel int type; 65065108Smarcel int protocol; 6519313Ssos}; 6529313Ssos 6539313Ssosstatic int 65483366Sjulianlinux_socket(struct thread *td, struct linux_socket_args *args) 6559313Ssos{ 65665108Smarcel struct socket_args /* { 65765108Smarcel int domain; 65865108Smarcel int type; 65965108Smarcel int protocol; 66065108Smarcel } */ bsd_args; 661192206Sdchagin int retval_socket, socket_flags; 6629313Ssos 663182890Skib bsd_args.protocol = args->protocol; 664192206Sdchagin socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; 665192206Sdchagin if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 666192206Sdchagin return (EINVAL); 667192206Sdchagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 668192205Sdchagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 669192205Sdchagin return (EINVAL); 670182890Skib bsd_args.domain = linux_to_bsd_domain(args->domain); 67165108Smarcel if (bsd_args.domain == -1) 672191875Sdchagin return (EAFNOSUPPORT); 67331711Smsmith 674225617Skmacy retval_socket = sys_socket(td, &bsd_args); 675192204Sdchagin if (retval_socket) 676192204Sdchagin return (retval_socket); 677192204Sdchagin 678193165Sdchagin retval_socket = linux_set_socket_flags(td, td->td_retval[0], 679193165Sdchagin socket_flags); 680193165Sdchagin if (retval_socket) { 681193165Sdchagin (void)kern_close(td, td->td_retval[0]); 682193165Sdchagin goto out; 683192206Sdchagin } 684192206Sdchagin 68565108Smarcel if (bsd_args.type == SOCK_RAW 68665108Smarcel && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 687192204Sdchagin && bsd_args.domain == PF_INET) { 68865108Smarcel /* It's a raw IP socket: set the IP_HDRINCL option. */ 689132313Sdwmalone int hdrincl; 69065108Smarcel 691132313Sdwmalone hdrincl = 1; 692132313Sdwmalone /* We ignore any error returned by kern_setsockopt() */ 693132313Sdwmalone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 694132313Sdwmalone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 69565108Smarcel } 696110295Sume#ifdef INET6 697110295Sume /* 698198467Sbz * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default 699198467Sbz * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. 700198467Sbz * For simplicity we do this unconditionally of the net.inet6.ip6.v6only 701198467Sbz * sysctl value. 702110295Sume */ 703198467Sbz if (bsd_args.domain == PF_INET6) { 704132313Sdwmalone int v6only; 70565108Smarcel 706132313Sdwmalone v6only = 0; 707110295Sume /* We ignore any error returned by setsockopt() */ 708132313Sdwmalone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 709132313Sdwmalone &v6only, UIO_SYSSPACE, sizeof(v6only)); 710110295Sume } 711110295Sume#endif 712110295Sume 713192206Sdchaginout: 71465108Smarcel return (retval_socket); 7159313Ssos} 7169313Ssos 7179313Ssosstruct linux_bind_args { 71865108Smarcel int s; 719133816Stjr l_uintptr_t name; 72065108Smarcel int namelen; 7219313Ssos}; 7229313Ssos 7239313Ssosstatic int 72483366Sjulianlinux_bind(struct thread *td, struct linux_bind_args *args) 7259313Ssos{ 726110295Sume struct sockaddr *sa; 72765108Smarcel int error; 7289313Ssos 729182890Skib error = linux_getsockaddr(&sa, PTRIN(args->name), 730182890Skib args->namelen); 731110295Sume if (error) 732110295Sume return (error); 733110295Sume 734182890Skib error = kern_bind(td, args->s, sa); 735160506Sjhb free(sa, M_SONAME); 736182890Skib if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in)) 737162585Snetchild return (EINVAL); 738160506Sjhb return (error); 7399313Ssos} 7409313Ssos 741158415Snetchildstruct linux_connect_args { 74265108Smarcel int s; 743133816Stjr l_uintptr_t name; 74465108Smarcel int namelen; 7459313Ssos}; 74683366Sjulianint linux_connect(struct thread *, struct linux_connect_args *); 7479313Ssos 74868803Sgallatinint 74983366Sjulianlinux_connect(struct thread *td, struct linux_connect_args *args) 7509313Ssos{ 751255219Spjd cap_rights_t rights; 75273288Sjlemon struct socket *so; 753110295Sume struct sockaddr *sa; 75486504Sdillon u_int fflag; 75565108Smarcel int error; 7569313Ssos 757182890Skib error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name), 758182890Skib args->namelen); 759110295Sume if (error) 760110295Sume return (error); 761110295Sume 762182890Skib error = kern_connect(td, args->s, sa); 763160506Sjhb free(sa, M_SONAME); 76473288Sjlemon if (error != EISCONN) 76573288Sjlemon return (error); 76633148Smsmith 76773288Sjlemon /* 76873288Sjlemon * Linux doesn't return EISCONN the first time it occurs, 76973288Sjlemon * when on a non-blocking socket. Instead it returns the 77073288Sjlemon * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 771157369Srwatson * 772157369Srwatson * XXXRW: Instead of using fgetsock(), check that it is a 773157369Srwatson * socket and use the file descriptor reference instead of 774157369Srwatson * creating a new one. 77573288Sjlemon */ 776255219Spjd error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT), 777255219Spjd &so, &fflag); 778147853Sjhb if (error == 0) { 779147853Sjhb error = EISCONN; 780147853Sjhb if (fflag & FNONBLOCK) { 781147853Sjhb SOCK_LOCK(so); 782147853Sjhb if (so->so_emuldata == 0) 783147853Sjhb error = so->so_error; 784147853Sjhb so->so_emuldata = (void *)1; 785147853Sjhb SOCK_UNLOCK(so); 786147853Sjhb } 787147853Sjhb fputsock(so); 78833148Smsmith } 78965108Smarcel return (error); 7909313Ssos} 7919313Ssos 7929313Ssosstruct linux_listen_args { 79365108Smarcel int s; 79465108Smarcel int backlog; 7959313Ssos}; 7969313Ssos 7979313Ssosstatic int 79883366Sjulianlinux_listen(struct thread *td, struct linux_listen_args *args) 7999313Ssos{ 80065108Smarcel struct listen_args /* { 80165108Smarcel int s; 80265108Smarcel int backlog; 80365108Smarcel } */ bsd_args; 8049313Ssos 805182890Skib bsd_args.s = args->s; 806182890Skib bsd_args.backlog = args->backlog; 807225617Skmacy return (sys_listen(td, &bsd_args)); 8089313Ssos} 8099313Ssos 810158415Snetchildstatic int 811193262Sdchaginlinux_accept_common(struct thread *td, int s, l_uintptr_t addr, 812193265Sdchagin l_uintptr_t namelen, int flags) 8139313Ssos{ 81465108Smarcel struct accept_args /* { 815123828Sbde int s; 816123828Sbde struct sockaddr * __restrict name; 817123828Sbde socklen_t * __restrict anamelen; 81865108Smarcel } */ bsd_args; 819193263Sdchagin int error; 8209313Ssos 821193263Sdchagin if (flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 822193263Sdchagin return (EINVAL); 823193263Sdchagin 824193262Sdchagin bsd_args.s = s; 825123828Sbde /* XXX: */ 826193262Sdchagin bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr); 827193262Sdchagin bsd_args.anamelen = PTRIN(namelen);/* XXX */ 828225617Skmacy error = sys_accept(td, &bsd_args); 829156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name); 830162585Snetchild if (error) { 831193262Sdchagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) 832182890Skib return (EINVAL); 83365108Smarcel return (error); 834162585Snetchild } 83565108Smarcel 83665108Smarcel /* 83765108Smarcel * linux appears not to copy flags from the parent socket to the 838193263Sdchagin * accepted one, so we must clear the flags in the new descriptor 839193263Sdchagin * and apply the requested flags. 84065108Smarcel */ 841193263Sdchagin error = kern_fcntl(td, td->td_retval[0], F_SETFL, 0); 842193263Sdchagin if (error) 843193263Sdchagin goto out; 844193263Sdchagin error = linux_set_socket_flags(td, td->td_retval[0], flags); 845193263Sdchagin if (error) 846193263Sdchagin goto out; 847193263Sdchagin if (addr) 848193263Sdchagin error = linux_sa_put(PTRIN(addr)); 849193263Sdchagin 850193263Sdchaginout: 851193263Sdchagin if (error) { 852193263Sdchagin (void)kern_close(td, td->td_retval[0]); 853193263Sdchagin td->td_retval[0] = 0; 854193263Sdchagin } 855193263Sdchagin return (error); 8569313Ssos} 8579313Ssos 858193262Sdchaginstruct linux_accept_args { 859193262Sdchagin int s; 860193262Sdchagin l_uintptr_t addr; 861193262Sdchagin l_uintptr_t namelen; 862193262Sdchagin}; 863193262Sdchagin 864193262Sdchaginstatic int 865193262Sdchaginlinux_accept(struct thread *td, struct linux_accept_args *args) 866193262Sdchagin{ 867193262Sdchagin 868193262Sdchagin return (linux_accept_common(td, args->s, args->addr, 869193265Sdchagin args->namelen, 0)); 870193262Sdchagin} 871193262Sdchagin 872193264Sdchaginstruct linux_accept4_args { 873193264Sdchagin int s; 874193264Sdchagin l_uintptr_t addr; 875193264Sdchagin l_uintptr_t namelen; 876193264Sdchagin int flags; 877193264Sdchagin}; 878193264Sdchagin 879193264Sdchaginstatic int 880193264Sdchaginlinux_accept4(struct thread *td, struct linux_accept4_args *args) 881193264Sdchagin{ 882193264Sdchagin 883193264Sdchagin return (linux_accept_common(td, args->s, args->addr, 884193264Sdchagin args->namelen, args->flags)); 885193264Sdchagin} 886193264Sdchagin 887158415Snetchildstruct linux_getsockname_args { 88865108Smarcel int s; 889133816Stjr l_uintptr_t addr; 890133816Stjr l_uintptr_t namelen; 8919313Ssos}; 8929313Ssos 893158415Snetchildstatic int 89483366Sjulianlinux_getsockname(struct thread *td, struct linux_getsockname_args *args) 8959313Ssos{ 89665108Smarcel struct getsockname_args /* { 897123828Sbde int fdes; 898123828Sbde struct sockaddr * __restrict asa; 899123828Sbde socklen_t * __restrict alen; 90065108Smarcel } */ bsd_args; 90165108Smarcel int error; 9029313Ssos 903182890Skib bsd_args.fdes = args->s; 904123828Sbde /* XXX: */ 905182890Skib bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr); 906182890Skib bsd_args.alen = PTRIN(args->namelen); /* XXX */ 907225617Skmacy error = sys_getsockname(td, &bsd_args); 908156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 909110295Sume if (error) 910110295Sume return (error); 911182890Skib error = linux_sa_put(PTRIN(args->addr)); 912110295Sume if (error) 913110295Sume return (error); 914110295Sume return (0); 9159313Ssos} 9169313Ssos 917158415Snetchildstruct linux_getpeername_args { 91865108Smarcel int s; 919133816Stjr l_uintptr_t addr; 920133816Stjr l_uintptr_t namelen; 9219313Ssos}; 9229313Ssos 923158415Snetchildstatic int 92483366Sjulianlinux_getpeername(struct thread *td, struct linux_getpeername_args *args) 9259313Ssos{ 926156842Snetchild struct getpeername_args /* { 92765108Smarcel int fdes; 92865108Smarcel caddr_t asa; 92965108Smarcel int *alen; 93065108Smarcel } */ bsd_args; 93165108Smarcel int error; 9329313Ssos 933182890Skib bsd_args.fdes = args->s; 934182890Skib bsd_args.asa = (struct sockaddr *)PTRIN(args->addr); 935182890Skib bsd_args.alen = (int *)PTRIN(args->namelen); 936225617Skmacy error = sys_getpeername(td, &bsd_args); 937156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa); 938110295Sume if (error) 939110295Sume return (error); 940182890Skib error = linux_sa_put(PTRIN(args->addr)); 941110295Sume if (error) 942110295Sume return (error); 943110295Sume return (0); 9449313Ssos} 9459313Ssos 946158415Snetchildstruct linux_socketpair_args { 94765108Smarcel int domain; 94865108Smarcel int type; 94965108Smarcel int protocol; 950133816Stjr l_uintptr_t rsv; 9519313Ssos}; 9529313Ssos 953158415Snetchildstatic int 95483366Sjulianlinux_socketpair(struct thread *td, struct linux_socketpair_args *args) 9559313Ssos{ 95665108Smarcel struct socketpair_args /* { 95765108Smarcel int domain; 95865108Smarcel int type; 95965108Smarcel int protocol; 96065108Smarcel int *rsv; 96165108Smarcel } */ bsd_args; 962193168Sdchagin int error, socket_flags; 963193168Sdchagin int sv[2]; 9649313Ssos 965182890Skib bsd_args.domain = linux_to_bsd_domain(args->domain); 966191871Sdchagin if (bsd_args.domain != PF_LOCAL) 967191871Sdchagin return (EAFNOSUPPORT); 96865108Smarcel 969193168Sdchagin socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; 970193168Sdchagin if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) 971193168Sdchagin return (EINVAL); 972193168Sdchagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; 973193168Sdchagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) 974193168Sdchagin return (EINVAL); 975193168Sdchagin 976191871Sdchagin if (args->protocol != 0 && args->protocol != PF_UNIX) 977191871Sdchagin 978191871Sdchagin /* 979191871Sdchagin * Use of PF_UNIX as protocol argument is not right, 980191871Sdchagin * but Linux does it. 981191871Sdchagin * Do not map PF_UNIX as its Linux value is identical 982191871Sdchagin * to FreeBSD one. 983191871Sdchagin */ 984191871Sdchagin return (EPROTONOSUPPORT); 985191871Sdchagin else 986191742Sdchagin bsd_args.protocol = 0; 987182890Skib bsd_args.rsv = (int *)PTRIN(args->rsv); 988193168Sdchagin error = kern_socketpair(td, bsd_args.domain, bsd_args.type, 989193168Sdchagin bsd_args.protocol, sv); 990193168Sdchagin if (error) 991193168Sdchagin return (error); 992193168Sdchagin error = linux_set_socket_flags(td, sv[0], socket_flags); 993193168Sdchagin if (error) 994193168Sdchagin goto out; 995193168Sdchagin error = linux_set_socket_flags(td, sv[1], socket_flags); 996193168Sdchagin if (error) 997193168Sdchagin goto out; 998193168Sdchagin 999193168Sdchagin error = copyout(sv, bsd_args.rsv, 2 * sizeof(int)); 1000193168Sdchagin 1001193168Sdchaginout: 1002193168Sdchagin if (error) { 1003193168Sdchagin (void)kern_close(td, sv[0]); 1004193168Sdchagin (void)kern_close(td, sv[1]); 1005193168Sdchagin } 1006193168Sdchagin return (error); 10079313Ssos} 10089313Ssos 1009158415Snetchildstruct linux_send_args { 101065108Smarcel int s; 1011133816Stjr l_uintptr_t msg; 101265108Smarcel int len; 101365108Smarcel int flags; 10149313Ssos}; 10159313Ssos 1016158415Snetchildstatic int 101783366Sjulianlinux_send(struct thread *td, struct linux_send_args *args) 10189313Ssos{ 1019131796Sphk struct sendto_args /* { 1020103886Smini int s; 102165108Smarcel caddr_t buf; 1022103886Smini int len; 102365108Smarcel int flags; 1024131796Sphk caddr_t to; 1025131796Sphk int tolen; 102665108Smarcel } */ bsd_args; 10279313Ssos 1028182890Skib bsd_args.s = args->s; 1029182890Skib bsd_args.buf = (caddr_t)PTRIN(args->msg); 1030182890Skib bsd_args.len = args->len; 1031182890Skib bsd_args.flags = args->flags; 1032131796Sphk bsd_args.to = NULL; 1033131796Sphk bsd_args.tolen = 0; 1034225617Skmacy return sys_sendto(td, &bsd_args); 10359313Ssos} 10369313Ssos 1037158415Snetchildstruct linux_recv_args { 103865108Smarcel int s; 1039133816Stjr l_uintptr_t msg; 104065108Smarcel int len; 104165108Smarcel int flags; 10429313Ssos}; 10439313Ssos 1044158415Snetchildstatic int 104583366Sjulianlinux_recv(struct thread *td, struct linux_recv_args *args) 10469313Ssos{ 1047131796Sphk struct recvfrom_args /* { 104865108Smarcel int s; 104965108Smarcel caddr_t buf; 105065108Smarcel int len; 105165108Smarcel int flags; 1052131796Sphk struct sockaddr *from; 1053131796Sphk socklen_t fromlenaddr; 105465108Smarcel } */ bsd_args; 10559313Ssos 1056182890Skib bsd_args.s = args->s; 1057182890Skib bsd_args.buf = (caddr_t)PTRIN(args->msg); 1058182890Skib bsd_args.len = args->len; 1059191988Sdchagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 1060131796Sphk bsd_args.from = NULL; 1061131796Sphk bsd_args.fromlenaddr = 0; 1062225617Skmacy return (sys_recvfrom(td, &bsd_args)); 10639313Ssos} 10649313Ssos 10659313Ssosstatic int 106683366Sjulianlinux_sendto(struct thread *td, struct linux_sendto_args *args) 10679313Ssos{ 1068122358Sdwmalone struct msghdr msg; 1069122358Sdwmalone struct iovec aiov; 1070122358Sdwmalone int error; 10719313Ssos 1072182890Skib if (linux_check_hdrincl(td, args->s) == 0) 107365108Smarcel /* IP_HDRINCL set, tweak the packet before sending */ 1074182890Skib return (linux_sendto_hdrincl(td, args)); 107565108Smarcel 1076182890Skib msg.msg_name = PTRIN(args->to); 1077182890Skib msg.msg_namelen = args->tolen; 1078122358Sdwmalone msg.msg_iov = &aiov; 1079122358Sdwmalone msg.msg_iovlen = 1; 1080122358Sdwmalone msg.msg_control = NULL; 1081122358Sdwmalone msg.msg_flags = 0; 1082182890Skib aiov.iov_base = PTRIN(args->msg); 1083182890Skib aiov.iov_len = args->len; 1084185442Skib error = linux_sendit(td, args->s, &msg, args->flags, NULL, 1085185442Skib UIO_USERSPACE); 1086122358Sdwmalone return (error); 10879313Ssos} 10889313Ssos 1089158415Snetchildstruct linux_recvfrom_args { 109065108Smarcel int s; 1091133816Stjr l_uintptr_t buf; 109265108Smarcel int len; 109365108Smarcel int flags; 1094133816Stjr l_uintptr_t from; 1095133816Stjr l_uintptr_t fromlen; 10969313Ssos}; 10979313Ssos 1098158415Snetchildstatic int 109983366Sjulianlinux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 11009313Ssos{ 110165108Smarcel struct recvfrom_args /* { 1102123828Sbde int s; 1103123828Sbde caddr_t buf; 1104123828Sbde size_t len; 1105123828Sbde int flags; 1106123828Sbde struct sockaddr * __restrict from; 1107123828Sbde socklen_t * __restrict fromlenaddr; 110865108Smarcel } */ bsd_args; 1109156842Snetchild size_t len; 111065108Smarcel int error; 11119313Ssos 1112182890Skib if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t)))) 111365108Smarcel return (error); 111465108Smarcel 1115182890Skib bsd_args.s = args->s; 1116182890Skib bsd_args.buf = PTRIN(args->buf); 1117182890Skib bsd_args.len = args->len; 1118182890Skib bsd_args.flags = linux_to_bsd_msg_flags(args->flags); 1119123828Sbde /* XXX: */ 1120182890Skib bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from); 1121182890Skib bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */ 1122156842Snetchild 1123156842Snetchild linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len); 1124225617Skmacy error = sys_recvfrom(td, &bsd_args); 1125156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from); 1126156842Snetchild 1127110295Sume if (error) 1128110295Sume return (error); 1129182890Skib if (args->from) { 1130133816Stjr error = linux_sa_put((struct osockaddr *) 1131182890Skib PTRIN(args->from)); 1132110295Sume if (error) 1133110295Sume return (error); 1134110295Sume } 1135110295Sume return (0); 11369313Ssos} 11379313Ssos 1138158415Snetchildstruct linux_sendmsg_args { 1139110295Sume int s; 1140133816Stjr l_uintptr_t msg; 1141110295Sume int flags; 1142110295Sume}; 1143110295Sume 1144158415Snetchildstatic int 1145110295Sumelinux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 1146110295Sume{ 1147185442Skib struct cmsghdr *cmsg; 1148220031Savg struct cmsgcred cmcred; 1149185442Skib struct mbuf *control; 1150110295Sume struct msghdr msg; 1151185442Skib struct l_cmsghdr linux_cmsg; 1152185442Skib struct l_cmsghdr *ptr_cmsg; 1153185442Skib struct l_msghdr linux_msg; 1154131897Sphk struct iovec *iov; 1155185442Skib socklen_t datalen; 1156220031Savg struct sockaddr *sa; 1157220031Savg sa_family_t sa_family; 1158185442Skib void *data; 1159110295Sume int error; 1160110295Sume 1161185442Skib error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1162131897Sphk if (error) 1163110295Sume return (error); 1164168711Srwatson 1165168711Srwatson /* 1166168711Srwatson * Some Linux applications (ping) define a non-NULL control data 1167168711Srwatson * pointer, but a msg_controllen of 0, which is not allowed in the 1168168711Srwatson * FreeBSD system call interface. NULL the msg_control pointer in 1169168711Srwatson * order to handle this case. This should be checked, but allows the 1170168711Srwatson * Linux ping to work. 1171168711Srwatson */ 1172220031Savg if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0) 1173220031Savg linux_msg.msg_control = PTROUT(NULL); 1174185442Skib 1175220031Savg error = linux_to_bsd_msghdr(&msg, &linux_msg); 1176220031Savg if (error) 1177220031Savg return (error); 1178220031Savg 1179185442Skib#ifdef COMPAT_LINUX32 1180185442Skib error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1181185442Skib &iov, EMSGSIZE); 1182185442Skib#else 1183131897Sphk error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1184185442Skib#endif 1185131897Sphk if (error) 1186131897Sphk return (error); 1187185442Skib 1188220031Savg control = NULL; 1189220031Savg cmsg = NULL; 1190220031Savg 1191220031Savg if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) { 1192220031Savg error = kern_getsockname(td, args->s, &sa, &datalen); 1193220031Savg if (error) 1194220031Savg goto bad; 1195220031Savg sa_family = sa->sa_family; 1196220031Savg free(sa, M_SONAME); 1197220031Savg 1198185442Skib error = ENOBUFS; 1199185442Skib cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1200243882Sglebius control = m_get(M_WAITOK, MT_CONTROL); 1201185442Skib if (control == NULL) 1202185442Skib goto bad; 1203185442Skib 1204185442Skib do { 1205185442Skib error = copyin(ptr_cmsg, &linux_cmsg, 1206185442Skib sizeof(struct l_cmsghdr)); 1207185442Skib if (error) 1208185442Skib goto bad; 1209185442Skib 1210185442Skib error = EINVAL; 1211185442Skib if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr)) 1212185442Skib goto bad; 1213185442Skib 1214185442Skib /* 1215220031Savg * Now we support only SCM_RIGHTS and SCM_CRED, 1216220031Savg * so return EINVAL in any other cmsg_type 1217185442Skib */ 1218220031Savg cmsg->cmsg_type = 1219220031Savg linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type); 1220185442Skib cmsg->cmsg_level = 1221185442Skib linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level); 1222220031Savg if (cmsg->cmsg_type == -1 1223220031Savg || cmsg->cmsg_level != SOL_SOCKET) 1224220031Savg goto bad; 1225185442Skib 1226220031Savg /* 1227220031Savg * Some applications (e.g. pulseaudio) attempt to 1228220031Savg * send ancillary data even if the underlying protocol 1229220031Savg * doesn't support it which is not allowed in the 1230220031Savg * FreeBSD system call interface. 1231220031Savg */ 1232220031Savg if (sa_family != AF_UNIX) 1233220031Savg continue; 1234220031Savg 1235220031Savg data = LINUX_CMSG_DATA(ptr_cmsg); 1236185442Skib datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ; 1237220031Savg 1238220031Savg switch (cmsg->cmsg_type) 1239220031Savg { 1240220031Savg case SCM_RIGHTS: 1241220031Savg break; 1242220031Savg 1243220031Savg case SCM_CREDS: 1244220031Savg data = &cmcred; 1245220031Savg datalen = sizeof(cmcred); 1246220031Savg 1247220031Savg /* 1248220031Savg * The lower levels will fill in the structure 1249220031Savg */ 1250220031Savg bzero(data, datalen); 1251220031Savg break; 1252220031Savg } 1253220031Savg 1254185442Skib cmsg->cmsg_len = CMSG_LEN(datalen); 1255185442Skib 1256185442Skib error = ENOBUFS; 1257226074Sjkim if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg)) 1258185442Skib goto bad; 1259226074Sjkim if (!m_append(control, datalen, (c_caddr_t)data)) 1260185442Skib goto bad; 1261220031Savg } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg))); 1262220031Savg 1263220031Savg if (m_length(control, NULL) == 0) { 1264220031Savg m_freem(control); 1265220031Savg control = NULL; 1266220031Savg } 1267185442Skib } 1268185442Skib 1269122358Sdwmalone msg.msg_iov = iov; 1270122358Sdwmalone msg.msg_flags = 0; 1271185442Skib error = linux_sendit(td, args->s, &msg, args->flags, control, 1272185442Skib UIO_USERSPACE); 1273185442Skib 1274185442Skibbad: 1275131897Sphk free(iov, M_IOV); 1276185442Skib if (cmsg) 1277185442Skib free(cmsg, M_TEMP); 1278122358Sdwmalone return (error); 1279110295Sume} 1280110295Sume 1281158415Snetchildstruct linux_recvmsg_args { 128270178Sassar int s; 1283133816Stjr l_uintptr_t msg; 128470178Sassar int flags; 128570178Sassar}; 128670178Sassar 1287158415Snetchildstatic int 128883366Sjulianlinux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 128970178Sassar{ 1290185442Skib struct cmsghdr *cm; 1291220031Savg struct cmsgcred *cmcred; 1292110295Sume struct msghdr msg; 1293185442Skib struct l_cmsghdr *linux_cmsg = NULL; 1294220031Savg struct l_ucred linux_ucred; 1295220031Savg socklen_t datalen, outlen; 1296185442Skib struct l_msghdr linux_msg; 1297185442Skib struct iovec *iov, *uiov; 1298185442Skib struct mbuf *control = NULL; 1299185442Skib struct mbuf **controlp; 1300185442Skib caddr_t outbuf; 1301185442Skib void *data; 1302192284Sdchagin int error, i, fd, fds, *fdp; 130370178Sassar 1304185442Skib error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg)); 1305185442Skib if (error) 1306185442Skib return (error); 1307133816Stjr 1308185442Skib error = linux_to_bsd_msghdr(&msg, &linux_msg); 1309185442Skib if (error) 1310166398Skib return (error); 1311166398Skib 1312185442Skib#ifdef COMPAT_LINUX32 1313185442Skib error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen, 1314185442Skib &iov, EMSGSIZE); 1315185442Skib#else 1316185442Skib error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 1317185442Skib#endif 1318110295Sume if (error) 1319110295Sume return (error); 1320110295Sume 1321185442Skib if (msg.msg_name) { 1322185442Skib error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name, 1323185442Skib msg.msg_namelen); 1324185442Skib if (error) 1325185442Skib goto bad; 1326121008Siwasaki } 1327121008Siwasaki 1328185442Skib uiov = msg.msg_iov; 1329185442Skib msg.msg_iov = iov; 1330185442Skib controlp = (msg.msg_control != NULL) ? &control : NULL; 1331185442Skib error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp); 1332185442Skib msg.msg_iov = uiov; 1333110295Sume if (error) 1334185442Skib goto bad; 1335185442Skib 1336185442Skib error = bsd_to_linux_msghdr(&msg, &linux_msg); 1337185442Skib if (error) 1338185442Skib goto bad; 1339185442Skib 1340185442Skib if (linux_msg.msg_name) { 1341185442Skib error = bsd_to_linux_sockaddr((struct sockaddr *) 1342185442Skib PTRIN(linux_msg.msg_name)); 1343185442Skib if (error) 1344185442Skib goto bad; 1345185442Skib } 1346185442Skib if (linux_msg.msg_name && linux_msg.msg_namelen > 2) { 1347185442Skib error = linux_sa_put(PTRIN(linux_msg.msg_name)); 1348185442Skib if (error) 1349185442Skib goto bad; 1350185442Skib } 1351185442Skib 1352220031Savg outbuf = PTRIN(linux_msg.msg_control); 1353220031Savg outlen = 0; 1354220031Savg 1355185442Skib if (control) { 1356185442Skib linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO); 1357185442Skib 1358220031Savg msg.msg_control = mtod(control, struct cmsghdr *); 1359220031Savg msg.msg_controllen = control->m_len; 1360220031Savg 1361220031Savg cm = CMSG_FIRSTHDR(&msg); 1362220031Savg 1363185442Skib while (cm != NULL) { 1364220031Savg linux_cmsg->cmsg_type = 1365220031Savg bsd_to_linux_cmsg_type(cm->cmsg_type); 1366220031Savg linux_cmsg->cmsg_level = 1367220031Savg bsd_to_linux_sockopt_level(cm->cmsg_level); 1368220031Savg if (linux_cmsg->cmsg_type == -1 1369220031Savg || cm->cmsg_level != SOL_SOCKET) 1370185442Skib { 1371185442Skib error = EINVAL; 1372185442Skib goto bad; 1373185442Skib } 1374220031Savg 1375185442Skib data = CMSG_DATA(cm); 1376185442Skib datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1377185442Skib 1378220031Savg switch (cm->cmsg_type) 1379192284Sdchagin { 1380220031Savg case SCM_RIGHTS: 1381192284Sdchagin if (args->flags & LINUX_MSG_CMSG_CLOEXEC) { 1382192284Sdchagin fds = datalen / sizeof(int); 1383192284Sdchagin fdp = data; 1384192284Sdchagin for (i = 0; i < fds; i++) { 1385192284Sdchagin fd = *fdp++; 1386192284Sdchagin (void)kern_fcntl(td, fd, 1387192284Sdchagin F_SETFD, FD_CLOEXEC); 1388192284Sdchagin } 1389192284Sdchagin } 1390192284Sdchagin break; 1391220031Savg 1392220031Savg case SCM_CREDS: 1393220031Savg /* 1394220031Savg * Currently LOCAL_CREDS is never in 1395220031Savg * effect for Linux so no need to worry 1396220031Savg * about sockcred 1397220031Savg */ 1398226074Sjkim if (datalen != sizeof(*cmcred)) { 1399220031Savg error = EMSGSIZE; 1400220031Savg goto bad; 1401220031Savg } 1402220031Savg cmcred = (struct cmsgcred *)data; 1403220031Savg bzero(&linux_ucred, sizeof(linux_ucred)); 1404220031Savg linux_ucred.pid = cmcred->cmcred_pid; 1405220031Savg linux_ucred.uid = cmcred->cmcred_uid; 1406220031Savg linux_ucred.gid = cmcred->cmcred_gid; 1407220031Savg data = &linux_ucred; 1408220031Savg datalen = sizeof(linux_ucred); 1409220031Savg break; 1410185442Skib } 1411185442Skib 1412220031Savg if (outlen + LINUX_CMSG_LEN(datalen) > 1413220031Savg linux_msg.msg_controllen) { 1414220031Savg if (outlen == 0) { 1415220031Savg error = EMSGSIZE; 1416220031Savg goto bad; 1417220031Savg } else { 1418220031Savg linux_msg.msg_flags |= 1419220031Savg LINUX_MSG_CTRUNC; 1420220031Savg goto out; 1421220031Savg } 1422220031Savg } 1423220031Savg 1424185442Skib linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen); 1425185442Skib 1426185442Skib error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ); 1427185442Skib if (error) 1428185442Skib goto bad; 1429185442Skib outbuf += L_CMSG_HDRSZ; 1430185442Skib 1431185442Skib error = copyout(data, outbuf, datalen); 1432185442Skib if (error) 1433185442Skib goto bad; 1434185442Skib 1435185442Skib outbuf += LINUX_CMSG_ALIGN(datalen); 1436185442Skib outlen += LINUX_CMSG_LEN(datalen); 1437185442Skib 1438220031Savg cm = CMSG_NXTHDR(&msg, cm); 1439185442Skib } 1440185442Skib } 1441185442Skib 1442185442Skibout: 1443220031Savg linux_msg.msg_controllen = outlen; 1444185442Skib error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg)); 1445185442Skib 1446185442Skibbad: 1447185442Skib free(iov, M_IOV); 1448247764Seadler m_freem(control); 1449247764Seadler free(linux_cmsg, M_TEMP); 1450185442Skib 1451110295Sume return (error); 145270178Sassar} 145370178Sassar 14549313Ssosstruct linux_shutdown_args { 145565108Smarcel int s; 145665108Smarcel int how; 14579313Ssos}; 14589313Ssos 14599313Ssosstatic int 146083366Sjulianlinux_shutdown(struct thread *td, struct linux_shutdown_args *args) 14619313Ssos{ 146265108Smarcel struct shutdown_args /* { 146365108Smarcel int s; 146465108Smarcel int how; 146565108Smarcel } */ bsd_args; 14669313Ssos 1467182890Skib bsd_args.s = args->s; 1468182890Skib bsd_args.how = args->how; 1469225617Skmacy return (sys_shutdown(td, &bsd_args)); 14709313Ssos} 14719313Ssos 14729313Ssosstruct linux_setsockopt_args { 147365108Smarcel int s; 147465108Smarcel int level; 147565108Smarcel int optname; 1476133816Stjr l_uintptr_t optval; 147765108Smarcel int optlen; 14789313Ssos}; 14799313Ssos 14809313Ssosstatic int 148183366Sjulianlinux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 14829313Ssos{ 148365108Smarcel struct setsockopt_args /* { 148465108Smarcel int s; 148565108Smarcel int level; 148665108Smarcel int name; 148765108Smarcel caddr_t val; 148865108Smarcel int valsize; 148965108Smarcel } */ bsd_args; 1490191989Sdchagin l_timeval linux_tv; 1491191989Sdchagin struct timeval tv; 149265108Smarcel int error, name; 14939313Ssos 1494182890Skib bsd_args.s = args->s; 1495182890Skib bsd_args.level = linux_to_bsd_sockopt_level(args->level); 149665108Smarcel switch (bsd_args.level) { 149765108Smarcel case SOL_SOCKET: 1498182890Skib name = linux_to_bsd_so_sockopt(args->optname); 1499191989Sdchagin switch (name) { 1500191989Sdchagin case SO_RCVTIMEO: 1501191989Sdchagin /* FALLTHROUGH */ 1502191989Sdchagin case SO_SNDTIMEO: 1503191989Sdchagin error = copyin(PTRIN(args->optval), &linux_tv, 1504191989Sdchagin sizeof(linux_tv)); 1505191989Sdchagin if (error) 1506191989Sdchagin return (error); 1507191989Sdchagin tv.tv_sec = linux_tv.tv_sec; 1508191989Sdchagin tv.tv_usec = linux_tv.tv_usec; 1509191989Sdchagin return (kern_setsockopt(td, args->s, bsd_args.level, 1510191989Sdchagin name, &tv, UIO_SYSSPACE, sizeof(tv))); 1511191989Sdchagin /* NOTREACHED */ 1512191989Sdchagin break; 1513191989Sdchagin default: 1514191989Sdchagin break; 1515191989Sdchagin } 151665108Smarcel break; 151765108Smarcel case IPPROTO_IP: 1518182890Skib name = linux_to_bsd_ip_sockopt(args->optname); 151965108Smarcel break; 152065108Smarcel case IPPROTO_TCP: 1521245849Sjhb name = linux_to_bsd_tcp_sockopt(args->optname); 152265108Smarcel break; 152365108Smarcel default: 152465108Smarcel name = -1; 152565108Smarcel break; 152665108Smarcel } 152765108Smarcel if (name == -1) 1528162585Snetchild return (ENOPROTOOPT); 152965108Smarcel 153065108Smarcel bsd_args.name = name; 1531182890Skib bsd_args.val = PTRIN(args->optval); 1532182890Skib bsd_args.valsize = args->optlen; 1533156842Snetchild 1534156842Snetchild if (name == IPV6_NEXTHOP) { 1535156842Snetchild linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val, 1536156842Snetchild bsd_args.valsize); 1537225617Skmacy error = sys_setsockopt(td, &bsd_args); 1538156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1539156842Snetchild } else 1540225617Skmacy error = sys_setsockopt(td, &bsd_args); 1541156842Snetchild 1542156842Snetchild return (error); 15439313Ssos} 15449313Ssos 15459313Ssosstruct linux_getsockopt_args { 154665108Smarcel int s; 154765108Smarcel int level; 154865108Smarcel int optname; 1549133816Stjr l_uintptr_t optval; 1550133816Stjr l_uintptr_t optlen; 15519313Ssos}; 15529313Ssos 15539313Ssosstatic int 155483366Sjulianlinux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 15559313Ssos{ 155665108Smarcel struct getsockopt_args /* { 155765108Smarcel int s; 155865108Smarcel int level; 155965108Smarcel int name; 156065108Smarcel caddr_t val; 156165108Smarcel int *avalsize; 156265108Smarcel } */ bsd_args; 1563191989Sdchagin l_timeval linux_tv; 1564191989Sdchagin struct timeval tv; 1565192203Sdchagin socklen_t tv_len, xulen; 1566192203Sdchagin struct xucred xu; 1567192203Sdchagin struct l_ucred lxu; 156865108Smarcel int error, name; 15699313Ssos 1570182890Skib bsd_args.s = args->s; 1571182890Skib bsd_args.level = linux_to_bsd_sockopt_level(args->level); 157265108Smarcel switch (bsd_args.level) { 157365108Smarcel case SOL_SOCKET: 1574182890Skib name = linux_to_bsd_so_sockopt(args->optname); 1575191989Sdchagin switch (name) { 1576191989Sdchagin case SO_RCVTIMEO: 1577191989Sdchagin /* FALLTHROUGH */ 1578191989Sdchagin case SO_SNDTIMEO: 1579191989Sdchagin tv_len = sizeof(tv); 1580191989Sdchagin error = kern_getsockopt(td, args->s, bsd_args.level, 1581191989Sdchagin name, &tv, UIO_SYSSPACE, &tv_len); 1582191989Sdchagin if (error) 1583191989Sdchagin return (error); 1584191989Sdchagin linux_tv.tv_sec = tv.tv_sec; 1585191989Sdchagin linux_tv.tv_usec = tv.tv_usec; 1586191989Sdchagin return (copyout(&linux_tv, PTRIN(args->optval), 1587191989Sdchagin sizeof(linux_tv))); 1588191989Sdchagin /* NOTREACHED */ 1589191989Sdchagin break; 1590192203Sdchagin case LOCAL_PEERCRED: 1591192203Sdchagin if (args->optlen != sizeof(lxu)) 1592192203Sdchagin return (EINVAL); 1593192203Sdchagin xulen = sizeof(xu); 1594192203Sdchagin error = kern_getsockopt(td, args->s, bsd_args.level, 1595192203Sdchagin name, &xu, UIO_SYSSPACE, &xulen); 1596192203Sdchagin if (error) 1597192203Sdchagin return (error); 1598192203Sdchagin /* 1599192203Sdchagin * XXX Use 0 for pid as the FreeBSD does not cache peer pid. 1600192203Sdchagin */ 1601192203Sdchagin lxu.pid = 0; 1602192203Sdchagin lxu.uid = xu.cr_uid; 1603192203Sdchagin lxu.gid = xu.cr_gid; 1604192203Sdchagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu))); 1605192203Sdchagin /* NOTREACHED */ 1606192203Sdchagin break; 1607191989Sdchagin default: 1608191989Sdchagin break; 1609191989Sdchagin } 161065108Smarcel break; 161165108Smarcel case IPPROTO_IP: 1612182890Skib name = linux_to_bsd_ip_sockopt(args->optname); 161365108Smarcel break; 161465108Smarcel case IPPROTO_TCP: 1615245849Sjhb name = linux_to_bsd_tcp_sockopt(args->optname); 161665108Smarcel break; 161765108Smarcel default: 161865108Smarcel name = -1; 161965108Smarcel break; 162065108Smarcel } 162165108Smarcel if (name == -1) 162265108Smarcel return (EINVAL); 162365108Smarcel 162465108Smarcel bsd_args.name = name; 1625182890Skib bsd_args.val = PTRIN(args->optval); 1626182890Skib bsd_args.avalsize = PTRIN(args->optlen); 1627156842Snetchild 1628156842Snetchild if (name == IPV6_NEXTHOP) { 1629225617Skmacy error = sys_getsockopt(td, &bsd_args); 1630156842Snetchild bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val); 1631156842Snetchild } else 1632225617Skmacy error = sys_getsockopt(td, &bsd_args); 1633156842Snetchild 1634156842Snetchild return (error); 16359313Ssos} 16369313Ssos 1637192373Sdchagin/* Argument list sizes for linux_socketcall */ 1638192373Sdchagin 1639192373Sdchagin#define LINUX_AL(x) ((x) * sizeof(l_ulong)) 1640192373Sdchagin 1641192373Sdchaginstatic const unsigned char lxs_args[] = { 1642192373Sdchagin LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */, 1643192373Sdchagin LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */, 1644192373Sdchagin LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */, 1645192373Sdchagin LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */, 1646192373Sdchagin LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */, 1647192373Sdchagin LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */, 1648192373Sdchagin LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */, 1649192373Sdchagin LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */, 1650193264Sdchagin LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */, 1651193264Sdchagin LINUX_AL(4) /* accept4 */ 1652192373Sdchagin}; 1653192373Sdchagin 1654192373Sdchagin#define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1 1655192373Sdchagin 16569313Ssosint 165783366Sjulianlinux_socketcall(struct thread *td, struct linux_socketcall_args *args) 16589313Ssos{ 1659192373Sdchagin l_ulong a[6]; 1660192373Sdchagin void *arg; 1661192373Sdchagin int error; 166242509Smsmith 1663192373Sdchagin if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE) 1664192373Sdchagin return (EINVAL); 1665192373Sdchagin error = copyin(PTRIN(args->args), a, lxs_args[args->what]); 1666192373Sdchagin if (error) 1667192373Sdchagin return (error); 1668192373Sdchagin 1669192373Sdchagin arg = a; 167065108Smarcel switch (args->what) { 167165108Smarcel case LINUX_SOCKET: 167283366Sjulian return (linux_socket(td, arg)); 167365108Smarcel case LINUX_BIND: 167483366Sjulian return (linux_bind(td, arg)); 167565108Smarcel case LINUX_CONNECT: 167683366Sjulian return (linux_connect(td, arg)); 167765108Smarcel case LINUX_LISTEN: 167883366Sjulian return (linux_listen(td, arg)); 167965108Smarcel case LINUX_ACCEPT: 168083366Sjulian return (linux_accept(td, arg)); 168165108Smarcel case LINUX_GETSOCKNAME: 168283366Sjulian return (linux_getsockname(td, arg)); 168365108Smarcel case LINUX_GETPEERNAME: 168483366Sjulian return (linux_getpeername(td, arg)); 168565108Smarcel case LINUX_SOCKETPAIR: 168683366Sjulian return (linux_socketpair(td, arg)); 168765108Smarcel case LINUX_SEND: 168883366Sjulian return (linux_send(td, arg)); 168965108Smarcel case LINUX_RECV: 169083366Sjulian return (linux_recv(td, arg)); 169165108Smarcel case LINUX_SENDTO: 169283366Sjulian return (linux_sendto(td, arg)); 169365108Smarcel case LINUX_RECVFROM: 169483366Sjulian return (linux_recvfrom(td, arg)); 169565108Smarcel case LINUX_SHUTDOWN: 169683366Sjulian return (linux_shutdown(td, arg)); 169765108Smarcel case LINUX_SETSOCKOPT: 169883366Sjulian return (linux_setsockopt(td, arg)); 169965108Smarcel case LINUX_GETSOCKOPT: 170083366Sjulian return (linux_getsockopt(td, arg)); 170165108Smarcel case LINUX_SENDMSG: 1702110295Sume return (linux_sendmsg(td, arg)); 170365108Smarcel case LINUX_RECVMSG: 170483366Sjulian return (linux_recvmsg(td, arg)); 1705193264Sdchagin case LINUX_ACCEPT4: 1706193264Sdchagin return (linux_accept4(td, arg)); 170765108Smarcel } 170865108Smarcel 17099313Ssos uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 171065108Smarcel return (ENOSYS); 17119313Ssos} 1712