Change the split syscall naming convention from syscall1() to kern_syscall()
[dragonfly.git] / sys / emulation / linux / linux_socket.c
1 /*-
2  * Copyright (c) 1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer 
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.19.2.8 2001/11/07 20:33:55 marcel Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_socket.c,v 1.10 2003/09/07 20:36:11 daver Exp $
30  */
31
32 /* XXX we use functions that might not exist. */
33 #include "opt_compat.h"
34
35 #ifndef COMPAT_43
36 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/proc.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/fcntl.h>
44 #include <sys/file.h>
45 #include <sys/kern_syscall.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/uio.h>
49 #include <sys/malloc.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54
55 #include <arch_linux/linux.h>
56 #include <arch_linux/linux_proto.h>
57 #include "linux_socket.h"
58 #include "linux_util.h"
59
60 /*
61  * Copyin a sockaddr structure provided by a Linux binary.  Linux uses
62  * the 4.3BSD sockaddr structure which has no sa_len field.  We must
63  * pass 4.4BSD sockaddr structures when we call native functions in the
64  * BSD kernel.  his function does the conversion for us.
65  *
66  * Also, our socket calls require the sockaddr structure length to agree
67  * with the address family.  Linux does not, so we must force it.
68  *
69  * This function should only need to be called from linux_connect()
70  * and linux_bind().
71  */
72 static int
73 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
74 {
75         struct sockaddr *sa;
76         uint16_t family;        /* XXX: must match Linux sockaddr */
77         int error;
78         int sa_len;
79
80         *namp = NULL;
81
82         if (len > SOCK_MAXADDRLEN)
83                 return ENAMETOOLONG;
84         error = copyin(uaddr, &family, sizeof(family));
85         if (error)
86                 return (error);
87
88         /*
89          * Force the sa_len field to match the address family.
90          */
91         switch (family) {
92         case AF_INET:
93                 sa_len = sizeof(struct sockaddr_in);
94                 break;
95         case AF_INET6:
96                 sa_len = sizeof(struct sockaddr_in6);
97                 break;
98         default:
99                 /*
100                  * This is the default behavior of the old
101                  * linux_to_bsd_namelen() function.  NOTE!  The
102                  * minimum length we allocate must cover sa->sa_len and
103                  * sa->sa_family.
104                  */
105                 sa_len = offsetof(struct sockaddr, sa_data[0]);
106                 if (sa_len < len)
107                         sa_len = len;
108                 break;
109         }
110
111         MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
112         error = copyin(uaddr, sa, sa_len);
113         if (error) {
114                 FREE(sa, M_SONAME);
115         } else {
116                 /*
117                  * Convert to the 4.4BSD sockaddr structure.
118                  */
119                 sa->sa_family = *(sa_family_t *)sa;
120                 sa->sa_len = sa_len;
121                 *namp = sa;
122         }
123
124         return (error);
125 }
126  
127 #ifndef __alpha__
128 static int
129 linux_to_bsd_domain(int domain)
130 {
131
132         switch (domain) {
133         case LINUX_AF_UNSPEC:
134                 return (AF_UNSPEC);
135         case LINUX_AF_UNIX:
136                 return (AF_LOCAL);
137         case LINUX_AF_INET:
138                 return (AF_INET);
139         case LINUX_AF_AX25:
140                 return (AF_CCITT);
141         case LINUX_AF_IPX:
142                 return (AF_IPX);
143         case LINUX_AF_APPLETALK:
144                 return (AF_APPLETALK);
145         }
146         return (-1);
147 }
148
149 static int
150 linux_to_bsd_sockopt_level(int level)
151 {
152
153         switch (level) {
154         case LINUX_SOL_SOCKET:
155                 return (SOL_SOCKET);
156         }
157         return (level);
158 }
159
160 static int
161 linux_to_bsd_ip_sockopt(int opt)
162 {
163
164         switch (opt) {
165         case LINUX_IP_TOS:
166                 return (IP_TOS);
167         case LINUX_IP_TTL:
168                 return (IP_TTL);
169         case LINUX_IP_OPTIONS:
170                 return (IP_OPTIONS);
171         case LINUX_IP_MULTICAST_IF:
172                 return (IP_MULTICAST_IF);
173         case LINUX_IP_MULTICAST_TTL:
174                 return (IP_MULTICAST_TTL);
175         case LINUX_IP_MULTICAST_LOOP:
176                 return (IP_MULTICAST_LOOP);
177         case LINUX_IP_ADD_MEMBERSHIP:
178                 return (IP_ADD_MEMBERSHIP);
179         case LINUX_IP_DROP_MEMBERSHIP:
180                 return (IP_DROP_MEMBERSHIP);
181         case LINUX_IP_HDRINCL:
182                 return (IP_HDRINCL);
183         }
184         return (-1);
185 }
186
187 static int
188 linux_to_bsd_so_sockopt(int opt)
189 {
190
191         switch (opt) {
192         case LINUX_SO_DEBUG:
193                 return (SO_DEBUG);
194         case LINUX_SO_REUSEADDR:
195                 return (SO_REUSEADDR);
196         case LINUX_SO_TYPE:
197                 return (SO_TYPE);
198         case LINUX_SO_ERROR:
199                 return (SO_ERROR);
200         case LINUX_SO_DONTROUTE:
201                 return (SO_DONTROUTE);
202         case LINUX_SO_BROADCAST:
203                 return (SO_BROADCAST);
204         case LINUX_SO_SNDBUF:
205                 return (SO_SNDBUF);
206         case LINUX_SO_RCVBUF:
207                 return (SO_RCVBUF);
208         case LINUX_SO_KEEPALIVE:
209                 return (SO_KEEPALIVE);
210         case LINUX_SO_OOBINLINE:
211                 return (SO_OOBINLINE);
212         case LINUX_SO_LINGER:
213                 return (SO_LINGER);
214         }
215         return (-1);
216 }
217
218 static int
219 linux_to_bsd_msg_flags(int flags)
220 {
221         int ret_flags = 0;
222
223         if (flags & LINUX_MSG_OOB)
224                 ret_flags |= MSG_OOB;
225         if (flags & LINUX_MSG_PEEK)
226                 ret_flags |= MSG_PEEK;
227         if (flags & LINUX_MSG_DONTROUTE)
228                 ret_flags |= MSG_DONTROUTE;
229         if (flags & LINUX_MSG_CTRUNC)
230                 ret_flags |= MSG_CTRUNC;
231         if (flags & LINUX_MSG_TRUNC)
232                 ret_flags |= MSG_TRUNC;
233         if (flags & LINUX_MSG_DONTWAIT)
234                 ret_flags |= MSG_DONTWAIT;
235         if (flags & LINUX_MSG_EOR)
236                 ret_flags |= MSG_EOR;
237         if (flags & LINUX_MSG_WAITALL)
238                 ret_flags |= MSG_WAITALL;
239 #if 0 /* not handled */
240         if (flags & LINUX_MSG_PROXY)
241                 ;
242         if (flags & LINUX_MSG_FIN)
243                 ;
244         if (flags & LINUX_MSG_SYN)
245                 ;
246         if (flags & LINUX_MSG_CONFIRM)
247                 ;
248         if (flags & LINUX_MSG_RST)
249                 ;
250         if (flags & LINUX_MSG_ERRQUEUE)
251                 ;
252         if (flags & LINUX_MSG_NOSIGNAL)
253                 ;
254 #endif
255         return ret_flags;
256 }
257
258 /* Return 0 if IP_HDRINCL is set for the given socket. */
259 static int
260 linux_check_hdrincl(int s)
261 {
262         struct getsockopt_args /* {
263                 int s;
264                 int level;
265                 int name;
266                 caddr_t val;
267                 int *avalsize;
268         } */ bsd_args;
269         int error;
270         caddr_t sg, val, valsize;
271         int size_val = sizeof val;
272         int optval;
273
274         sg = stackgap_init();
275         val = stackgap_alloc(&sg, sizeof(int));
276         valsize = stackgap_alloc(&sg, sizeof(int));
277
278         if ((error = copyout(&size_val, valsize, sizeof(size_val))))
279                 return (error);
280
281         bsd_args.s = s;
282         bsd_args.level = IPPROTO_IP;
283         bsd_args.name = IP_HDRINCL;
284         bsd_args.val = val;
285         bsd_args.avalsize = (int *)valsize;
286         bsd_args.sysmsg_result = 0;
287         if ((error = getsockopt(&bsd_args)))
288                 return (error);
289         /* return value not used */
290
291         if ((error = copyin(val, &optval, sizeof(optval))))
292                 return (error);
293
294         return (optval == 0);
295 }
296
297 /*
298  * Updated sendto() when IP_HDRINCL is set:
299  * tweak endian-dependent fields in the IP packet.
300  */
301 static int
302 linux_sendto_hdrincl(struct sendto_args *bsd_args)
303 {
304 /*
305  * linux_ip_copysize defines how many bytes we should copy
306  * from the beginning of the IP packet before we customize it for BSD.
307  * It should include all the fields we modify (ip_len and ip_off)
308  * and be as small as possible to minimize copying overhead.
309  */
310 #define linux_ip_copysize       8
311
312         int error;
313         caddr_t sg;
314         struct ip *packet;
315         struct msghdr *msg;
316         struct iovec *iov;
317         struct  sendmsg_args /* {
318                 int s;
319                 caddr_t msg;
320                 int flags;
321         } */ sendmsg_args;
322
323         /* Check the packet isn't too small before we mess with it */
324         if (bsd_args->len < linux_ip_copysize)
325                 return (EINVAL);
326
327         /*
328          * Tweaking the user buffer in place would be bad manners.
329          * We create a corrected IP header with just the needed length,
330          * then use an iovec to glue it to the rest of the user packet
331          * when calling sendmsg().
332          */
333         sg = stackgap_init();
334         packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
335         msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
336         iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
337
338         /* Make a copy of the beginning of the packet to be sent */
339         if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
340                 return (error);
341
342         /* Convert fields from Linux to BSD raw IP socket format */
343         packet->ip_len = bsd_args->len;
344         packet->ip_off = ntohs(packet->ip_off);
345
346         /* Prepare the msghdr and iovec structures describing the new packet */
347         msg->msg_name = bsd_args->to;
348         msg->msg_namelen = bsd_args->tolen;
349         msg->msg_iov = iov;
350         msg->msg_iovlen = 2;
351         msg->msg_control = NULL;
352         msg->msg_controllen = 0;
353         msg->msg_flags = 0;
354         iov[0].iov_base = (char *)packet;
355         iov[0].iov_len = linux_ip_copysize;
356         iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
357         iov[1].iov_len = bsd_args->len - linux_ip_copysize;
358
359         sendmsg_args.s = bsd_args->s;
360         sendmsg_args.msg = (caddr_t)msg;
361         sendmsg_args.flags = bsd_args->flags;
362         sendmsg_args.sysmsg_result = 0;
363         error = sendmsg(&sendmsg_args);
364         bsd_args->sysmsg_result = sendmsg_args.sysmsg_result;
365         return(error);
366 }
367
368 struct linux_socket_args {
369         int domain;
370         int type;
371         int protocol;
372 };
373
374 static int
375 linux_socket(struct linux_socket_args *args, int *res)
376 {
377         struct linux_socket_args linux_args;
378         struct socket_args bsd_args;
379         int error;
380         int retval_socket;
381
382         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
383                 return (error);
384
385         bsd_args.sysmsg_result = 0;
386         bsd_args.protocol = linux_args.protocol;
387         bsd_args.type = linux_args.type;
388         bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
389         if (bsd_args.domain == -1)
390                 return (EINVAL);
391
392         retval_socket = socket(&bsd_args);
393         /* Copy back the return value from socket() */
394         *res = bsd_args.sysmsg_result;
395         if (bsd_args.type == SOCK_RAW
396             && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
397             && bsd_args.domain == AF_INET
398             && retval_socket >= 0) {
399                 /* It's a raw IP socket: set the IP_HDRINCL option. */
400                 struct setsockopt_args /* {
401                         int s;
402                         int level;
403                         int name;
404                         caddr_t val;
405                         int valsize;
406                 } */ bsd_setsockopt_args;
407                 caddr_t sg;
408                 int *hdrincl;
409
410                 sg = stackgap_init();
411                 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
412                 *hdrincl = 1;
413                 bsd_setsockopt_args.s = bsd_args.sysmsg_result;
414                 bsd_setsockopt_args.level = IPPROTO_IP;
415                 bsd_setsockopt_args.name = IP_HDRINCL;
416                 bsd_setsockopt_args.val = (caddr_t)hdrincl;
417                 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
418                 /* We ignore any error returned by setsockopt() */
419                 setsockopt(&bsd_setsockopt_args);
420         }
421
422         return (retval_socket);
423 }
424
425 struct linux_bind_args {
426         int s;
427         struct sockaddr *name;
428         int namelen;
429 };
430
431 static int
432 linux_bind(struct linux_bind_args *args, int *res)
433 {
434         struct linux_bind_args linux_args;
435         struct sockaddr *sa;
436         int error;
437
438         error = copyin(args, &linux_args, sizeof(linux_args));
439         if (error)
440                 return (error);
441         error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
442         if (error)
443                 return (error);
444
445         error = kern_bind(linux_args.s, sa);
446         FREE(sa, M_SONAME);
447
448         return (error);
449 }
450
451 struct linux_connect_args {
452         int s;
453         struct sockaddr * name;
454         int namelen;
455 };
456 int linux_connect(struct linux_connect_args *, int *res);
457 #endif /* !__alpha__*/
458
459 int
460 linux_connect(struct linux_connect_args *args, int *res)
461 {
462         struct thread *td = curthread;  /* XXX */
463         struct proc *p = td->td_proc;
464         struct linux_connect_args linux_args;
465         struct sockaddr *sa;
466         struct socket *so;
467         struct file *fp;
468         int error;
469
470         KKASSERT(p);
471
472         error = copyin(args, &linux_args, sizeof(linux_args));
473         if (error)
474                 return (error);
475         error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
476         if (error)
477                 return (error);
478
479         error = kern_connect(linux_args.s, sa);
480         FREE(sa, M_SONAME);
481
482         if (error != EISCONN)
483                 return (error);
484
485         /*
486          * Linux doesn't return EISCONN the first time it occurs,
487          * when on a non-blocking socket. Instead it returns the
488          * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
489          */
490         error = holdsock(p->p_fd, linux_args.s, &fp);
491         if (error)
492                 return (error);
493         error = EISCONN;
494         if (fp->f_flag & FNONBLOCK) {
495                 so = (struct socket *)fp->f_data;
496                 if (so->so_emuldata == 0)
497                         error = so->so_error;
498                 so->so_emuldata = (void *)1;
499         }
500         fdrop(fp, td);
501         return (error);
502 }
503
504 #ifndef __alpha__
505
506 struct linux_listen_args {
507         int s;
508         int backlog;
509 };
510
511 static int
512 linux_listen(struct linux_listen_args *args, int *res)
513 {
514         struct linux_listen_args linux_args;
515         struct listen_args /* {
516                 int s;
517                 int backlog;
518         } */ bsd_args;
519         int error;
520
521         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
522                 return (error);
523
524         bsd_args.sysmsg_result = 0;
525         bsd_args.s = linux_args.s;
526         bsd_args.backlog = linux_args.backlog;
527         error = listen(&bsd_args);
528         *res = bsd_args.sysmsg_result;
529         return(error);
530 }
531
532 struct linux_accept_args {
533         int s;
534         struct sockaddr *addr;
535         int *namelen;
536 };
537
538 static int
539 linux_accept(struct linux_accept_args *args, int *res)
540 {
541         struct linux_accept_args linux_args;
542         struct fcntl_args /* {
543                 int fd;
544                 int cmd;
545                 long arg;
546         } */ f_args;
547         struct sockaddr *sa = NULL;
548         int error, sa_len;
549
550         error = copyin(args, &linux_args, sizeof(linux_args));
551         if (error)
552                 return (error);
553
554         if (linux_args.addr) {
555                 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
556                 if (error)
557                         return (error);
558
559                 error = kern_accept(linux_args.s, &sa, &sa_len, res);
560
561                 if (error) {
562                         /*
563                          * Return a namelen of zero for older code which
564                          * might ignore the return value from accept().
565                          */
566                         sa_len = 0;
567                         copyout(&sa_len, linux_args.namelen,
568                             sizeof(*linux_args.namelen));
569                 } else {
570                         /*
571                          * Convert to the Linux sockaddr strucuture.
572                          */
573                         *(u_short *)sa = sa->sa_family;
574                         error = copyout(sa, linux_args.addr, sa_len);
575                         if (error == 0) {
576                                 error = copyout(&sa_len, linux_args.namelen,
577                                     sizeof(*linux_args.namelen));
578                         }
579                 }
580                 if (sa)
581                         FREE(sa, M_SONAME);
582         } else {
583                 error = kern_accept(linux_args.s, NULL, 0, res);
584         }
585
586         if (error)
587                 return (error);
588
589         /*
590          * linux appears not to copy flags from the parent socket to the
591          * accepted one, so we must clear the flags in the new descriptor.
592          * Ignore any errors, because we already have an open fd.
593          */
594         f_args.fd = *res;
595         f_args.cmd = F_SETFL;
596         f_args.arg = 0;
597         (void)fcntl(&f_args);
598         return (0);
599 }
600
601 struct linux_getsockname_args {
602         int s;
603         struct sockaddr *addr;
604         int *namelen;
605 };
606
607 static int
608 linux_getsockname(struct linux_getsockname_args *args, int *res)
609 {
610         struct linux_getsockname_args linux_args;
611         struct getsockname_args /* {
612                 int fdes;
613                 caddr_t asa;
614                 int *alen;
615         } */ bsd_args;
616         int error;
617
618         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
619                 return (error);
620
621         bsd_args.sysmsg_result = 0;
622         bsd_args.fdes = linux_args.s;
623         bsd_args.asa = (caddr_t) linux_args.addr;
624         bsd_args.alen = linux_args.namelen;
625         error = ogetsockname(&bsd_args);
626         *res = bsd_args.sysmsg_result;
627         return(error);
628 }
629
630 struct linux_getpeername_args {
631         int s;
632         struct sockaddr *addr;
633         int *namelen;
634 };
635
636 static int
637 linux_getpeername(struct linux_getpeername_args *args, int *res)
638 {
639         struct linux_getpeername_args linux_args;
640         struct ogetpeername_args /* {
641                 int fdes;
642                 caddr_t asa;
643                 int *alen;
644         } */ bsd_args;
645         int error;
646
647         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
648                 return (error);
649
650         bsd_args.sysmsg_result = 0;
651         bsd_args.fdes = linux_args.s;
652         bsd_args.asa = (caddr_t) linux_args.addr;
653         bsd_args.alen = linux_args.namelen;
654         error = ogetpeername(&bsd_args);
655         *res = bsd_args.sysmsg_result;
656         return(error);
657 }
658
659 struct linux_socketpair_args {
660         int domain;
661         int type;
662         int protocol;
663         int *rsv;
664 };
665
666 static int
667 linux_socketpair(struct linux_socketpair_args *args, int *res)
668 {
669         struct linux_socketpair_args linux_args;
670         struct socketpair_args /* {
671                 int domain;
672                 int type;
673                 int protocol;
674                 int *rsv;
675         } */ bsd_args;
676         int error;
677
678         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
679                 return (error);
680
681         bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
682         if (bsd_args.domain == -1)
683                 return (EINVAL);
684
685         bsd_args.sysmsg_result = 0;
686         bsd_args.type = linux_args.type;
687         bsd_args.protocol = linux_args.protocol;
688         bsd_args.rsv = linux_args.rsv;
689         error = socketpair(&bsd_args);
690         *res = bsd_args.sysmsg_result;
691         return(error);
692 }
693
694 struct linux_send_args {
695         int s;
696         void *msg;
697         int len;
698         int flags;
699 };
700
701 static int
702 linux_send(struct linux_send_args *args, int *res)
703 {
704         struct linux_send_args linux_args;
705         struct osend_args /* {
706                 int s;
707                 caddr_t buf;
708                 int len;
709                 int flags;
710         } */ bsd_args;
711         int error;
712
713         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
714                 return (error);
715
716         bsd_args.sysmsg_result = 0;
717         bsd_args.s = linux_args.s;
718         bsd_args.buf = linux_args.msg;
719         bsd_args.len = linux_args.len;
720         bsd_args.flags = linux_args.flags;
721         error = osend(&bsd_args);
722         *res = bsd_args.sysmsg_result;
723         return(error);
724 }
725
726 struct linux_recv_args {
727         int s;
728         void *msg;
729         int len;
730         int flags;
731 };
732
733 static int
734 linux_recv(struct linux_recv_args *args, int *res)
735 {
736         struct linux_recv_args linux_args;
737         struct orecv_args /* {
738                 int s;
739                 caddr_t buf;
740                 int len;
741                 int flags;
742         } */ bsd_args;
743         int error;
744
745         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
746                 return (error);
747
748         bsd_args.sysmsg_result = 0;
749         bsd_args.s = linux_args.s;
750         bsd_args.buf = linux_args.msg;
751         bsd_args.len = linux_args.len;
752         bsd_args.flags = linux_args.flags;
753         error = orecv(&bsd_args);
754         *res = bsd_args.sysmsg_result;
755         return(error);
756 }
757
758 struct linux_sendto_args {
759         int s;
760         void *msg;
761         int len;
762         int flags;
763         caddr_t to;
764         int tolen;
765 };
766
767 static int
768 linux_sendto(struct linux_sendto_args *args, int *res)
769 {
770         struct linux_sendto_args linux_args;
771         struct sendto_args /* {
772                 int s;
773                 caddr_t buf;
774                 size_t len;
775                 int flags;
776                 caddr_t to;
777                 int tolen;
778         } */ bsd_args;
779         int error;
780
781         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
782                 return (error);
783
784         bsd_args.sysmsg_result = 0;
785         bsd_args.s = linux_args.s;
786         bsd_args.buf = linux_args.msg;
787         bsd_args.len = linux_args.len;
788         bsd_args.flags = linux_args.flags;
789         bsd_args.to = linux_args.to;
790         bsd_args.tolen = linux_args.tolen;
791
792         if (linux_check_hdrincl(linux_args.s) == 0)
793                 /* IP_HDRINCL set, tweak the packet before sending */
794                 return (linux_sendto_hdrincl(&bsd_args));
795
796         error = sendto(&bsd_args);
797         *res = bsd_args.sysmsg_result;
798         return(error);
799 }
800
801 struct linux_recvfrom_args {
802         int s;
803         void *buf;
804         int len;
805         int flags;
806         caddr_t from;
807         int *fromlen;
808 };
809
810 static int
811 linux_recvfrom(struct linux_recvfrom_args *args, int *res)
812 {
813         struct linux_recvfrom_args linux_args;
814         struct recvfrom_args /* {
815                 int s;
816                 caddr_t buf;
817                 size_t len;
818                 int flags;
819                 caddr_t from;
820                 int *fromlenaddr;
821         } */ bsd_args;
822         int error;
823
824         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
825                 return (error);
826
827         bsd_args.sysmsg_result = 0;
828         bsd_args.s = linux_args.s;
829         bsd_args.buf = linux_args.buf;
830         bsd_args.len = linux_args.len;
831         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
832         bsd_args.from = linux_args.from;
833         bsd_args.fromlenaddr = linux_args.fromlen;
834         error = orecvfrom(&bsd_args);
835         *res = bsd_args.sysmsg_result;
836         return(error);
837 }
838
839 struct linux_recvmsg_args {
840         int s;
841         struct msghdr *msg;
842         int flags;
843 };
844
845 static int
846 linux_recvmsg(struct linux_recvmsg_args *args, int *res)
847 {
848         struct linux_recvmsg_args linux_args;
849         struct recvmsg_args /* {
850                 int     s;
851                 struct  msghdr *msg;
852                 int     flags;
853         } */ bsd_args;
854         int error;
855
856         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
857                 return (error);
858
859         bsd_args.sysmsg_result = 0;
860         bsd_args.s = linux_args.s;
861         bsd_args.msg = linux_args.msg;
862         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
863         error = recvmsg(&bsd_args);
864         *res = bsd_args.sysmsg_result;
865         return(error);
866 }
867
868 struct linux_shutdown_args {
869         int s;
870         int how;
871 };
872
873 static int
874 linux_shutdown(struct linux_shutdown_args *args, int *res)
875 {
876         struct linux_shutdown_args linux_args;
877         struct shutdown_args /* {
878                 int s;
879                 int how;
880         } */ bsd_args;
881         int error;
882
883         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
884                 return (error);
885
886         bsd_args.sysmsg_result = 0;
887         bsd_args.s = linux_args.s;
888         bsd_args.how = linux_args.how;
889         error = shutdown(&bsd_args);
890         *res = bsd_args.sysmsg_result;
891         return(error);
892 }
893
894 struct linux_setsockopt_args {
895         int s;
896         int level;
897         int optname;
898         void *optval;
899         int optlen;
900 };
901
902 static int
903 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
904 {
905         struct linux_setsockopt_args linux_args;
906         struct setsockopt_args /* {
907                 int s;
908                 int level;
909                 int name;
910                 caddr_t val;
911                 int valsize;
912         } */ bsd_args;
913         int error, name;
914
915         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
916                 return (error);
917
918         bsd_args.sysmsg_result = 0;
919         bsd_args.s = linux_args.s;
920         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
921         switch (bsd_args.level) {
922         case SOL_SOCKET:
923                 name = linux_to_bsd_so_sockopt(linux_args.optname);
924                 break;
925         case IPPROTO_IP:
926                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
927                 break;
928         case IPPROTO_TCP:
929                 /* Linux TCP option values match BSD's */
930                 name = linux_args.optname;
931                 break;
932         default:
933                 name = -1;
934                 break;
935         }
936         if (name == -1)
937                 return (EINVAL);
938
939         bsd_args.name = name;
940         bsd_args.val = linux_args.optval;
941         bsd_args.valsize = linux_args.optlen;
942         error = setsockopt(&bsd_args);
943         *res = bsd_args.sysmsg_result;
944         return(error);
945 }
946
947 struct linux_getsockopt_args {
948         int s;
949         int level;
950         int optname;
951         void *optval;
952         int *optlen;
953 };
954
955 static int
956 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
957 {
958         struct linux_getsockopt_args linux_args;
959         struct getsockopt_args /* {
960                 int s;
961                 int level;
962                 int name;
963                 caddr_t val;
964                 int *avalsize;
965         } */ bsd_args;
966         int error, name;
967
968         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
969                 return (error);
970
971         bsd_args.sysmsg_result = 0;
972         bsd_args.s = linux_args.s;
973         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
974         switch (bsd_args.level) {
975         case SOL_SOCKET:
976                 name = linux_to_bsd_so_sockopt(linux_args.optname);
977                 break;
978         case IPPROTO_IP:
979                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
980                 break;
981         case IPPROTO_TCP:
982                 /* Linux TCP option values match BSD's */
983                 name = linux_args.optname;
984                 break;
985         default:
986                 name = -1;
987                 break;
988         }
989         if (name == -1)
990                 return (EINVAL);
991
992         bsd_args.name = name;
993         bsd_args.val = linux_args.optval;
994         bsd_args.avalsize = linux_args.optlen;
995         error = getsockopt(&bsd_args);
996         *res = bsd_args.sysmsg_result;
997         return(error);
998 }
999
1000 int
1001 linux_socketcall(struct linux_socketcall_args *args)
1002 {
1003         void *arg = (void *)args->args;
1004
1005         switch (args->what) {
1006         case LINUX_SOCKET:
1007                 return (linux_socket(arg, &args->sysmsg_result));
1008         case LINUX_BIND:
1009                 return (linux_bind(arg, &args->sysmsg_result));
1010         case LINUX_CONNECT:
1011                 return (linux_connect(arg, &args->sysmsg_result));
1012         case LINUX_LISTEN:
1013                 return (linux_listen(arg, &args->sysmsg_result));
1014         case LINUX_ACCEPT:
1015                 return (linux_accept(arg, &args->sysmsg_result));
1016         case LINUX_GETSOCKNAME:
1017                 return (linux_getsockname(arg, &args->sysmsg_result));
1018         case LINUX_GETPEERNAME:
1019                 return (linux_getpeername(arg, &args->sysmsg_result));
1020         case LINUX_SOCKETPAIR:
1021                 return (linux_socketpair(arg, &args->sysmsg_result));
1022         case LINUX_SEND:
1023                 return (linux_send(arg, &args->sysmsg_result));
1024         case LINUX_RECV:
1025                 return (linux_recv(arg, &args->sysmsg_result));
1026         case LINUX_SENDTO:
1027                 return (linux_sendto(arg, &args->sysmsg_result));
1028         case LINUX_RECVFROM:
1029                 return (linux_recvfrom(arg, &args->sysmsg_result));
1030         case LINUX_SHUTDOWN:
1031                 return (linux_shutdown(arg, &args->sysmsg_result));
1032         case LINUX_SETSOCKOPT:
1033                 return (linux_setsockopt(arg, &args->sysmsg_result));
1034         case LINUX_GETSOCKOPT:
1035                 return (linux_getsockopt(arg, &args->sysmsg_result));
1036         case LINUX_SENDMSG:
1037                 do {
1038                         int error;
1039                         int level;
1040                         caddr_t control;
1041                         struct sendmsg_args bsd_args; 
1042
1043                         error = copyin(arg, &bsd_args.s, sizeof(bsd_args) - offsetof(struct sendmsg_args, s));
1044                         if (error)
1045                                 return (error);
1046                         error = copyin(&((struct msghdr *)bsd_args.msg)->msg_control, &control,
1047                             sizeof(caddr_t));
1048                         if (error)
1049                                 return (error);
1050
1051                         if (control == NULL)
1052                                 goto done;
1053
1054                         error = copyin(&((struct cmsghdr*)control)->cmsg_level,
1055                             &level, sizeof(int));
1056                         if (error)
1057                                 return (error);
1058
1059                         if (level == 1) {
1060                                 /*
1061                                  * Linux thinks that SOL_SOCKET is 1; we know
1062                                  * that it's really 0xffff, of course.
1063                                  */
1064                                 level = SOL_SOCKET;
1065                                 error = copyout(&level,
1066                                     &((struct cmsghdr *)control)->cmsg_level,
1067                                     sizeof(int));
1068                                 if (error)
1069                                         return (error);
1070                         }
1071                 done:
1072                         bsd_args.sysmsg_result = 0;
1073                         error = sendmsg(&bsd_args);
1074                         args->sysmsg_result = bsd_args.sysmsg_result;
1075                         return(error);
1076                 } while (0);
1077         case LINUX_RECVMSG:
1078                 return (linux_recvmsg(arg, &args->sysmsg_result));
1079         }
1080
1081         uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1082         return (ENOSYS);
1083 }
1084 #endif  /*!__alpha__*/