linux_socket.c revision 103886
162590Sitojun/*- 2122615Sume * Copyright (c) 1995 S�ren Schmidt 362590Sitojun * All rights reserved. 455505Sshin * 555505Sshin * Redistribution and use in source and binary forms, with or without 655505Sshin * modification, are permitted provided that the following conditions 755505Sshin * are met: 855505Sshin * 1. Redistributions of source code must retain the above copyright 955505Sshin * notice, this list of conditions and the following disclaimer 1055505Sshin * in this position and unchanged. 1155505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1255505Sshin * notice, this list of conditions and the following disclaimer in the 1355505Sshin * documentation and/or other materials provided with the distribution. 1455505Sshin * 3. The name of the author may not be used to endorse or promote products 1555505Sshin * derived from this software without specific prior written permission 1655505Sshin * 1755505Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1855505Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1955505Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2055505Sshin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2155505Sshin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2255505Sshin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2355505Sshin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2455505Sshin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2555505Sshin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2655505Sshin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2755505Sshin * 2855505Sshin * $FreeBSD: head/sys/compat/linux/linux_socket.c 103886 2002-09-24 07:03:01Z mini $ 2955505Sshin */ 3055505Sshin 3155505Sshin/* XXX we use functions that might not exist. */ 3255505Sshin#include "opt_compat.h" 3355505Sshin 3455505Sshin#ifndef COMPAT_43 3555505Sshin#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 3655505Sshin#endif 3755505Sshin 3855505Sshin#include <sys/param.h> 3955505Sshin#include <sys/proc.h> 4055505Sshin#include <sys/systm.h> 4155505Sshin#include <sys/sysproto.h> 4255505Sshin#include <sys/fcntl.h> 4355505Sshin#include <sys/file.h> 4455505Sshin#include <sys/socket.h> 4555505Sshin#include <sys/socketvar.h> 4655505Sshin#include <sys/uio.h> 4755505Sshin 4855505Sshin#include <netinet/in.h> 4955505Sshin#include <netinet/in_systm.h> 5055505Sshin#include <netinet/ip.h> 5155505Sshin 5255505Sshin#include <machine/../linux/linux.h> 5355505Sshin#include <machine/../linux/linux_proto.h> 5455505Sshin#include <compat/linux/linux_socket.h> 5555505Sshin#include <compat/linux/linux_util.h> 5655505Sshin 5755505Sshin/* 5855505Sshin * FreeBSD's socket calls require the sockaddr struct length to agree 5955505Sshin * with the address family. Linux does not, so we must force it. 6055505Sshin */ 6155505Sshinstatic int 6255505Sshinlinux_to_bsd_namelen(caddr_t name, int namelen) 6355505Sshin{ 6455505Sshin uint16_t family; /* XXX must match Linux sockaddr */ 6555505Sshin 6655505Sshin if (copyin(name, &family, sizeof(family))) 6755505Sshin return namelen; 6855505Sshin 6955505Sshin switch (family) { 7055505Sshin case AF_INET: 7155505Sshin return sizeof(struct sockaddr_in); 7255505Sshin case AF_INET6: 7355505Sshin return sizeof(struct sockaddr_in6); 7455505Sshin } 7555505Sshin return namelen; 7655505Sshin} 7755505Sshin 7855505Sshin#ifndef __alpha__ 7955505Sshinstatic int 8055505Sshinlinux_to_bsd_domain(int domain) 8155505Sshin{ 82253999Shrs 8378064Sume switch (domain) { 8455505Sshin case LINUX_AF_UNSPEC: 8555505Sshin return (AF_UNSPEC); 8655505Sshin case LINUX_AF_UNIX: 8755505Sshin return (AF_LOCAL); 8855505Sshin case LINUX_AF_INET: 8955505Sshin return (AF_INET); 9055505Sshin case LINUX_AF_AX25: 9155505Sshin return (AF_CCITT); 9255505Sshin case LINUX_AF_IPX: 9355505Sshin return (AF_IPX); 9455505Sshin case LINUX_AF_APPLETALK: 9555505Sshin return (AF_APPLETALK); 9655505Sshin } 9755505Sshin return (-1); 9855505Sshin} 9955505Sshin 10055505Sshinstatic int 10155505Sshinlinux_to_bsd_sockopt_level(int level) 10255505Sshin{ 10355505Sshin 10455505Sshin switch (level) { 10555505Sshin case LINUX_SOL_SOCKET: 10655505Sshin return (SOL_SOCKET); 10755505Sshin } 10855505Sshin return (level); 10955505Sshin} 11055505Sshin 11155505Sshinstatic int 112186119Sqinglilinux_to_bsd_ip_sockopt(int opt) 113186119Sqingli{ 114196866Sbz 115186119Sqingli switch (opt) { 116186119Sqingli case LINUX_IP_TOS: 117100650Sjmallett return (IP_TOS); 11862590Sitojun case LINUX_IP_TTL: 11962590Sitojun return (IP_TTL); 12062590Sitojun case LINUX_IP_OPTIONS: 12162590Sitojun return (IP_OPTIONS); 12262590Sitojun case LINUX_IP_MULTICAST_IF: 12355505Sshin return (IP_MULTICAST_IF); 12462590Sitojun case LINUX_IP_MULTICAST_TTL: 12562590Sitojun return (IP_MULTICAST_TTL); 12662590Sitojun case LINUX_IP_MULTICAST_LOOP: 12755505Sshin return (IP_MULTICAST_LOOP); 128173412Skevlo case LINUX_IP_ADD_MEMBERSHIP: 129173412Skevlo return (IP_ADD_MEMBERSHIP); 130173412Skevlo case LINUX_IP_DROP_MEMBERSHIP: 131173412Skevlo return (IP_DROP_MEMBERSHIP); 132173412Skevlo case LINUX_IP_HDRINCL: 133173412Skevlo return (IP_HDRINCL); 134259176Sae } 135173412Skevlo return (-1); 136173412Skevlo} 137173412Skevlo 138173412Skevlostatic int 139173412Skevlolinux_to_bsd_so_sockopt(int opt) 140173412Skevlo{ 141173412Skevlo 142173412Skevlo switch (opt) { 143173412Skevlo case LINUX_SO_DEBUG: 144173412Skevlo return (SO_DEBUG); 145173412Skevlo case LINUX_SO_REUSEADDR: 14662590Sitojun return (SO_REUSEADDR); 147173412Skevlo case LINUX_SO_TYPE: 148173412Skevlo return (SO_TYPE); 14962590Sitojun case LINUX_SO_ERROR: 150173412Skevlo return (SO_ERROR); 151253999Shrs case LINUX_SO_DONTROUTE: 15255505Sshin return (SO_DONTROUTE); 153122615Sume case LINUX_SO_BROADCAST: 15478064Sume return (SO_BROADCAST); 15578064Sume case LINUX_SO_SNDBUF: 15678064Sume return (SO_SNDBUF); 15778064Sume case LINUX_SO_RCVBUF: 15878064Sume return (SO_RCVBUF); 15978064Sume case LINUX_SO_KEEPALIVE: 160122615Sume return (SO_KEEPALIVE); 16178064Sume case LINUX_SO_OOBINLINE: 162122615Sume return (SO_OOBINLINE); 163122615Sume case LINUX_SO_LINGER: 164122615Sume return (SO_LINGER); 16555505Sshin } 166259169Sae return (-1); 16755505Sshin} 16855505Sshin 16955505Sshinstatic int 17055505Sshinlinux_to_bsd_msg_flags(int flags) 17155505Sshin{ 172122615Sume int ret_flags = 0; 173121156Sume 17455505Sshin if (flags & LINUX_MSG_OOB) 17555505Sshin ret_flags |= MSG_OOB; 176122615Sume if (flags & LINUX_MSG_PEEK) 177122615Sume ret_flags |= MSG_PEEK; 178122615Sume if (flags & LINUX_MSG_DONTROUTE) 179122615Sume ret_flags |= MSG_DONTROUTE; 180122615Sume if (flags & LINUX_MSG_CTRUNC) 181122615Sume ret_flags |= MSG_CTRUNC; 182122615Sume if (flags & LINUX_MSG_TRUNC) 183122615Sume ret_flags |= MSG_TRUNC; 184122615Sume if (flags & LINUX_MSG_DONTWAIT) 185122615Sume ret_flags |= MSG_DONTWAIT; 186122615Sume if (flags & LINUX_MSG_EOR) 187122615Sume ret_flags |= MSG_EOR; 188122615Sume if (flags & LINUX_MSG_WAITALL) 18955505Sshin ret_flags |= MSG_WAITALL; 19055505Sshin#if 0 /* not handled */ 191122615Sume if (flags & LINUX_MSG_PROXY) 19255505Sshin ; 193122615Sume if (flags & LINUX_MSG_FIN) 19455505Sshin ; 195122615Sume if (flags & LINUX_MSG_SYN) 196122615Sume ; 197122615Sume if (flags & LINUX_MSG_CONFIRM) 198122615Sume ; 199122615Sume if (flags & LINUX_MSG_RST) 20055505Sshin ; 20155505Sshin if (flags & LINUX_MSG_ERRQUEUE) 20255505Sshin ; 20355505Sshin if (flags & LINUX_MSG_NOSIGNAL) 20455505Sshin ; 20555505Sshin#endif 20655505Sshin return ret_flags; 207122615Sume} 208122615Sume 209122615Sume/* Return 0 if IP_HDRINCL is set for the given socket. */ 210122615Sumestatic int 211122615Sumelinux_check_hdrincl(struct thread *td, int s) 21255505Sshin{ 213122615Sume struct getsockopt_args /* { 21455505Sshin int s; 215122615Sume int level; 216122615Sume int name; 21755505Sshin caddr_t val; 21855505Sshin int *avalsize; 21955505Sshin } */ bsd_args; 22055505Sshin int error; 22155505Sshin caddr_t sg, val, valsize; 22255505Sshin int size_val = sizeof val; 22355505Sshin int optval; 22455505Sshin 225122615Sume sg = stackgap_init(); 226122615Sume val = stackgap_alloc(&sg, sizeof(int)); 227122615Sume valsize = stackgap_alloc(&sg, sizeof(int)); 228122615Sume 22955505Sshin if ((error = copyout(&size_val, valsize, sizeof(size_val)))) 230122615Sume return (error); 231122615Sume 232122615Sume bsd_args.s = s; 233122615Sume bsd_args.level = IPPROTO_IP; 234122615Sume bsd_args.name = IP_HDRINCL; 235122615Sume bsd_args.val = val; 236122615Sume bsd_args.avalsize = (int *)valsize; 237122615Sume if ((error = getsockopt(td, &bsd_args))) 238122615Sume return (error); 239122615Sume 240122615Sume if ((error = copyin(val, &optval, sizeof(optval)))) 241122615Sume return (error); 242122615Sume 243122615Sume return (optval == 0); 244122615Sume} 245122615Sume 246122615Sume/* 247122615Sume * Updated sendto() when IP_HDRINCL is set: 248122615Sume * tweak endian-dependent fields in the IP packet. 249122615Sume */ 250122615Sumestatic int 251122615Sumelinux_sendto_hdrincl(struct thread *td, struct sendto_args *bsd_args) 252122615Sume{ 253122615Sume/* 254122615Sume * linux_ip_copysize defines how many bytes we should copy 255122615Sume * from the beginning of the IP packet before we customize it for BSD. 256122615Sume * It should include all the fields we modify (ip_len and ip_off) 257122615Sume * and be as small as possible to minimize copying overhead. 258122615Sume */ 259122615Sume#define linux_ip_copysize 8 260122615Sume 261122615Sume caddr_t sg; 262122615Sume struct ip *packet; 263122615Sume struct msghdr *msg; 26455505Sshin struct iovec *iov; 265122615Sume 266122615Sume int error; 267122615Sume struct sendmsg_args /* { 268122615Sume int s; 269122615Sume caddr_t msg; 270122615Sume int flags; 271122615Sume } */ sendmsg_args; 272122615Sume 273122615Sume /* Check the packet isn't too small before we mess with it */ 27455505Sshin if (bsd_args->len < linux_ip_copysize) 275122615Sume return (EINVAL); 276122615Sume 27755505Sshin /* 27855505Sshin * Tweaking the user buffer in place would be bad manners. 27955505Sshin * We create a corrected IP header with just the needed length, 280122615Sume * then use an iovec to glue it to the rest of the user packet 281122615Sume * when calling sendmsg(). 282122615Sume */ 283122615Sume sg = stackgap_init(); 284122615Sume packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 28555505Sshin msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 286122615Sume iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 287122615Sume 288122615Sume /* Make a copy of the beginning of the packet to be sent */ 289122615Sume if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize))) 290122615Sume return (error); 291122615Sume 29255505Sshin /* Convert fields from Linux to BSD raw IP socket format */ 293122615Sume packet->ip_len = bsd_args->len; 294122615Sume packet->ip_off = ntohs(packet->ip_off); 295122615Sume 296122615Sume /* Prepare the msghdr and iovec structures describing the new packet */ 297122615Sume msg->msg_name = bsd_args->to; 298122615Sume msg->msg_namelen = bsd_args->tolen; 29955505Sshin msg->msg_iov = iov; 300122615Sume msg->msg_iovlen = 2; 301122615Sume msg->msg_control = NULL; 302122615Sume msg->msg_controllen = 0; 303122615Sume msg->msg_flags = 0; 304122615Sume iov[0].iov_base = (char *)packet; 305122615Sume iov[0].iov_len = linux_ip_copysize; 306122615Sume iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 307122615Sume iov[1].iov_len = bsd_args->len - linux_ip_copysize; 30855505Sshin 30955505Sshin sendmsg_args.s = bsd_args->s; 31055505Sshin sendmsg_args.msg = (caddr_t)msg; 31155505Sshin sendmsg_args.flags = bsd_args->flags; 31255505Sshin return (sendmsg(td, &sendmsg_args)); 31355505Sshin} 31455505Sshin 31555505Sshinstruct linux_socket_args { 316259169Sae int domain; 31755505Sshin int type; 31855505Sshin int protocol; 31955505Sshin}; 32055505Sshin 32155505Sshinstatic int 32255505Sshinlinux_socket(struct thread *td, struct linux_socket_args *args) 32355505Sshin{ 32455505Sshin struct linux_socket_args linux_args; 32555505Sshin struct socket_args /* { 32655505Sshin int domain; 32755505Sshin int type; 32855505Sshin int protocol; 32955505Sshin } */ bsd_args; 33055505Sshin int error; 33155505Sshin int retval_socket; 332167260Skevlo 333122615Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 334122615Sume return (error); 33555505Sshin 33655505Sshin bsd_args.protocol = linux_args.protocol; 33755505Sshin bsd_args.type = linux_args.type; 33855505Sshin bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 33955505Sshin if (bsd_args.domain == -1) 34055505Sshin return (EINVAL); 34155505Sshin 34255505Sshin retval_socket = socket(td, &bsd_args); 34355505Sshin if (bsd_args.type == SOCK_RAW 34455505Sshin && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 34555505Sshin && bsd_args.domain == AF_INET 34655505Sshin && retval_socket >= 0) { 34755505Sshin /* It's a raw IP socket: set the IP_HDRINCL option. */ 34855505Sshin struct setsockopt_args /* { 34955505Sshin int s; 35055505Sshin int level; 35155505Sshin int name; 35255505Sshin caddr_t val; 353121156Sume int valsize; 354121156Sume } */ bsd_setsockopt_args; 35555505Sshin caddr_t sg; 35655505Sshin int *hdrincl; 35755505Sshin 35855505Sshin sg = stackgap_init(); 35962590Sitojun hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 36055505Sshin *hdrincl = 1; 36155505Sshin bsd_setsockopt_args.s = td->td_retval[0]; 362253999Shrs bsd_setsockopt_args.level = IPPROTO_IP; 363253999Shrs bsd_setsockopt_args.name = IP_HDRINCL; 36455505Sshin bsd_setsockopt_args.val = (caddr_t)hdrincl; 36555505Sshin bsd_setsockopt_args.valsize = sizeof(*hdrincl); 36655505Sshin /* We ignore any error returned by setsockopt() */ 36755505Sshin setsockopt(td, &bsd_setsockopt_args); 36855505Sshin /* Copy back the return value from socket() */ 36955505Sshin td->td_retval[0] = bsd_setsockopt_args.s; 37055505Sshin } 37155505Sshin 37255505Sshin return (retval_socket); 373259169Sae} 37455505Sshin 37555505Sshinstruct linux_bind_args { 37655505Sshin int s; 37755505Sshin struct sockaddr *name; 37855505Sshin int namelen; 37955505Sshin}; 38055505Sshin 38155505Sshinstatic int 38255505Sshinlinux_bind(struct thread *td, struct linux_bind_args *args) 38355505Sshin{ 38455505Sshin struct linux_bind_args linux_args; 38555505Sshin struct bind_args /* { 38655505Sshin int s; 38755505Sshin caddr_t name; 38855505Sshin int namelen; 38955505Sshin } */ bsd_args; 39055505Sshin int error; 39155505Sshin 39255505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 39355505Sshin return (error); 39455505Sshin 39555505Sshin bsd_args.s = linux_args.s; 39655505Sshin bsd_args.name = (caddr_t)linux_args.name; 39755505Sshin bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 398243903Shrs return (bind(td, &bsd_args)); 399243903Shrs} 40055505Sshin 40155505Sshinstruct linux_connect_args { 40255505Sshin int s; 40355505Sshin struct sockaddr * name; 40455505Sshin int namelen; 40555505Sshin}; 406253999Shrsint linux_connect(struct thread *, struct linux_connect_args *); 407121156Sume#endif /* !__alpha__*/ 408253999Shrs 409253970Shrsint 41062590Sitojunlinux_connect(struct thread *td, struct linux_connect_args *args) 41162590Sitojun{ 41255505Sshin struct linux_connect_args linux_args; 41355505Sshin struct connect_args /* { 41455505Sshin int s; 415121156Sume caddr_t name; 416121156Sume int namelen; 41755505Sshin } */ bsd_args; 41855505Sshin struct socket *so; 419259171Sae u_int fflag; 42055505Sshin int error; 42155505Sshin 422122615Sume#ifdef __alpha__ 423122615Sume bcopy(args, &linux_args, sizeof(linux_args)); 424122615Sume#else 425122615Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 426210936Sjhb return (error); 427122615Sume#endif /* __alpha__ */ 428122615Sume 42955505Sshin bsd_args.s = linux_args.s; 43062590Sitojun bsd_args.name = (caddr_t)linux_args.name; 43162590Sitojun bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen); 43255505Sshin error = connect(td, &bsd_args); 43362590Sitojun if (error != EISCONN) 43455505Sshin return (error); 43555505Sshin 43655505Sshin /* 43755505Sshin * Linux doesn't return EISCONN the first time it occurs, 43855505Sshin * when on a non-blocking socket. Instead it returns the 43955505Sshin * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 44055505Sshin */ 44155505Sshin if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 44255505Sshin return(error); 44355505Sshin error = EISCONN; 44455505Sshin if (fflag & FNONBLOCK) { 44555505Sshin if (so->so_emuldata == 0) 44655505Sshin error = so->so_error; 44755505Sshin so->so_emuldata = (void *)1; 448259169Sae } 44955505Sshin fputsock(so); 45055505Sshin return (error); 45155505Sshin} 45255505Sshin 45355505Sshin#ifndef __alpha__ 45455505Sshin 45555505Sshinstruct linux_listen_args { 45655505Sshin int s; 45755505Sshin int backlog; 45855505Sshin}; 45955505Sshin 460121156Sumestatic int 46155505Sshinlinux_listen(struct thread *td, struct linux_listen_args *args) 46255505Sshin{ 46355505Sshin struct linux_listen_args linux_args; 464259176Sae struct listen_args /* { 465259176Sae int s; 466259176Sae int backlog; 46755505Sshin } */ bsd_args; 46855505Sshin int error; 469121156Sume 470121156Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 47155505Sshin return (error); 47255505Sshin 47355505Sshin bsd_args.s = linux_args.s; 47455505Sshin bsd_args.backlog = linux_args.backlog; 47555505Sshin return (listen(td, &bsd_args)); 47655505Sshin} 47755505Sshin 47855505Sshinstruct linux_accept_args { 47955505Sshin int s; 480259169Sae struct sockaddr *addr; 48155505Sshin int *namelen; 48255505Sshin}; 48355505Sshin 484186119Sqinglistatic int 48555505Sshinlinux_accept(struct thread *td, struct linux_accept_args *args) 48655505Sshin{ 48755505Sshin struct linux_accept_args linux_args; 48855505Sshin struct accept_args /* { 48955505Sshin int s; 49055505Sshin caddr_t name; 49155505Sshin int *anamelen; 49255505Sshin } */ bsd_args; 49355505Sshin struct fcntl_args /* { 49455505Sshin int fd; 49555505Sshin int cmd; 49655505Sshin long arg; 497121156Sume } */ f_args; 49855505Sshin int error; 49955505Sshin 50055505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 501243903Shrs return (error); 502243903Shrs 50355505Sshin bsd_args.s = linux_args.s; 504121156Sume bsd_args.name = (caddr_t)linux_args.addr; 505121156Sume bsd_args.anamelen = linux_args.namelen; 50655505Sshin error = oaccept(td, &bsd_args); 50755505Sshin if (error) 508259171Sae return (error); 50955505Sshin 51055505Sshin /* 51162590Sitojun * linux appears not to copy flags from the parent socket to the 51278064Sume * accepted one, so we must clear the flags in the new descriptor. 51355505Sshin * Ignore any errors, because we already have an open fd. 51462590Sitojun */ 51562590Sitojun f_args.fd = td->td_retval[0]; 51655505Sshin f_args.cmd = F_SETFL; 51762590Sitojun f_args.arg = 0; 51855505Sshin (void)fcntl(td, &f_args); 51955505Sshin td->td_retval[0] = f_args.fd; 52055505Sshin return (0); 52155505Sshin} 52255505Sshin 523186119Sqinglistruct linux_getsockname_args { 524186119Sqingli int s; 525186119Sqingli struct sockaddr *addr; 526186119Sqingli int *namelen; 527186119Sqingli}; 528186500Sqingli 52955505Sshinstatic int 530243903Shrslinux_getsockname(struct thread *td, struct linux_getsockname_args *args) 531243903Shrs{ 532121156Sume struct linux_getsockname_args linux_args; 533121156Sume struct getsockname_args /* { 53455505Sshin int fdes; 53555505Sshin caddr_t asa; 53655505Sshin int *alen; 53755505Sshin } */ bsd_args; 53855505Sshin int error; 53955505Sshin 540122615Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 54178064Sume return (error); 54278064Sume 54378064Sume bsd_args.fdes = linux_args.s; 54455505Sshin bsd_args.asa = (caddr_t) linux_args.addr; 54555505Sshin bsd_args.alen = linux_args.namelen; 54655505Sshin return (ogetsockname(td, &bsd_args)); 54755505Sshin} 548259176Sae 54955505Sshinstruct linux_getpeername_args { 55055505Sshin int s; 55155505Sshin struct sockaddr *addr; 55262590Sitojun int *namelen; 55355505Sshin}; 55455505Sshin 55555505Sshinstatic int 55655505Sshinlinux_getpeername(struct thread *td, struct linux_getpeername_args *args) 55755505Sshin{ 558253999Shrs struct linux_getpeername_args linux_args; 55955505Sshin struct ogetpeername_args /* { 56078064Sume int fdes; 56178064Sume caddr_t asa; 56262590Sitojun int *alen; 56378064Sume } */ bsd_args; 56455505Sshin int error; 56555505Sshin 56666865Ssumikawa if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 567122615Sume return (error); 56878064Sume 569122615Sume bsd_args.fdes = linux_args.s; 57055505Sshin bsd_args.asa = (caddr_t) linux_args.addr; 57155505Sshin bsd_args.alen = linux_args.namelen; 57255505Sshin return (ogetpeername(td, &bsd_args)); 57355505Sshin} 57455505Sshin 57555505Sshinstruct linux_socketpair_args { 57655505Sshin int domain; 577186119Sqingli int type; 57855505Sshin int protocol; 579186119Sqingli int *rsv; 580186119Sqingli}; 581186119Sqingli 58255505Sshinstatic int 58355505Sshinlinux_socketpair(struct thread *td, struct linux_socketpair_args *args) 58455505Sshin{ 58555505Sshin struct linux_socketpair_args linux_args; 586121156Sume struct socketpair_args /* { 58755505Sshin int domain; 58855505Sshin int type; 58955505Sshin int protocol; 59055505Sshin int *rsv; 59155505Sshin } */ bsd_args; 59255505Sshin int error; 59355505Sshin 59455505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 59555505Sshin return (error); 59655505Sshin 59755505Sshin bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 598259171Sae if (bsd_args.domain == -1) 59978064Sume return (EINVAL); 60078064Sume 60178064Sume bsd_args.type = linux_args.type; 60278064Sume bsd_args.protocol = linux_args.protocol; 60378064Sume bsd_args.rsv = linux_args.rsv; 60478064Sume return (socketpair(td, &bsd_args)); 60578064Sume} 60678064Sume 607121156Sumestruct linux_send_args { 60878064Sume int s; 60978064Sume void *msg; 61078064Sume int len; 61178064Sume int flags; 61278064Sume}; 61378064Sume 61478064Sumestatic int 61578064Sumelinux_send(struct thread *td, struct linux_send_args *args) 616122615Sume{ 617122615Sume struct linux_send_args linux_args; 618122615Sume struct osend_args /* { 61955505Sshin int s; 620259176Sae caddr_t buf; 621259176Sae int len; 622259176Sae int flags; 62355505Sshin } */ bsd_args; 62455505Sshin int error; 62555505Sshin 62655505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 62755505Sshin return (error); 62855505Sshin 62955505Sshin bsd_args.s = linux_args.s; 63055505Sshin bsd_args.buf = linux_args.msg; 63155505Sshin bsd_args.len = linux_args.len; 63255505Sshin bsd_args.flags = linux_args.flags; 63355505Sshin return (osend(td, &bsd_args)); 634121156Sume} 635122615Sume 63681366Ssumikawastruct linux_recv_args { 63781366Ssumikawa int s; 63881366Ssumikawa void *msg; 639122615Sume int len; 640122615Sume int flags; 641122615Sume}; 64281366Ssumikawa 64366865Ssumikawastatic int 64481366Ssumikawalinux_recv(struct thread *td, struct linux_recv_args *args) 64566865Ssumikawa{ 64666865Ssumikawa struct linux_recv_args linux_args; 647253999Shrs struct orecv_args /* { 64855505Sshin int s; 649253970Shrs caddr_t buf; 65055505Sshin int len; 65178064Sume int flags; 65278064Sume } */ bsd_args; 65378064Sume int error; 65478064Sume 65578064Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 65678064Sume return (error); 65778064Sume 65878064Sume bsd_args.s = linux_args.s; 65978064Sume bsd_args.buf = linux_args.msg; 66078064Sume bsd_args.len = linux_args.len; 66178064Sume bsd_args.flags = linux_args.flags; 66278064Sume return (orecv(td, &bsd_args)); 66355505Sshin} 66478064Sume 66578064Sumestruct linux_sendto_args { 66655505Sshin int s; 66755505Sshin void *msg; 66862590Sitojun int len; 66955505Sshin int flags; 670253970Shrs caddr_t to; 67155505Sshin int tolen; 672253970Shrs}; 67378064Sume 67455505Sshinstatic int 67555505Sshinlinux_sendto(struct thread *td, struct linux_sendto_args *args) 67655505Sshin{ 67755505Sshin struct linux_sendto_args linux_args; 678121156Sume struct sendto_args /* { 679121156Sume int s; 68055505Sshin caddr_t buf; 68155505Sshin size_t len; 68278064Sume int flags; 683121156Sume caddr_t to; 68455505Sshin int tolen; 68555505Sshin } */ bsd_args; 68678064Sume int error; 687121156Sume 68855505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 68955505Sshin return (error); 690121156Sume 69155505Sshin bsd_args.s = linux_args.s; 69255505Sshin bsd_args.buf = linux_args.msg; 693121156Sume bsd_args.len = linux_args.len; 69455505Sshin bsd_args.flags = linux_args.flags; 69555505Sshin bsd_args.to = linux_args.to; 696121156Sume bsd_args.tolen = linux_args.tolen; 69755505Sshin 69855505Sshin if (linux_check_hdrincl(td, linux_args.s) == 0) 699121156Sume /* IP_HDRINCL set, tweak the packet before sending */ 70055505Sshin return (linux_sendto_hdrincl(td, &bsd_args)); 70155505Sshin 702121156Sume return (sendto(td, &bsd_args)); 70355505Sshin} 70455505Sshin 70555505Sshinstruct linux_recvfrom_args { 70655505Sshin int s; 70755505Sshin void *buf; 70855505Sshin int len; 70978064Sume int flags; 71055505Sshin caddr_t from; 71155505Sshin int *fromlen; 71255505Sshin}; 71355505Sshin 71462590Sitojunstatic int 71562590Sitojunlinux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 71662590Sitojun{ 71762590Sitojun struct linux_recvfrom_args linux_args; 71862590Sitojun struct recvfrom_args /* { 719121156Sume int s; 720121156Sume caddr_t buf; 72162590Sitojun size_t len; 72262590Sitojun int flags; 723121156Sume caddr_t from; 724122615Sume int *fromlenaddr; 72562590Sitojun } */ bsd_args; 726121156Sume int error; 727121156Sume 728121156Sume if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 729121156Sume return (error); 730122615Sume 731122615Sume bsd_args.s = linux_args.s; 732122615Sume bsd_args.buf = linux_args.buf; 733122615Sume bsd_args.len = linux_args.len; 734122615Sume bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 73555505Sshin bsd_args.from = linux_args.from; 736122615Sume bsd_args.fromlenaddr = linux_args.fromlen; 73755505Sshin return (orecvfrom(td, &bsd_args)); 73855505Sshin} 739122615Sume 74055505Sshinstruct linux_recvmsg_args { 74155505Sshin int s; 74255505Sshin struct msghdr *msg; 74378064Sume int flags; 74478064Sume}; 74555505Sshin 74655505Sshinstatic int 74755505Sshinlinux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 748125675Ssumikawa{ 74955505Sshin struct linux_recvmsg_args linux_args; 75055505Sshin struct recvmsg_args /* { 75155505Sshin int s; 75255505Sshin struct msghdr *msg; 75355505Sshin int flags; 75455505Sshin } */ bsd_args; 755259169Sae int error; 75655505Sshin 75755505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 75855505Sshin return (error); 75955505Sshin 76055505Sshin bsd_args.s = linux_args.s; 76155505Sshin bsd_args.msg = linux_args.msg; 76255505Sshin bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 76355505Sshin return (recvmsg(td, &bsd_args)); 76455505Sshin} 76555505Sshin 76655505Sshinstruct linux_shutdown_args { 76762590Sitojun int s; 76862590Sitojun int how; 76955505Sshin}; 77055505Sshin 77155505Sshinstatic int 77255505Sshinlinux_shutdown(struct thread *td, struct linux_shutdown_args *args) 77355505Sshin{ 77455505Sshin struct linux_shutdown_args linux_args; 77555505Sshin struct shutdown_args /* { 77655505Sshin int s; 77755505Sshin int how; 778217140Sdelphij } */ bsd_args; 77955505Sshin int error; 780121156Sume 781219819Sjeff if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 78255505Sshin return (error); 783219819Sjeff 784217140Sdelphij bsd_args.s = linux_args.s; 785217140Sdelphij bsd_args.how = linux_args.how; 786219819Sjeff return (shutdown(td, &bsd_args)); 787219819Sjeff} 788219819Sjeff 789219819Sjeffstruct linux_setsockopt_args { 790121156Sume int s; 79155505Sshin int level; 792121156Sume int optname; 79355505Sshin void *optval; 79455505Sshin int optlen; 79555505Sshin}; 796259169Sae 79755505Sshinstatic int 79855505Sshinlinux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 79955505Sshin{ 80055505Sshin struct linux_setsockopt_args linux_args; 801121156Sume struct setsockopt_args /* { 80255505Sshin int s; 80355505Sshin int level; 80455505Sshin int name; 80555505Sshin caddr_t val; 806121156Sume int valsize; 80755505Sshin } */ bsd_args; 80855505Sshin int error, name; 80955505Sshin 81055505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 81155505Sshin return (error); 81255505Sshin 81355505Sshin bsd_args.s = linux_args.s; 814122615Sume bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 815122615Sume switch (bsd_args.level) { 81678064Sume case SOL_SOCKET: 817122615Sume name = linux_to_bsd_so_sockopt(linux_args.optname); 818122615Sume break; 819122615Sume case IPPROTO_IP: 82062590Sitojun name = linux_to_bsd_ip_sockopt(linux_args.optname); 821122615Sume break; 82262590Sitojun case IPPROTO_TCP: 823122615Sume /* Linux TCP option values match BSD's */ 82455505Sshin name = linux_args.optname; 82555505Sshin break; 82655505Sshin default: 82755505Sshin name = -1; 828259169Sae break; 82955505Sshin } 83055505Sshin if (name == -1) 83155505Sshin return (EINVAL); 83255505Sshin 83355505Sshin bsd_args.name = name; 83455505Sshin bsd_args.val = linux_args.optval; 83555505Sshin bsd_args.valsize = linux_args.optlen; 83655505Sshin return (setsockopt(td, &bsd_args)); 83755505Sshin} 83855505Sshin 83955505Sshinstruct linux_getsockopt_args { 84055505Sshin int s; 84155505Sshin int level; 84255505Sshin int optname; 84355505Sshin void *optval; 84455505Sshin int *optlen; 84555505Sshin}; 84655505Sshin 84755505Sshinstatic int 84855505Sshinlinux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 849122615Sume{ 850122615Sume struct linux_getsockopt_args linux_args; 851122615Sume struct getsockopt_args /* { 852122615Sume int s; 853186500Sqingli int level; 854151473Ssuz int name; 85562590Sitojun caddr_t val; 85662590Sitojun int *avalsize; 857124241Ssuz } */ bsd_args; 85862590Sitojun int error, name; 859151473Ssuz 86055505Sshin if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 86155505Sshin return (error); 86255505Sshin 86355505Sshin bsd_args.s = linux_args.s; 86455505Sshin bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 86555505Sshin switch (bsd_args.level) { 86655505Sshin case SOL_SOCKET: 867151473Ssuz name = linux_to_bsd_so_sockopt(linux_args.optname); 86862590Sitojun break; 86955505Sshin case IPPROTO_IP: 870151473Ssuz name = linux_to_bsd_ip_sockopt(linux_args.optname); 87155505Sshin break; 87255505Sshin case IPPROTO_TCP: 87355505Sshin /* Linux TCP option values match BSD's */ 87455505Sshin name = linux_args.optname; 87555505Sshin break; 87655505Sshin default: 87755505Sshin name = -1; 87855505Sshin break; 879121156Sume } 880121156Sume if (name == -1) 88155505Sshin return (EINVAL); 88255505Sshin 88355505Sshin bsd_args.name = name; 88455505Sshin bsd_args.val = linux_args.optval; 88555505Sshin bsd_args.avalsize = linux_args.optlen; 88655505Sshin return (getsockopt(td, &bsd_args)); 88755505Sshin} 88855505Sshin 88955505Sshinint 89055505Sshinlinux_socketcall(struct thread *td, struct linux_socketcall_args *args) 89155505Sshin{ 89255505Sshin void *arg = (void *)args->args; 893259169Sae 89455505Sshin switch (args->what) { 89555505Sshin case LINUX_SOCKET: 89662590Sitojun return (linux_socket(td, arg)); 89762590Sitojun case LINUX_BIND: 89878064Sume return (linux_bind(td, arg)); 89978064Sume case LINUX_CONNECT: 90078064Sume return (linux_connect(td, arg)); 90155505Sshin case LINUX_LISTEN: 90255505Sshin return (linux_listen(td, arg)); 903121156Sume case LINUX_ACCEPT: 904121156Sume return (linux_accept(td, arg)); 90555505Sshin case LINUX_GETSOCKNAME: 90655505Sshin return (linux_getsockname(td, arg)); 907121156Sume case LINUX_GETPEERNAME: 90855505Sshin return (linux_getpeername(td, arg)); 909121156Sume case LINUX_SOCKETPAIR: 910121156Sume return (linux_socketpair(td, arg)); 911122615Sume case LINUX_SEND: 91262590Sitojun return (linux_send(td, arg)); 91362590Sitojun case LINUX_RECV: 914122615Sume return (linux_recv(td, arg)); 91562590Sitojun case LINUX_SENDTO: 91662590Sitojun return (linux_sendto(td, arg)); 91762590Sitojun case LINUX_RECVFROM: 91862590Sitojun return (linux_recvfrom(td, arg)); 91962590Sitojun case LINUX_SHUTDOWN: 92062590Sitojun return (linux_shutdown(td, arg)); 92162590Sitojun case LINUX_SETSOCKOPT: 92262590Sitojun return (linux_setsockopt(td, arg)); 92362590Sitojun case LINUX_GETSOCKOPT: 92462590Sitojun return (linux_getsockopt(td, arg)); 92562590Sitojun case LINUX_SENDMSG: 92662590Sitojun do { 92762590Sitojun int error; 92862590Sitojun int level; 92962590Sitojun caddr_t control; 93062590Sitojun struct { 93162590Sitojun int s; 932151468Ssuz const struct msghdr *msg; 933151468Ssuz int flags; 934151468Ssuz } *uap = arg; 935151468Ssuz 936151468Ssuz error = copyin(&uap->msg->msg_control, &control, 937151468Ssuz sizeof(caddr_t)); 938151468Ssuz if (error) 939151468Ssuz return (error); 940151468Ssuz 941151468Ssuz if (control == NULL) 942151468Ssuz goto done; 943151468Ssuz 944151468Ssuz error = copyin(&((struct cmsghdr*)control)->cmsg_level, 945151468Ssuz &level, sizeof(int)); 946151468Ssuz if (error) 947151468Ssuz return (error); 948151468Ssuz 949151468Ssuz if (level == 1) { 950151468Ssuz /* 951151468Ssuz * Linux thinks that SOL_SOCKET is 1; we know 952151468Ssuz * that it's really 0xffff, of course. 953151474Ssuz */ 95462590Sitojun level = SOL_SOCKET; 955118498Sume error = copyout(&level, 956118498Sume &((struct cmsghdr *)control)->cmsg_level, 957118498Sume sizeof(int)); 958197138Shrs if (error) 959197138Shrs return (error); 960197138Shrs } 961245230Sume done: 962245230Sume return (sendmsg(td, arg)); 963245230Sume } while (0); 964151468Ssuz case LINUX_RECVMSG: 965151468Ssuz return (linux_recvmsg(td, arg)); 966151468Ssuz } 96762590Sitojun 96862590Sitojun uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 969151468Ssuz return (ENOSYS); 970151468Ssuz} 971121156Sume#endif /*!__alpha__*/ 97262590Sitojun