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