proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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.4 2003/06/25 03:55:44 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         if ((error = getsockopt(&bsd_args)))
239                 return (error);
240
241         if ((error = copyin(val, &optval, sizeof(optval))))
242                 return (error);
243
244         return (optval == 0);
245 }
246
247 /*
248  * Updated sendto() when IP_HDRINCL is set:
249  * tweak endian-dependent fields in the IP packet.
250  */
251 static int
252 linux_sendto_hdrincl(struct sendto_args *bsd_args)
253 {
254 /*
255  * linux_ip_copysize defines how many bytes we should copy
256  * from the beginning of the IP packet before we customize it for BSD.
257  * It should include all the fields we modify (ip_len and ip_off)
258  * and be as small as possible to minimize copying overhead.
259  */
260 #define linux_ip_copysize       8
261
262         caddr_t sg;
263         struct ip *packet;
264         struct msghdr *msg;
265         struct iovec *iov;
266
267         int error;
268         struct  sendmsg_args /* {
269                 int s;
270                 caddr_t msg;
271                 int flags;
272         } */ sendmsg_args;
273
274         /* Check the packet isn't too small before we mess with it */
275         if (bsd_args->len < linux_ip_copysize)
276                 return (EINVAL);
277
278         /*
279          * Tweaking the user buffer in place would be bad manners.
280          * We create a corrected IP header with just the needed length,
281          * then use an iovec to glue it to the rest of the user packet
282          * when calling sendmsg().
283          */
284         sg = stackgap_init();
285         packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
286         msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
287         iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
288
289         /* Make a copy of the beginning of the packet to be sent */
290         if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
291                 return (error);
292
293         /* Convert fields from Linux to BSD raw IP socket format */
294         packet->ip_len = bsd_args->len;
295         packet->ip_off = ntohs(packet->ip_off);
296
297         /* Prepare the msghdr and iovec structures describing the new packet */
298         msg->msg_name = bsd_args->to;
299         msg->msg_namelen = bsd_args->tolen;
300         msg->msg_iov = iov;
301         msg->msg_iovlen = 2;
302         msg->msg_control = NULL;
303         msg->msg_controllen = 0;
304         msg->msg_flags = 0;
305         iov[0].iov_base = (char *)packet;
306         iov[0].iov_len = linux_ip_copysize;
307         iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
308         iov[1].iov_len = bsd_args->len - linux_ip_copysize;
309
310         sendmsg_args.s = bsd_args->s;
311         sendmsg_args.msg = (caddr_t)msg;
312         sendmsg_args.flags = bsd_args->flags;
313         return (sendmsg(&sendmsg_args));
314 }
315
316 struct linux_socket_args {
317         int domain;
318         int type;
319         int protocol;
320 };
321
322 static int
323 linux_socket(struct linux_socket_args *args)
324 {
325         struct proc *p = curproc;
326         struct linux_socket_args linux_args;
327         struct socket_args /* {
328                 int domain;
329                 int type;
330                 int protocol;
331         } */ bsd_args;
332         int error;
333         int retval_socket;
334
335         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
336                 return (error);
337
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         if (bsd_args.type == SOCK_RAW
346             && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
347             && bsd_args.domain == AF_INET
348             && retval_socket >= 0) {
349                 /* It's a raw IP socket: set the IP_HDRINCL option. */
350                 struct setsockopt_args /* {
351                         int s;
352                         int level;
353                         int name;
354                         caddr_t val;
355                         int valsize;
356                 } */ bsd_setsockopt_args;
357                 caddr_t sg;
358                 int *hdrincl;
359
360                 sg = stackgap_init();
361                 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
362                 *hdrincl = 1;
363                 bsd_setsockopt_args.s = p->p_retval[0];
364                 bsd_setsockopt_args.level = IPPROTO_IP;
365                 bsd_setsockopt_args.name = IP_HDRINCL;
366                 bsd_setsockopt_args.val = (caddr_t)hdrincl;
367                 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
368                 /* We ignore any error returned by setsockopt() */
369                 setsockopt(&bsd_setsockopt_args);
370                 /* Copy back the return value from socket() */
371                 p->p_retval[0] = bsd_setsockopt_args.s;
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)
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.s = linux_args.s;
398         bsd_args.name = (caddr_t)linux_args.name;
399         bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
400             linux_args.namelen);
401         return (bind(&bsd_args));
402 }
403
404 struct linux_connect_args {
405         int s;
406         struct sockaddr * name;
407         int namelen;
408 };
409 int linux_connect(struct linux_connect_args *);
410 #endif /* !__alpha__*/
411
412 int
413 linux_connect(struct linux_connect_args *args)
414 {
415         struct thread *td = curthread;  /* XXX */
416         struct proc *p = td->td_proc;
417         struct linux_connect_args linux_args;
418         struct connect_args /* {
419                 int s;
420                 caddr_t name;
421                 int namelen;
422         } */ bsd_args;
423         struct socket *so;
424         struct file *fp;
425         int error;
426
427         KKASSERT(p);
428
429 #ifdef __alpha__
430         bcopy(args, &linux_args, sizeof(linux_args));
431 #else
432         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
433                 return (error);
434 #endif /* __alpha__ */
435
436         bsd_args.s = linux_args.s;
437         bsd_args.name = (caddr_t)linux_args.name;
438         bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
439             linux_args.namelen);
440         error = connect(&bsd_args);
441         if (error != EISCONN)
442                 return (error);
443
444         /*
445          * Linux doesn't return EISCONN the first time it occurs,
446          * when on a non-blocking socket. Instead it returns the
447          * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
448          */
449         error = holdsock(p->p_fd, linux_args.s, &fp);
450         if (error)
451                 return (error);
452         error = EISCONN;
453         if (fp->f_flag & FNONBLOCK) {
454                 so = (struct socket *)fp->f_data;
455                 if (so->so_emuldata == 0)
456                         error = so->so_error;
457                 so->so_emuldata = (void *)1;
458         }
459         fdrop(fp, td);
460         return (error);
461 }
462
463 #ifndef __alpha__
464
465 struct linux_listen_args {
466         int s;
467         int backlog;
468 };
469
470 static int
471 linux_listen(struct linux_listen_args *args)
472 {
473         struct linux_listen_args linux_args;
474         struct listen_args /* {
475                 int s;
476                 int backlog;
477         } */ bsd_args;
478         int error;
479
480         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
481                 return (error);
482
483         bsd_args.s = linux_args.s;
484         bsd_args.backlog = linux_args.backlog;
485         return (listen(&bsd_args));
486 }
487
488 struct linux_accept_args {
489         int s;
490         struct sockaddr *addr;
491         int *namelen;
492 };
493
494 static int
495 linux_accept(struct linux_accept_args *args)
496 {
497         struct proc *p = curproc;
498         struct linux_accept_args linux_args;
499         struct accept_args /* {
500                 int s;
501                 caddr_t name;
502                 int *anamelen;
503         } */ bsd_args;
504         struct fcntl_args /* {
505                 int fd;
506                 int cmd;
507                 long arg;
508         } */ f_args;
509         int error;
510
511         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
512                 return (error);
513
514         bsd_args.s = linux_args.s;
515         bsd_args.name = (caddr_t)linux_args.addr;
516         bsd_args.anamelen = linux_args.namelen;
517         error = oaccept(&bsd_args);
518         if (error)
519                 return (error);
520
521         /*
522          * linux appears not to copy flags from the parent socket to the
523          * accepted one, so we must clear the flags in the new descriptor.
524          * Ignore any errors, because we already have an open fd.
525          */
526         f_args.fd = p->p_retval[0];
527         f_args.cmd = F_SETFL;
528         f_args.arg = 0;
529         (void)fcntl(&f_args);
530         p->p_retval[0] = f_args.fd;
531         return (0);
532 }
533
534 struct linux_getsockname_args {
535         int s;
536         struct sockaddr *addr;
537         int *namelen;
538 };
539
540 static int
541 linux_getsockname(struct linux_getsockname_args *args)
542 {
543         struct linux_getsockname_args linux_args;
544         struct getsockname_args /* {
545                 int fdes;
546                 caddr_t asa;
547                 int *alen;
548         } */ bsd_args;
549         int error;
550
551         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
552                 return (error);
553
554         bsd_args.fdes = linux_args.s;
555         bsd_args.asa = (caddr_t) linux_args.addr;
556         bsd_args.alen = linux_args.namelen;
557         return (ogetsockname(&bsd_args));
558 }
559
560 struct linux_getpeername_args {
561         int s;
562         struct sockaddr *addr;
563         int *namelen;
564 };
565
566 static int
567 linux_getpeername(struct linux_getpeername_args *args)
568 {
569         struct linux_getpeername_args linux_args;
570         struct ogetpeername_args /* {
571                 int fdes;
572                 caddr_t asa;
573                 int *alen;
574         } */ bsd_args;
575         int error;
576
577         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
578                 return (error);
579
580         bsd_args.fdes = linux_args.s;
581         bsd_args.asa = (caddr_t) linux_args.addr;
582         bsd_args.alen = linux_args.namelen;
583         return (ogetpeername(&bsd_args));
584 }
585
586 struct linux_socketpair_args {
587         int domain;
588         int type;
589         int protocol;
590         int *rsv;
591 };
592
593 static int
594 linux_socketpair(struct linux_socketpair_args *args)
595 {
596         struct linux_socketpair_args linux_args;
597         struct socketpair_args /* {
598                 int domain;
599                 int type;
600                 int protocol;
601                 int *rsv;
602         } */ bsd_args;
603         int error;
604
605         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
606                 return (error);
607
608         bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
609         if (bsd_args.domain == -1)
610                 return (EINVAL);
611
612         bsd_args.type = linux_args.type;
613         bsd_args.protocol = linux_args.protocol;
614         bsd_args.rsv = linux_args.rsv;
615         return (socketpair(&bsd_args));
616 }
617
618 struct linux_send_args {
619         int s;
620         void *msg;
621         int len;
622         int flags;
623 };
624
625 static int
626 linux_send(struct linux_send_args *args)
627 {
628         struct linux_send_args linux_args;
629         struct osend_args /* {
630                 int s;
631                 caddr_t buf;
632                 int len;
633                 int flags;
634         } */ bsd_args;
635         int error;
636
637         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
638                 return (error);
639
640         bsd_args.s = linux_args.s;
641         bsd_args.buf = linux_args.msg;
642         bsd_args.len = linux_args.len;
643         bsd_args.flags = linux_args.flags;
644         return (osend(&bsd_args));
645 }
646
647 struct linux_recv_args {
648         int s;
649         void *msg;
650         int len;
651         int flags;
652 };
653
654 static int
655 linux_recv(struct linux_recv_args *args)
656 {
657         struct linux_recv_args linux_args;
658         struct orecv_args /* {
659                 int s;
660                 caddr_t buf;
661                 int len;
662                 int flags;
663         } */ bsd_args;
664         int error;
665
666         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
667                 return (error);
668
669         bsd_args.s = linux_args.s;
670         bsd_args.buf = linux_args.msg;
671         bsd_args.len = linux_args.len;
672         bsd_args.flags = linux_args.flags;
673         return (orecv(&bsd_args));
674 }
675
676 struct linux_sendto_args {
677         int s;
678         void *msg;
679         int len;
680         int flags;
681         caddr_t to;
682         int tolen;
683 };
684
685 static int
686 linux_sendto(struct linux_sendto_args *args)
687 {
688         struct linux_sendto_args linux_args;
689         struct sendto_args /* {
690                 int s;
691                 caddr_t buf;
692                 size_t len;
693                 int flags;
694                 caddr_t to;
695                 int tolen;
696         } */ bsd_args;
697         int error;
698
699         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
700                 return (error);
701
702         bsd_args.s = linux_args.s;
703         bsd_args.buf = linux_args.msg;
704         bsd_args.len = linux_args.len;
705         bsd_args.flags = linux_args.flags;
706         bsd_args.to = linux_args.to;
707         bsd_args.tolen = linux_args.tolen;
708
709         if (linux_check_hdrincl(linux_args.s) == 0)
710                 /* IP_HDRINCL set, tweak the packet before sending */
711                 return (linux_sendto_hdrincl(&bsd_args));
712
713         return (sendto(&bsd_args));
714 }
715
716 struct linux_recvfrom_args {
717         int s;
718         void *buf;
719         int len;
720         int flags;
721         caddr_t from;
722         int *fromlen;
723 };
724
725 static int
726 linux_recvfrom(struct linux_recvfrom_args *args)
727 {
728         struct linux_recvfrom_args linux_args;
729         struct recvfrom_args /* {
730                 int s;
731                 caddr_t buf;
732                 size_t len;
733                 int flags;
734                 caddr_t from;
735                 int *fromlenaddr;
736         } */ bsd_args;
737         int error;
738
739         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
740                 return (error);
741
742         bsd_args.s = linux_args.s;
743         bsd_args.buf = linux_args.buf;
744         bsd_args.len = linux_args.len;
745         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
746         bsd_args.from = linux_args.from;
747         bsd_args.fromlenaddr = linux_args.fromlen;
748         return (orecvfrom(&bsd_args));
749 }
750
751 struct linux_recvmsg_args {
752         int s;
753         struct msghdr *msg;
754         int flags;
755 };
756
757 static int
758 linux_recvmsg(struct linux_recvmsg_args *args)
759 {
760         struct linux_recvmsg_args linux_args;
761         struct recvmsg_args /* {
762                 int     s;
763                 struct  msghdr *msg;
764                 int     flags;
765         } */ bsd_args;
766         int error;
767
768         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
769                 return (error);
770
771         bsd_args.s = linux_args.s;
772         bsd_args.msg = linux_args.msg;
773         bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
774         return (recvmsg(&bsd_args));
775 }
776
777 struct linux_shutdown_args {
778         int s;
779         int how;
780 };
781
782 static int
783 linux_shutdown(struct linux_shutdown_args *args)
784 {
785         struct linux_shutdown_args linux_args;
786         struct shutdown_args /* {
787                 int s;
788                 int how;
789         } */ bsd_args;
790         int error;
791
792         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
793                 return (error);
794
795         bsd_args.s = linux_args.s;
796         bsd_args.how = linux_args.how;
797         return (shutdown(&bsd_args));
798 }
799
800 struct linux_setsockopt_args {
801         int s;
802         int level;
803         int optname;
804         void *optval;
805         int optlen;
806 };
807
808 static int
809 linux_setsockopt(struct linux_setsockopt_args *args)
810 {
811         struct linux_setsockopt_args linux_args;
812         struct setsockopt_args /* {
813                 int s;
814                 int level;
815                 int name;
816                 caddr_t val;
817                 int valsize;
818         } */ bsd_args;
819         int error, name;
820
821         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
822                 return (error);
823
824         bsd_args.s = linux_args.s;
825         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
826         switch (bsd_args.level) {
827         case SOL_SOCKET:
828                 name = linux_to_bsd_so_sockopt(linux_args.optname);
829                 break;
830         case IPPROTO_IP:
831                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
832                 break;
833         case IPPROTO_TCP:
834                 /* Linux TCP option values match BSD's */
835                 name = linux_args.optname;
836                 break;
837         default:
838                 name = -1;
839                 break;
840         }
841         if (name == -1)
842                 return (EINVAL);
843
844         bsd_args.name = name;
845         bsd_args.val = linux_args.optval;
846         bsd_args.valsize = linux_args.optlen;
847         return (setsockopt(&bsd_args));
848 }
849
850 struct linux_getsockopt_args {
851         int s;
852         int level;
853         int optname;
854         void *optval;
855         int *optlen;
856 };
857
858 static int
859 linux_getsockopt(struct linux_getsockopt_args *args)
860 {
861         struct linux_getsockopt_args linux_args;
862         struct getsockopt_args /* {
863                 int s;
864                 int level;
865                 int name;
866                 caddr_t val;
867                 int *avalsize;
868         } */ bsd_args;
869         int error, name;
870
871         if ((error = copyin(args, &linux_args, sizeof(linux_args))))
872                 return (error);
873
874         bsd_args.s = linux_args.s;
875         bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
876         switch (bsd_args.level) {
877         case SOL_SOCKET:
878                 name = linux_to_bsd_so_sockopt(linux_args.optname);
879                 break;
880         case IPPROTO_IP:
881                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
882                 break;
883         case IPPROTO_TCP:
884                 /* Linux TCP option values match BSD's */
885                 name = linux_args.optname;
886                 break;
887         default:
888                 name = -1;
889                 break;
890         }
891         if (name == -1)
892                 return (EINVAL);
893
894         bsd_args.name = name;
895         bsd_args.val = linux_args.optval;
896         bsd_args.avalsize = linux_args.optlen;
897         return (getsockopt(&bsd_args));
898 }
899
900 int
901 linux_socketcall(struct linux_socketcall_args *args)
902 {
903         void *arg = (void *)args->args;
904
905         switch (args->what) {
906         case LINUX_SOCKET:
907                 return (linux_socket(arg));
908         case LINUX_BIND:
909                 return (linux_bind(arg));
910         case LINUX_CONNECT:
911                 return (linux_connect(arg));
912         case LINUX_LISTEN:
913                 return (linux_listen(arg));
914         case LINUX_ACCEPT:
915                 return (linux_accept(arg));
916         case LINUX_GETSOCKNAME:
917                 return (linux_getsockname(arg));
918         case LINUX_GETPEERNAME:
919                 return (linux_getpeername(arg));
920         case LINUX_SOCKETPAIR:
921                 return (linux_socketpair(arg));
922         case LINUX_SEND:
923                 return (linux_send(arg));
924         case LINUX_RECV:
925                 return (linux_recv(arg));
926         case LINUX_SENDTO:
927                 return (linux_sendto(arg));
928         case LINUX_RECVFROM:
929                 return (linux_recvfrom(arg));
930         case LINUX_SHUTDOWN:
931                 return (linux_shutdown(arg));
932         case LINUX_SETSOCKOPT:
933                 return (linux_setsockopt(arg));
934         case LINUX_GETSOCKOPT:
935                 return (linux_getsockopt(arg));
936         case LINUX_SENDMSG:
937                 do {
938                         int error;
939                         int level;
940                         caddr_t control;
941                         struct {
942                                 int s;
943                                 const struct msghdr *msg;
944                                 int flags;
945                         } *uap = arg;
946
947                         error = copyin(&uap->msg->msg_control, &control,
948                             sizeof(caddr_t));
949                         if (error)
950                                 return (error);
951
952                         if (control == NULL)
953                                 goto done;
954
955                         error = copyin(&((struct cmsghdr*)control)->cmsg_level,
956                             &level, sizeof(int));
957                         if (error)
958                                 return (error);
959
960                         if (level == 1) {
961                                 /*
962                                  * Linux thinks that SOL_SOCKET is 1; we know
963                                  * that it's really 0xffff, of course.
964                                  */
965                                 level = SOL_SOCKET;
966                                 error = copyout(&level,
967                                     &((struct cmsghdr *)control)->cmsg_level,
968                                     sizeof(int));
969                                 if (error)
970                                         return (error);
971                         }
972                 done:
973                         return (sendmsg(arg));
974                 } while (0);
975         case LINUX_RECVMSG:
976                 return (linux_recvmsg(arg));
977         }
978
979         uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
980         return (ENOSYS);
981 }
982 #endif  /*!__alpha__*/