linux_socket.c revision 132313
1238104Sdes/*- 2238104Sdes * Copyright (c) 1995 S�ren Schmidt 3238104Sdes * All rights reserved. 4238104Sdes * 5238104Sdes * Redistribution and use in source and binary forms, with or without 6238104Sdes * modification, are permitted provided that the following conditions 7238104Sdes * are met: 8238104Sdes * 1. Redistributions of source code must retain the above copyright 9238104Sdes * notice, this list of conditions and the following disclaimer 10238104Sdes * in this position and unchanged. 11238104Sdes * 2. Redistributions in binary form must reproduce the above copyright 12238104Sdes * notice, this list of conditions and the following disclaimer in the 13238104Sdes * documentation and/or other materials provided with the distribution. 14238104Sdes * 3. The name of the author may not be used to endorse or promote products 15238104Sdes * derived from this software without specific prior written permission 16238104Sdes * 17238104Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18238104Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19238104Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20238104Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21238104Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22238104Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23238104Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24238104Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25238104Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26238104Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27238104Sdes */ 28238104Sdes 29238104Sdes#include <sys/cdefs.h> 30238104Sdes__FBSDID("$FreeBSD: head/sys/compat/linux/linux_socket.c 132313 2004-07-17 21:06:36Z dwmalone $"); 31238104Sdes 32238104Sdes/* XXX we use functions that might not exist. */ 33238104Sdes#include "opt_compat.h" 34238104Sdes#include "opt_inet6.h" 35238104Sdes 36238104Sdes#ifndef COMPAT_43 37238104Sdes#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!" 38238104Sdes#endif 39238104Sdes 40238104Sdes#include <sys/param.h> 41238104Sdes#include <sys/proc.h> 42238104Sdes#include <sys/systm.h> 43238104Sdes#include <sys/sysproto.h> 44238104Sdes#include <sys/fcntl.h> 45238104Sdes#include <sys/file.h> 46238104Sdes#include <sys/limits.h> 47238104Sdes#include <sys/malloc.h> 48238104Sdes#include <sys/mbuf.h> 49238104Sdes#include <sys/socket.h> 50238104Sdes#include <sys/socketvar.h> 51238104Sdes#include <sys/syscallsubr.h> 52238104Sdes#include <sys/uio.h> 53238104Sdes#include <sys/syslog.h> 54238104Sdes 55238104Sdes#include <netinet/in.h> 56238104Sdes#include <netinet/in_systm.h> 57238104Sdes#include <netinet/ip.h> 58238104Sdes#ifdef INET6 59238104Sdes#include <netinet/ip6.h> 60238104Sdes#include <netinet6/ip6_var.h> 61238104Sdes#endif 62238104Sdes 63238104Sdes#include <machine/../linux/linux.h> 64238104Sdes#include <machine/../linux/linux_proto.h> 65238104Sdes#include <compat/linux/linux_socket.h> 66238104Sdes#include <compat/linux/linux_util.h> 67238104Sdes 68238104Sdesstatic int do_sa_get(struct sockaddr **, const struct osockaddr *, int *, 69238104Sdes struct malloc_type *); 70238104Sdesstatic int linux_to_bsd_domain(int); 71238104Sdes 72238104Sdes/* 73238104Sdes * Reads a linux sockaddr and does any necessary translation. 74238104Sdes * Linux sockaddrs don't have a length field, only a family. 75238104Sdes */ 76238104Sdesstatic int 77238104Sdeslinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len) 78238104Sdes{ 79238104Sdes int osalen = len; 80238104Sdes 81238104Sdes return (do_sa_get(sap, osa, &osalen, M_SONAME)); 82238104Sdes} 83238104Sdes 84238104Sdes/* 85238104Sdes * Copy the osockaddr structure pointed to by osa to kernel, adjust 86238104Sdes * family and convert to sockaddr. 87238104Sdes */ 88238104Sdesstatic int 89238104Sdesdo_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen, 90238104Sdes struct malloc_type *mtype) 91238104Sdes{ 92238104Sdes int error=0, bdom; 93238104Sdes struct sockaddr *sa; 94238104Sdes struct osockaddr *kosa; 95238104Sdes int alloclen; 96238104Sdes#ifdef INET6 97238104Sdes int oldv6size; 98238104Sdes struct sockaddr_in6 *sin6; 99238104Sdes#endif 100238104Sdes 101238104Sdes if (*osalen < 2 || *osalen > UCHAR_MAX || !osa) 102238104Sdes return (EINVAL); 103238104Sdes 104238104Sdes alloclen = *osalen; 105238104Sdes#ifdef INET6 106238104Sdes oldv6size = 0; 107238104Sdes /* 108238104Sdes * Check for old (pre-RFC2553) sockaddr_in6. We may accept it 109238104Sdes * if it's a v4-mapped address, so reserve the proper space 110238104Sdes * for it. 111238104Sdes */ 112238104Sdes if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) { 113238104Sdes alloclen = sizeof (struct sockaddr_in6); 114238104Sdes oldv6size = 1; 115238104Sdes } 116238104Sdes#endif 117238104Sdes 118238104Sdes MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK); 119238104Sdes 120238104Sdes if ((error = copyin(osa, kosa, *osalen))) 121238104Sdes goto out; 122238104Sdes 123238104Sdes bdom = linux_to_bsd_domain(kosa->sa_family); 124238104Sdes if (bdom == -1) { 125238104Sdes error = EINVAL; 126238104Sdes goto out; 127238104Sdes } 128238104Sdes 129238104Sdes#ifdef INET6 130238104Sdes /* 131238104Sdes * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6, 132238104Sdes * which lacks the scope id compared with RFC2553 one. If we detect 133238104Sdes * the situation, reject the address and write a message to system log. 134238104Sdes * 135238104Sdes * Still accept addresses for which the scope id is not used. 136238104Sdes */ 137238104Sdes if (oldv6size && bdom == AF_INET6) { 138238104Sdes sin6 = (struct sockaddr_in6 *)kosa; 139238104Sdes if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) || 140238104Sdes (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 141238104Sdes !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && 142238104Sdes !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) && 143238104Sdes !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 144238104Sdes !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) { 145238104Sdes sin6->sin6_scope_id = 0; 146238104Sdes } else { 147238104Sdes log(LOG_DEBUG, 148238104Sdes "obsolete pre-RFC2553 sockaddr_in6 rejected"); 149238104Sdes error = EINVAL; 150238104Sdes goto out; 151238104Sdes } 152238104Sdes } else 153238104Sdes#endif 154238104Sdes if (bdom == AF_INET) 155238104Sdes alloclen = sizeof(struct sockaddr_in); 156238104Sdes 157238104Sdes sa = (struct sockaddr *) kosa; 158238104Sdes sa->sa_family = bdom; 159238104Sdes sa->sa_len = alloclen; 160238104Sdes 161238104Sdes *sap = sa; 162238104Sdes *osalen = alloclen; 163238104Sdes return (0); 164238104Sdes 165238104Sdesout: 166238104Sdes FREE(kosa, mtype); 167238104Sdes return (error); 168238104Sdes} 169238104Sdes 170238104Sdesstatic int 171238104Sdeslinux_to_bsd_domain(int domain) 172238104Sdes{ 173238104Sdes 174238104Sdes switch (domain) { 175238104Sdes case LINUX_AF_UNSPEC: 176238104Sdes return (AF_UNSPEC); 177238104Sdes case LINUX_AF_UNIX: 178238104Sdes return (AF_LOCAL); 179238104Sdes case LINUX_AF_INET: 180238104Sdes return (AF_INET); 181238104Sdes case LINUX_AF_INET6: 182238104Sdes return (AF_INET6); 183238104Sdes case LINUX_AF_AX25: 184238104Sdes return (AF_CCITT); 185238104Sdes case LINUX_AF_IPX: 186238104Sdes return (AF_IPX); 187238104Sdes case LINUX_AF_APPLETALK: 188238104Sdes return (AF_APPLETALK); 189238104Sdes } 190238104Sdes return (-1); 191238104Sdes} 192238104Sdes 193238104Sdes#ifndef __alpha__ 194238104Sdesstatic int 195238104Sdesbsd_to_linux_domain(int domain) 196238104Sdes{ 197238104Sdes 198238104Sdes switch (domain) { 199238104Sdes case AF_UNSPEC: 200238104Sdes return (LINUX_AF_UNSPEC); 201238104Sdes case AF_LOCAL: 202238104Sdes return (LINUX_AF_UNIX); 203238104Sdes case AF_INET: 204238104Sdes return (LINUX_AF_INET); 205238104Sdes case AF_INET6: 206238104Sdes return (LINUX_AF_INET6); 207238104Sdes case AF_CCITT: 208238104Sdes return (LINUX_AF_AX25); 209238104Sdes case AF_IPX: 210238104Sdes return (LINUX_AF_IPX); 211238104Sdes case AF_APPLETALK: 212238104Sdes return (LINUX_AF_APPLETALK); 213238104Sdes } 214238104Sdes return (-1); 215238104Sdes} 216238104Sdes 217238104Sdesstatic int 218238104Sdeslinux_to_bsd_sockopt_level(int level) 219238104Sdes{ 220238104Sdes 221238104Sdes switch (level) { 222238104Sdes case LINUX_SOL_SOCKET: 223238104Sdes return (SOL_SOCKET); 224238104Sdes } 225238104Sdes return (level); 226238104Sdes} 227238104Sdes 228238104Sdesstatic int 229238104Sdesbsd_to_linux_sockopt_level(int level) 230238104Sdes{ 231238104Sdes 232238104Sdes switch (level) { 233238104Sdes case SOL_SOCKET: 234238104Sdes return (LINUX_SOL_SOCKET); 235238104Sdes } 236238104Sdes return (level); 237238104Sdes} 238238104Sdes 239238104Sdesstatic int 240238104Sdeslinux_to_bsd_ip_sockopt(int opt) 241238104Sdes{ 242238104Sdes 243238104Sdes switch (opt) { 244238104Sdes case LINUX_IP_TOS: 245238104Sdes return (IP_TOS); 246238104Sdes case LINUX_IP_TTL: 247238104Sdes return (IP_TTL); 248238104Sdes case LINUX_IP_OPTIONS: 249238104Sdes return (IP_OPTIONS); 250238104Sdes case LINUX_IP_MULTICAST_IF: 251238104Sdes return (IP_MULTICAST_IF); 252238104Sdes case LINUX_IP_MULTICAST_TTL: 253238104Sdes return (IP_MULTICAST_TTL); 254238104Sdes case LINUX_IP_MULTICAST_LOOP: 255238104Sdes return (IP_MULTICAST_LOOP); 256238104Sdes case LINUX_IP_ADD_MEMBERSHIP: 257238104Sdes return (IP_ADD_MEMBERSHIP); 258238104Sdes case LINUX_IP_DROP_MEMBERSHIP: 259238104Sdes return (IP_DROP_MEMBERSHIP); 260238104Sdes case LINUX_IP_HDRINCL: 261238104Sdes return (IP_HDRINCL); 262238104Sdes } 263238104Sdes return (-1); 264238104Sdes} 265238104Sdes 266238104Sdesstatic int 267238104Sdeslinux_to_bsd_so_sockopt(int opt) 268238104Sdes{ 269238104Sdes 270238104Sdes switch (opt) { 271238104Sdes case LINUX_SO_DEBUG: 272238104Sdes return (SO_DEBUG); 273238104Sdes case LINUX_SO_REUSEADDR: 274238104Sdes return (SO_REUSEADDR); 275238104Sdes case LINUX_SO_TYPE: 276238104Sdes return (SO_TYPE); 277238104Sdes case LINUX_SO_ERROR: 278238104Sdes return (SO_ERROR); 279238104Sdes case LINUX_SO_DONTROUTE: 280238104Sdes return (SO_DONTROUTE); 281238104Sdes case LINUX_SO_BROADCAST: 282238104Sdes return (SO_BROADCAST); 283238104Sdes case LINUX_SO_SNDBUF: 284238104Sdes return (SO_SNDBUF); 285238104Sdes case LINUX_SO_RCVBUF: 286238104Sdes return (SO_RCVBUF); 287238104Sdes case LINUX_SO_KEEPALIVE: 288238104Sdes return (SO_KEEPALIVE); 289238104Sdes case LINUX_SO_OOBINLINE: 290238104Sdes return (SO_OOBINLINE); 291238104Sdes case LINUX_SO_LINGER: 292238104Sdes return (SO_LINGER); 293238104Sdes } 294238104Sdes return (-1); 295238104Sdes} 296238104Sdes 297238104Sdesstatic int 298238104Sdeslinux_to_bsd_msg_flags(int flags) 299238104Sdes{ 300238104Sdes int ret_flags = 0; 301238104Sdes 302238104Sdes if (flags & LINUX_MSG_OOB) 303238104Sdes ret_flags |= MSG_OOB; 304238104Sdes if (flags & LINUX_MSG_PEEK) 305238104Sdes ret_flags |= MSG_PEEK; 306238104Sdes if (flags & LINUX_MSG_DONTROUTE) 307238104Sdes ret_flags |= MSG_DONTROUTE; 308238104Sdes if (flags & LINUX_MSG_CTRUNC) 309238104Sdes ret_flags |= MSG_CTRUNC; 310238104Sdes if (flags & LINUX_MSG_TRUNC) 311238104Sdes ret_flags |= MSG_TRUNC; 312238104Sdes if (flags & LINUX_MSG_DONTWAIT) 313238104Sdes ret_flags |= MSG_DONTWAIT; 314238104Sdes if (flags & LINUX_MSG_EOR) 315238104Sdes ret_flags |= MSG_EOR; 316238104Sdes if (flags & LINUX_MSG_WAITALL) 317238104Sdes ret_flags |= MSG_WAITALL; 318238104Sdes#if 0 /* not handled */ 319238104Sdes if (flags & LINUX_MSG_PROXY) 320238104Sdes ; 321238104Sdes if (flags & LINUX_MSG_FIN) 322238104Sdes ; 323238104Sdes if (flags & LINUX_MSG_SYN) 324238104Sdes ; 325238104Sdes if (flags & LINUX_MSG_CONFIRM) 326238104Sdes ; 327238104Sdes if (flags & LINUX_MSG_RST) 328238104Sdes ; 329238104Sdes if (flags & LINUX_MSG_ERRQUEUE) 330238104Sdes ; 331238104Sdes if (flags & LINUX_MSG_NOSIGNAL) 332238104Sdes ; 333238104Sdes#endif 334238104Sdes return ret_flags; 335238104Sdes} 336238104Sdes 337238104Sdesstatic int 338238104Sdeslinux_sa_put(struct osockaddr *osa) 339238104Sdes{ 340238104Sdes struct osockaddr sa; 341238104Sdes int error, bdom; 342238104Sdes 343238104Sdes /* 344238104Sdes * Only read/write the osockaddr family part, the rest is 345238104Sdes * not changed. 346238104Sdes */ 347238104Sdes error = copyin(osa, &sa, sizeof(sa.sa_family)); 348238104Sdes if (error) 349238104Sdes return (error); 350238104Sdes 351238104Sdes bdom = bsd_to_linux_domain(sa.sa_family); 352238104Sdes if (bdom == -1) 353238104Sdes return (EINVAL); 354238104Sdes 355238104Sdes sa.sa_family = bdom; 356238104Sdes error = copyout(&sa, osa, sizeof(sa.sa_family)); 357238104Sdes if (error) 358238104Sdes return (error); 359238104Sdes 360238104Sdes return (0); 361238104Sdes} 362238104Sdes 363238104Sdesstatic int 364238104Sdeslinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags) 365238104Sdes{ 366238104Sdes struct mbuf *control; 367238104Sdes struct sockaddr *to; 368238104Sdes int error; 369238104Sdes 370238104Sdes if (mp->msg_name != NULL) { 371238104Sdes error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen); 372238104Sdes if (error) 373238104Sdes return (error); 374238104Sdes mp->msg_name = to; 375238104Sdes } else 376238104Sdes to = NULL; 377238104Sdes 378238104Sdes if (mp->msg_control != NULL) { 379238104Sdes struct cmsghdr *cmsg; 380238104Sdes 381238104Sdes if (mp->msg_controllen < sizeof(struct cmsghdr)) { 382238104Sdes error = EINVAL; 383238104Sdes goto bad; 384238104Sdes } 385238104Sdes error = sockargs(&control, mp->msg_control, 386238104Sdes mp->msg_controllen, MT_CONTROL); 387238104Sdes if (error) 388238104Sdes goto bad; 389238104Sdes 390238104Sdes cmsg = mtod(control, struct cmsghdr *); 391238104Sdes cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level); 392238104Sdes } else 393238104Sdes control = NULL; 394238104Sdes 395238104Sdes error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control); 396238104Sdes 397238104Sdesbad: 398238104Sdes if (to) 399238104Sdes FREE(to, M_SONAME); 400238104Sdes return (error); 401238104Sdes} 402238104Sdes 403238104Sdes/* Return 0 if IP_HDRINCL is set for the given socket. */ 404238104Sdesstatic int 405238104Sdeslinux_check_hdrincl(struct thread *td, int s) 406238104Sdes{ 407238104Sdes int error, optval, size_val; 408238104Sdes 409238104Sdes size_val = sizeof(optval); 410238104Sdes error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL, 411238104Sdes &optval, UIO_SYSSPACE, &size_val); 412238104Sdes if (error) 413238104Sdes return (error); 414238104Sdes 415238104Sdes return (optval == 0); 416238104Sdes} 417238104Sdes 418238104Sdesstruct linux_sendto_args { 419238104Sdes int s; 420238104Sdes void *msg; 421238104Sdes int len; 422238104Sdes int flags; 423238104Sdes caddr_t to; 424238104Sdes int tolen; 425238104Sdes}; 426238104Sdes 427238104Sdes/* 428238104Sdes * Updated sendto() when IP_HDRINCL is set: 429238104Sdes * tweak endian-dependent fields in the IP packet. 430238104Sdes */ 431238104Sdesstatic int 432238104Sdeslinux_sendto_hdrincl(struct thread *td, caddr_t *sg, struct linux_sendto_args *linux_args) 433238104Sdes{ 434238104Sdes/* 435238104Sdes * linux_ip_copysize defines how many bytes we should copy 436238104Sdes * from the beginning of the IP packet before we customize it for BSD. 437238104Sdes * It should include all the fields we modify (ip_len and ip_off) 438238104Sdes * and be as small as possible to minimize copying overhead. 439238104Sdes */ 440238104Sdes#define linux_ip_copysize 8 441238104Sdes 442238104Sdes struct ip *packet; 443238104Sdes caddr_t sg = stackgap_init(); 444238104Sdes struct msghdr msg; 445238104Sdes struct iovec aiov[2]; 446238104Sdes int error; 447238104Sdes 448238104Sdes /* Check the packet isn't too small before we mess with it */ 449238104Sdes if (linux_args->len < linux_ip_copysize) 450238104Sdes return (EINVAL); 451238104Sdes 452238104Sdes /* 453238104Sdes * Tweaking the user buffer in place would be bad manners. 454238104Sdes * We create a corrected IP header with just the needed length, 455238104Sdes * then use an iovec to glue it to the rest of the user packet 456238104Sdes * when calling sendit(). 457238104Sdes */ 458238104Sdes packet = (struct ip *)stackgap_alloc(sg, linux_ip_copysize); 459238104Sdes 460238104Sdes /* Make a copy of the beginning of the packet to be sent */ 461238104Sdes if ((error = copyin(linux_args->msg, packet, linux_ip_copysize))) 462238104Sdes return (error); 463238104Sdes 464238104Sdes /* Convert fields from Linux to BSD raw IP socket format */ 465238104Sdes packet->ip_len = linux_args->len; 466238104Sdes packet->ip_off = ntohs(packet->ip_off); 467238104Sdes 468238104Sdes /* Prepare the msghdr and iovec structures describing the new packet */ 469238104Sdes msg.msg_name = linux_args->to; 470238104Sdes msg.msg_namelen = linux_args->tolen; 471238104Sdes msg.msg_iov = aiov; 472238104Sdes msg.msg_iovlen = 2; 473238104Sdes msg.msg_control = NULL; 474238104Sdes msg.msg_flags = 0; 475238104Sdes aiov[0].iov_base = (char *)packet; 476238104Sdes aiov[0].iov_len = linux_ip_copysize; 477238104Sdes aiov[1].iov_base = (char *)(linux_args->msg) + linux_ip_copysize; 478238104Sdes aiov[1].iov_len = linux_args->len - linux_ip_copysize; 479238104Sdes error = linux_sendit(td, linux_args->s, &msg, linux_args->flags); 480238104Sdes return (error); 481238104Sdes} 482238104Sdes 483238104Sdesstruct linux_socket_args { 484238104Sdes int domain; 485238104Sdes int type; 486238104Sdes int protocol; 487238104Sdes}; 488238104Sdes 489238104Sdesstatic int 490238104Sdeslinux_socket(struct thread *td, struct linux_socket_args *args) 491238104Sdes{ 492238104Sdes struct linux_socket_args linux_args; 493238104Sdes struct socket_args /* { 494238104Sdes int domain; 495238104Sdes int type; 496238104Sdes int protocol; 497238104Sdes } */ bsd_args; 498238104Sdes int error; 499238104Sdes int retval_socket; 500238104Sdes 501238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 502238104Sdes return (error); 503238104Sdes 504238104Sdes bsd_args.protocol = linux_args.protocol; 505238104Sdes bsd_args.type = linux_args.type; 506238104Sdes bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 507238104Sdes if (bsd_args.domain == -1) 508238104Sdes return (EINVAL); 509238104Sdes 510238104Sdes retval_socket = socket(td, &bsd_args); 511238104Sdes if (bsd_args.type == SOCK_RAW 512238104Sdes && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 513238104Sdes && bsd_args.domain == AF_INET 514238104Sdes && retval_socket >= 0) { 515238104Sdes /* It's a raw IP socket: set the IP_HDRINCL option. */ 516238104Sdes int hdrincl; 517238104Sdes 518238104Sdes hdrincl = 1; 519238104Sdes /* We ignore any error returned by kern_setsockopt() */ 520238104Sdes kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, 521238104Sdes &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); 522238104Sdes } 523238104Sdes#ifdef INET6 524238104Sdes /* 525238104Sdes * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by 526238104Sdes * default and some apps depend on this. So, set V6ONLY to 0 527238104Sdes * for Linux apps if the sysctl value is set to 1. 528238104Sdes */ 529238104Sdes if (bsd_args.domain == PF_INET6 && retval_socket >= 0 530238104Sdes#ifndef KLD_MODULE 531238104Sdes /* 532238104Sdes * XXX: Avoid undefined symbol error with an IPv4 only 533238104Sdes * kernel. 534238104Sdes */ 535238104Sdes && ip6_v6only 536238104Sdes#endif 537238104Sdes ) { 538238104Sdes int v6only; 539238104Sdes 540238104Sdes v6only = 0; 541238104Sdes /* We ignore any error returned by setsockopt() */ 542238104Sdes kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, 543238104Sdes &v6only, UIO_SYSSPACE, sizeof(v6only)); 544238104Sdes } 545238104Sdes#endif 546238104Sdes 547238104Sdes return (retval_socket); 548238104Sdes} 549238104Sdes 550238104Sdesstruct linux_bind_args { 551238104Sdes int s; 552238104Sdes struct osockaddr *name; 553238104Sdes int namelen; 554238104Sdes}; 555238104Sdes 556238104Sdesstatic int 557238104Sdeslinux_bind(struct thread *td, struct linux_bind_args *args) 558238104Sdes{ 559238104Sdes struct linux_bind_args linux_args; 560238104Sdes struct sockaddr *sa; 561238104Sdes int error; 562238104Sdes 563238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 564238104Sdes return (error); 565238104Sdes 566238104Sdes error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen); 567238104Sdes if (error) 568238104Sdes return (error); 569238104Sdes 570238104Sdes return (kern_bind(td, linux_args.s, sa)); 571238104Sdes} 572238104Sdes 573238104Sdesstruct linux_connect_args { 574238104Sdes int s; 575238104Sdes struct osockaddr * name; 576238104Sdes int namelen; 577238104Sdes}; 578238104Sdesint linux_connect(struct thread *, struct linux_connect_args *); 579238104Sdes#endif /* !__alpha__*/ 580238104Sdes 581238104Sdesint 582238104Sdeslinux_connect(struct thread *td, struct linux_connect_args *args) 583238104Sdes{ 584238104Sdes struct linux_connect_args linux_args; 585238104Sdes struct socket *so; 586238104Sdes struct sockaddr *sa; 587238104Sdes u_int fflag; 588238104Sdes int error; 589238104Sdes 590238104Sdes#ifdef __alpha__ 591238104Sdes bcopy(args, &linux_args, sizeof(linux_args)); 592238104Sdes#else 593238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 594238104Sdes return (error); 595238104Sdes#endif /* __alpha__ */ 596238104Sdes 597238104Sdes error = linux_getsockaddr(&sa, (struct osockaddr *)linux_args.name, 598238104Sdes linux_args.namelen); 599238104Sdes if (error) 600238104Sdes return (error); 601238104Sdes 602238104Sdes error = kern_connect(td, linux_args.s, sa); 603238104Sdes if (error != EISCONN) 604238104Sdes return (error); 605238104Sdes 606238104Sdes /* 607238104Sdes * Linux doesn't return EISCONN the first time it occurs, 608238104Sdes * when on a non-blocking socket. Instead it returns the 609238104Sdes * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. 610238104Sdes */ 611238104Sdes if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0) 612238104Sdes return(error); 613238104Sdes error = EISCONN; 614238104Sdes if (fflag & FNONBLOCK) { 615238104Sdes if (so->so_emuldata == 0) 616238104Sdes error = so->so_error; 617238104Sdes so->so_emuldata = (void *)1; 618238104Sdes } 619238104Sdes fputsock(so); 620238104Sdes return (error); 621238104Sdes} 622238104Sdes 623238104Sdes#ifndef __alpha__ 624238104Sdes 625238104Sdesstruct linux_listen_args { 626238104Sdes int s; 627238104Sdes int backlog; 628238104Sdes}; 629238104Sdes 630238104Sdesstatic int 631238104Sdeslinux_listen(struct thread *td, struct linux_listen_args *args) 632238104Sdes{ 633238104Sdes struct linux_listen_args linux_args; 634238104Sdes struct listen_args /* { 635238104Sdes int s; 636238104Sdes int backlog; 637238104Sdes } */ bsd_args; 638238104Sdes int error; 639238104Sdes 640238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 641238104Sdes return (error); 642238104Sdes 643238104Sdes bsd_args.s = linux_args.s; 644238104Sdes bsd_args.backlog = linux_args.backlog; 645238104Sdes return (listen(td, &bsd_args)); 646238104Sdes} 647238104Sdes 648238104Sdesstruct linux_accept_args { 649238104Sdes int s; 650238104Sdes struct osockaddr *addr; 651238104Sdes int *namelen; 652238104Sdes}; 653238104Sdes 654238104Sdesstatic int 655238104Sdeslinux_accept(struct thread *td, struct linux_accept_args *args) 656238104Sdes{ 657269257Sdes struct linux_accept_args linux_args; 658269257Sdes struct accept_args /* { 659269257Sdes int s; 660269257Sdes struct sockaddr * __restrict name; 661269257Sdes socklen_t * __restrict anamelen; 662269257Sdes } */ bsd_args; 663269257Sdes struct close_args /* { 664269257Sdes int fd; 665269257Sdes } */ c_args; 666269257Sdes struct fcntl_args /* { 667269257Sdes int fd; 668269257Sdes int cmd; 669269257Sdes long arg; 670269257Sdes } */ f_args; 671269257Sdes int error; 672269257Sdes 673269257Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 674269257Sdes return (error); 675269257Sdes 676269257Sdes bsd_args.s = linux_args.s; 677269257Sdes /* XXX: */ 678269257Sdes bsd_args.name = (struct sockaddr * __restrict)linux_args.addr; 679269257Sdes bsd_args.anamelen = linux_args.namelen; /* XXX */ 680269257Sdes error = oaccept(td, &bsd_args); 681269257Sdes if (error) 682269257Sdes return (error); 683269257Sdes if (linux_args.addr) { 684238104Sdes error = linux_sa_put(linux_args.addr); 685238104Sdes if (error) { 686238104Sdes c_args.fd = td->td_retval[0]; 687238104Sdes (void)close(td, &c_args); 688238104Sdes return (error); 689269257Sdes } 690269257Sdes } 691269257Sdes 692269257Sdes /* 693269257Sdes * linux appears not to copy flags from the parent socket to the 694269257Sdes * accepted one, so we must clear the flags in the new descriptor. 695269257Sdes * Ignore any errors, because we already have an open fd. 696269257Sdes */ 697269257Sdes f_args.fd = td->td_retval[0]; 698238104Sdes f_args.cmd = F_SETFL; 699269257Sdes f_args.arg = 0; 700269257Sdes (void)fcntl(td, &f_args); 701269257Sdes td->td_retval[0] = f_args.fd; 702269257Sdes return (0); 703238104Sdes} 704238104Sdes 705238104Sdesstruct linux_getsockname_args { 706238104Sdes int s; 707238104Sdes struct osockaddr *addr; 708238104Sdes int *namelen; 709269257Sdes}; 710269257Sdes 711269257Sdesstatic int 712269257Sdeslinux_getsockname(struct thread *td, struct linux_getsockname_args *args) 713269257Sdes{ 714269257Sdes struct linux_getsockname_args linux_args; 715269257Sdes struct getsockname_args /* { 716269257Sdes int fdes; 717238104Sdes struct sockaddr * __restrict asa; 718238104Sdes socklen_t * __restrict alen; 719269257Sdes } */ bsd_args; 720269257Sdes int error; 721269257Sdes 722269257Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 723269257Sdes return (error); 724269257Sdes 725269257Sdes bsd_args.fdes = linux_args.s; 726238104Sdes /* XXX: */ 727269257Sdes bsd_args.asa = (struct sockaddr * __restrict)linux_args.addr; 728269257Sdes bsd_args.alen = linux_args.namelen; /* XXX */ 729269257Sdes error = ogetsockname(td, &bsd_args); 730269257Sdes if (error) 731269257Sdes return (error); 732269257Sdes error = linux_sa_put(linux_args.addr); 733269257Sdes if (error) 734269257Sdes return (error); 735269257Sdes return (0); 736269257Sdes} 737269257Sdes 738238104Sdesstruct linux_getpeername_args { 739269257Sdes int s; 740269257Sdes struct osockaddr *addr; 741269257Sdes int *namelen; 742269257Sdes}; 743238104Sdes 744269257Sdesstatic int 745238104Sdeslinux_getpeername(struct thread *td, struct linux_getpeername_args *args) 746238104Sdes{ 747238104Sdes struct linux_getpeername_args linux_args; 748269257Sdes struct ogetpeername_args /* { 749269257Sdes int fdes; 750269257Sdes caddr_t asa; 751269257Sdes int *alen; 752269257Sdes } */ bsd_args; 753269257Sdes int error; 754238104Sdes 755238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 756269257Sdes return (error); 757269257Sdes 758269257Sdes bsd_args.fdes = linux_args.s; 759269257Sdes bsd_args.asa = (caddr_t) linux_args.addr; 760269257Sdes bsd_args.alen = linux_args.namelen; 761269257Sdes error = ogetpeername(td, &bsd_args); 762269257Sdes if (error) 763269257Sdes return (error); 764238104Sdes error = linux_sa_put(linux_args.addr); 765238104Sdes if (error) 766238104Sdes return (error); 767238104Sdes return (0); 768238104Sdes} 769238104Sdes 770238104Sdesstruct linux_socketpair_args { 771238104Sdes int domain; 772238104Sdes int type; 773238104Sdes int protocol; 774238104Sdes int *rsv; 775238104Sdes}; 776238104Sdes 777238104Sdesstatic int 778238104Sdeslinux_socketpair(struct thread *td, struct linux_socketpair_args *args) 779238104Sdes{ 780238104Sdes struct linux_socketpair_args linux_args; 781238104Sdes struct socketpair_args /* { 782238104Sdes int domain; 783238104Sdes int type; 784238104Sdes int protocol; 785238104Sdes int *rsv; 786238104Sdes } */ bsd_args; 787238104Sdes int error; 788238104Sdes 789238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 790238104Sdes return (error); 791238104Sdes 792238104Sdes bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 793238104Sdes if (bsd_args.domain == -1) 794238104Sdes return (EINVAL); 795238104Sdes 796238104Sdes bsd_args.type = linux_args.type; 797238104Sdes bsd_args.protocol = linux_args.protocol; 798238104Sdes bsd_args.rsv = linux_args.rsv; 799238104Sdes return (socketpair(td, &bsd_args)); 800238104Sdes} 801238104Sdes 802238104Sdesstruct linux_send_args { 803238104Sdes int s; 804238104Sdes void *msg; 805238104Sdes int len; 806238104Sdes int flags; 807238104Sdes}; 808238104Sdes 809238104Sdesstatic int 810238104Sdeslinux_send(struct thread *td, struct linux_send_args *args) 811238104Sdes{ 812238104Sdes struct linux_send_args linux_args; 813238104Sdes struct sendto_args /* { 814238104Sdes int s; 815238104Sdes caddr_t buf; 816238104Sdes int len; 817238104Sdes int flags; 818238104Sdes caddr_t to; 819238104Sdes int tolen; 820238104Sdes } */ bsd_args; 821238104Sdes int error; 822238104Sdes 823238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 824238104Sdes return (error); 825238104Sdes 826238104Sdes bsd_args.s = linux_args.s; 827238104Sdes bsd_args.buf = linux_args.msg; 828238104Sdes bsd_args.len = linux_args.len; 829238104Sdes bsd_args.flags = linux_args.flags; 830238104Sdes bsd_args.to = NULL; 831238104Sdes bsd_args.tolen = 0; 832238104Sdes return (sendto(td, &bsd_args)); 833238104Sdes} 834238104Sdes 835238104Sdesstruct linux_recv_args { 836238104Sdes int s; 837238104Sdes void *msg; 838238104Sdes int len; 839238104Sdes int flags; 840238104Sdes}; 841238104Sdes 842238104Sdesstatic int 843238104Sdeslinux_recv(struct thread *td, struct linux_recv_args *args) 844238104Sdes{ 845238104Sdes struct linux_recv_args linux_args; 846238104Sdes struct recvfrom_args /* { 847238104Sdes int s; 848238104Sdes caddr_t buf; 849238104Sdes int len; 850238104Sdes int flags; 851238104Sdes struct sockaddr *from; 852238104Sdes socklen_t fromlenaddr; 853238104Sdes } */ bsd_args; 854238104Sdes int error; 855238104Sdes 856238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 857238104Sdes return (error); 858238104Sdes 859238104Sdes bsd_args.s = linux_args.s; 860238104Sdes bsd_args.buf = linux_args.msg; 861238104Sdes bsd_args.len = linux_args.len; 862238104Sdes bsd_args.flags = linux_args.flags; 863238104Sdes bsd_args.from = NULL; 864238104Sdes bsd_args.fromlenaddr = 0; 865238104Sdes return (recvfrom(td, &bsd_args)); 866238104Sdes} 867238104Sdes 868238104Sdesstatic int 869238104Sdeslinux_sendto(struct thread *td, struct linux_sendto_args *args) 870238104Sdes{ 871238104Sdes struct linux_sendto_args linux_args; 872238104Sdes struct msghdr msg; 873238104Sdes struct iovec aiov; 874238104Sdes int error; 875238104Sdes 876238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 877238104Sdes return (error); 878238104Sdes 879238104Sdes if (linux_check_hdrincl(td, linux_args.s) == 0) 880238104Sdes /* IP_HDRINCL set, tweak the packet before sending */ 881238104Sdes return (linux_sendto_hdrincl(td, &linux_args)); 882238104Sdes 883238104Sdes msg.msg_name = linux_args.to; 884238104Sdes msg.msg_namelen = linux_args.tolen; 885238104Sdes msg.msg_iov = &aiov; 886238104Sdes msg.msg_iovlen = 1; 887238104Sdes msg.msg_control = NULL; 888238104Sdes msg.msg_flags = 0; 889238104Sdes aiov.iov_base = linux_args.msg; 890238104Sdes aiov.iov_len = linux_args.len; 891238104Sdes error = linux_sendit(td, linux_args.s, &msg, linux_args.flags); 892238104Sdes return (error); 893238104Sdes} 894238104Sdes 895238104Sdesstruct linux_recvfrom_args { 896238104Sdes int s; 897238104Sdes void *buf; 898238104Sdes int len; 899238104Sdes int flags; 900238104Sdes caddr_t from; 901238104Sdes int *fromlen; 902238104Sdes}; 903238104Sdes 904238104Sdesstatic int 905238104Sdeslinux_recvfrom(struct thread *td, struct linux_recvfrom_args *args) 906238104Sdes{ 907238104Sdes struct linux_recvfrom_args linux_args; 908238104Sdes struct recvfrom_args /* { 909238104Sdes int s; 910238104Sdes caddr_t buf; 911238104Sdes size_t len; 912238104Sdes int flags; 913238104Sdes struct sockaddr * __restrict from; 914238104Sdes socklen_t * __restrict fromlenaddr; 915238104Sdes } */ bsd_args; 916238104Sdes int error; 917238104Sdes 918238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 919238104Sdes return (error); 920238104Sdes 921238104Sdes bsd_args.s = linux_args.s; 922238104Sdes bsd_args.buf = linux_args.buf; 923238104Sdes bsd_args.len = linux_args.len; 924238104Sdes bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 925238104Sdes /* XXX: */ 926238104Sdes bsd_args.from = (struct sockaddr * __restrict)linux_args.from; 927238104Sdes bsd_args.fromlenaddr = linux_args.fromlen; /* XXX */ 928238104Sdes error = orecvfrom(td, &bsd_args); 929238104Sdes if (error) 930238104Sdes return (error); 931238104Sdes if (linux_args.from) { 932238104Sdes error = linux_sa_put((struct osockaddr *) linux_args.from); 933238104Sdes if (error) 934238104Sdes return (error); 935238104Sdes } 936238104Sdes return (0); 937238104Sdes} 938238104Sdes 939238104Sdesstruct linux_sendmsg_args { 940238104Sdes int s; 941238104Sdes const struct msghdr *msg; 942238104Sdes int flags; 943238104Sdes}; 944238104Sdes 945238104Sdesstatic int 946238104Sdeslinux_sendmsg(struct thread *td, struct linux_sendmsg_args *args) 947238104Sdes{ 948238104Sdes struct linux_sendmsg_args linux_args; 949238104Sdes struct msghdr msg; 950238104Sdes struct iovec *iov; 951238104Sdes int error; 952238104Sdes 953238104Sdes error = copyin(args, &linux_args, sizeof(linux_args)); 954238104Sdes if (error) 955238104Sdes return (error); 956238104Sdes error = copyin(linux_args.msg, &msg, sizeof(msg)); 957238104Sdes if (error) 958238104Sdes return (error); 959238104Sdes error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE); 960238104Sdes if (error) 961238104Sdes return (error); 962238104Sdes msg.msg_iov = iov; 963238104Sdes msg.msg_flags = 0; 964238104Sdes error = linux_sendit(td, linux_args.s, &msg, linux_args.flags); 965238104Sdes free(iov, M_IOV); 966238104Sdes return (error); 967238104Sdes} 968238104Sdes 969238104Sdesstruct linux_recvmsg_args { 970238104Sdes int s; 971238104Sdes struct msghdr *msg; 972238104Sdes int flags; 973238104Sdes}; 974238104Sdes 975238104Sdesstatic int 976238104Sdeslinux_recvmsg(struct thread *td, struct linux_recvmsg_args *args) 977238104Sdes{ 978238104Sdes struct linux_recvmsg_args linux_args; 979238104Sdes struct recvmsg_args /* { 980238104Sdes int s; 981238104Sdes struct msghdr *msg; 982238104Sdes int flags; 983238104Sdes } */ bsd_args; 984238104Sdes struct msghdr msg; 985238104Sdes struct cmsghdr *cmsg; 986238104Sdes int error; 987238104Sdes 988238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 989238104Sdes return (error); 990238104Sdes 991238104Sdes bsd_args.s = linux_args.s; 992238104Sdes bsd_args.msg = linux_args.msg; 993238104Sdes bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags); 994238104Sdes error = recvmsg(td, &bsd_args); 995238104Sdes if (error) 996238104Sdes return (error); 997238104Sdes 998238104Sdes if (bsd_args.msg->msg_control != NULL) { 999238104Sdes cmsg = (struct cmsghdr*)bsd_args.msg->msg_control; 1000269257Sdes cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level); 1001238104Sdes } 1002269257Sdes 1003238104Sdes error = copyin(linux_args.msg, &msg, sizeof(msg)); 1004238104Sdes if (error) 1005238104Sdes return (error); 1006238104Sdes if (msg.msg_name && msg.msg_namelen > 2) 1007238104Sdes error = linux_sa_put(msg.msg_name); 1008238104Sdes return (error); 1009238104Sdes} 1010238104Sdes 1011238104Sdesstruct linux_shutdown_args { 1012238104Sdes int s; 1013238104Sdes int how; 1014238104Sdes}; 1015238104Sdes 1016238104Sdesstatic int 1017238104Sdeslinux_shutdown(struct thread *td, struct linux_shutdown_args *args) 1018238104Sdes{ 1019238104Sdes struct linux_shutdown_args linux_args; 1020238104Sdes struct shutdown_args /* { 1021238104Sdes int s; 1022238104Sdes int how; 1023238104Sdes } */ bsd_args; 1024238104Sdes int error; 1025238104Sdes 1026238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1027238104Sdes return (error); 1028238104Sdes 1029238104Sdes bsd_args.s = linux_args.s; 1030238104Sdes bsd_args.how = linux_args.how; 1031238104Sdes return (shutdown(td, &bsd_args)); 1032238104Sdes} 1033238104Sdes 1034238104Sdesstruct linux_setsockopt_args { 1035238104Sdes int s; 1036238104Sdes int level; 1037238104Sdes int optname; 1038238104Sdes void *optval; 1039238104Sdes int optlen; 1040238104Sdes}; 1041238104Sdes 1042238104Sdesstatic int 1043238104Sdeslinux_setsockopt(struct thread *td, struct linux_setsockopt_args *args) 1044238104Sdes{ 1045238104Sdes struct linux_setsockopt_args linux_args; 1046238104Sdes struct setsockopt_args /* { 1047269257Sdes int s; 1048238104Sdes int level; 1049238104Sdes int name; 1050238104Sdes caddr_t val; 1051238104Sdes int valsize; 1052238104Sdes } */ bsd_args; 1053269257Sdes int error, name; 1054238104Sdes 1055238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1056238104Sdes return (error); 1057238104Sdes 1058238104Sdes bsd_args.s = linux_args.s; 1059238104Sdes bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1060238104Sdes switch (bsd_args.level) { 1061269257Sdes case SOL_SOCKET: 1062238104Sdes name = linux_to_bsd_so_sockopt(linux_args.optname); 1063269257Sdes break; 1064238104Sdes case IPPROTO_IP: 1065238104Sdes name = linux_to_bsd_ip_sockopt(linux_args.optname); 1066238104Sdes break; 1067238104Sdes case IPPROTO_TCP: 1068238104Sdes /* Linux TCP option values match BSD's */ 1069238104Sdes name = linux_args.optname; 1070238104Sdes break; 1071238104Sdes default: 1072238104Sdes name = -1; 1073238104Sdes break; 1074238104Sdes } 1075238104Sdes if (name == -1) 1076238104Sdes return (EINVAL); 1077238104Sdes 1078238104Sdes bsd_args.name = name; 1079238104Sdes bsd_args.val = linux_args.optval; 1080238104Sdes bsd_args.valsize = linux_args.optlen; 1081238104Sdes return (setsockopt(td, &bsd_args)); 1082238104Sdes} 1083238104Sdes 1084238104Sdesstruct linux_getsockopt_args { 1085238104Sdes int s; 1086238104Sdes int level; 1087238104Sdes int optname; 1088238104Sdes void *optval; 1089238104Sdes int *optlen; 1090238104Sdes}; 1091238104Sdes 1092238104Sdesstatic int 1093238104Sdeslinux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) 1094238104Sdes{ 1095238104Sdes struct linux_getsockopt_args linux_args; 1096238104Sdes struct getsockopt_args /* { 1097238104Sdes int s; 1098238104Sdes int level; 1099238104Sdes int name; 1100238104Sdes caddr_t val; 1101238104Sdes int *avalsize; 1102238104Sdes } */ bsd_args; 1103238104Sdes int error, name; 1104238104Sdes 1105238104Sdes if ((error = copyin(args, &linux_args, sizeof(linux_args)))) 1106238104Sdes return (error); 1107238104Sdes 1108238104Sdes bsd_args.s = linux_args.s; 1109238104Sdes bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 1110238104Sdes switch (bsd_args.level) { 1111238104Sdes case SOL_SOCKET: 1112238104Sdes name = linux_to_bsd_so_sockopt(linux_args.optname); 1113238104Sdes break; 1114238104Sdes case IPPROTO_IP: 1115238104Sdes name = linux_to_bsd_ip_sockopt(linux_args.optname); 1116238104Sdes break; 1117238104Sdes case IPPROTO_TCP: 1118238104Sdes /* Linux TCP option values match BSD's */ 1119238104Sdes name = linux_args.optname; 1120238104Sdes break; 1121238104Sdes default: 1122238104Sdes name = -1; 1123238104Sdes break; 1124238104Sdes } 1125238104Sdes if (name == -1) 1126238104Sdes return (EINVAL); 1127238104Sdes 1128238104Sdes bsd_args.name = name; 1129238104Sdes bsd_args.val = linux_args.optval; 1130238104Sdes bsd_args.avalsize = linux_args.optlen; 1131238104Sdes return (getsockopt(td, &bsd_args)); 1132238104Sdes} 1133238104Sdes 1134238104Sdesint 1135238104Sdeslinux_socketcall(struct thread *td, struct linux_socketcall_args *args) 1136238104Sdes{ 1137238104Sdes void *arg = (void *)args->args; 1138238104Sdes 1139238104Sdes switch (args->what) { 1140238104Sdes case LINUX_SOCKET: 1141238104Sdes return (linux_socket(td, arg)); 1142238104Sdes case LINUX_BIND: 1143238104Sdes return (linux_bind(td, arg)); 1144238104Sdes case LINUX_CONNECT: 1145238104Sdes return (linux_connect(td, arg)); 1146238104Sdes case LINUX_LISTEN: 1147238104Sdes return (linux_listen(td, arg)); 1148238104Sdes case LINUX_ACCEPT: 1149238104Sdes return (linux_accept(td, arg)); 1150238104Sdes case LINUX_GETSOCKNAME: 1151238104Sdes return (linux_getsockname(td, arg)); 1152238104Sdes case LINUX_GETPEERNAME: 1153238104Sdes return (linux_getpeername(td, arg)); 1154238104Sdes case LINUX_SOCKETPAIR: 1155238104Sdes return (linux_socketpair(td, arg)); 1156238104Sdes case LINUX_SEND: 1157238104Sdes return (linux_send(td, arg)); 1158238104Sdes case LINUX_RECV: 1159238104Sdes return (linux_recv(td, arg)); 1160238104Sdes case LINUX_SENDTO: 1161238104Sdes return (linux_sendto(td, arg)); 1162238104Sdes case LINUX_RECVFROM: 1163238104Sdes return (linux_recvfrom(td, arg)); 1164238104Sdes case LINUX_SHUTDOWN: 1165238104Sdes return (linux_shutdown(td, arg)); 1166238104Sdes case LINUX_SETSOCKOPT: 1167238104Sdes return (linux_setsockopt(td, arg)); 1168238104Sdes case LINUX_GETSOCKOPT: 1169238104Sdes return (linux_getsockopt(td, arg)); 1170238104Sdes case LINUX_SENDMSG: 1171238104Sdes return (linux_sendmsg(td, arg)); 1172246854Sdes case LINUX_RECVMSG: 1173246854Sdes return (linux_recvmsg(td, arg)); 1174238104Sdes } 1175246854Sdes 1176238104Sdes uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 1177246854Sdes return (ENOSYS); 1178246854Sdes} 1179238104Sdes#endif /*!__alpha__*/ 1180246854Sdes