a40609b219dd7a0d2c261cff112293298f7f6b28
[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.28 2008/07/10 00:19:27 aggelos Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/proc.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/fcntl.h>
37 #include <sys/file.h>
38 #include <sys/kern_syscall.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/uio.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
48
49 #include <arch_linux/linux.h>
50 #include <arch_linux/linux_proto.h>
51 #include "linux_socket.h"
52 #include "linux_util.h"
53
54 /*
55  * Copyin a sockaddr structure provided by a Linux binary.  Linux uses
56  * the 4.3BSD sockaddr structure which has no sa_len field.  We must
57  * pass 4.4BSD sockaddr structures when we call native functions in the
58  * BSD kernel.  This function does the conversion for us.
59  *
60  * Also, our socket calls require the sockaddr structure length to agree
61  * with the address family.  Linux does not, so we must force it.
62  *
63  * This function should only need to be called from linux_connect()
64  * and linux_bind().
65  */
66 static int
67 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
68 {
69         struct sockaddr *sa;
70         uint16_t family;        /* XXX: must match Linux sockaddr */
71         int error;
72         int sa_len;
73
74         *namp = NULL;
75
76         if (len > SOCK_MAXADDRLEN)
77                 return ENAMETOOLONG;
78         error = copyin(uaddr, &family, sizeof(family));
79         if (error)
80                 return (error);
81
82         /*
83          * Force the sa_len field to match the address family.
84          */
85         switch (family) {
86         case AF_INET:
87                 sa_len = sizeof(struct sockaddr_in);
88                 break;
89         case AF_INET6:
90                 sa_len = sizeof(struct sockaddr_in6);
91                 break;
92         default:
93                 /*
94                  * This is the default behavior of the old
95                  * linux_to_bsd_namelen() function.  NOTE!  The
96                  * minimum length we allocate must cover sa->sa_len and
97                  * sa->sa_family.
98                  */
99                 sa_len = offsetof(struct sockaddr, sa_data[0]);
100                 if (sa_len < len)
101                         sa_len = len;
102                 break;
103         }
104
105         MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
106         error = copyin(uaddr, sa, sa_len);
107         if (error) {
108                 FREE(sa, M_SONAME);
109         } else {
110                 /*
111                  * Convert to the 4.4BSD sockaddr structure.
112                  */
113                 sa->sa_family = *(sa_family_t *)sa;
114                 sa->sa_len = sa_len;
115                 *namp = sa;
116         }
117
118         return (error);
119 }
120
121 /*
122  * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
123  * and copy it out to a user address.
124  */
125 static int
126 linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
127 {
128         int error;
129
130         if (sa_len < (int)sizeof(u_short))
131                 return (EINVAL);
132
133         *(u_short *)sa = sa->sa_family;
134         error = copyout(sa, uaddr, sa_len);
135
136         return (error);
137 }
138  
139 static int
140 linux_to_bsd_domain(int domain)
141 {
142
143         switch (domain) {
144         case LINUX_AF_UNSPEC:
145                 return (AF_UNSPEC);
146         case LINUX_AF_UNIX:
147                 return (AF_LOCAL);
148         case LINUX_AF_INET:
149                 return (AF_INET);
150         case LINUX_AF_AX25:
151                 return (AF_CCITT);
152         case LINUX_AF_IPX:
153                 return (AF_IPX);
154         case LINUX_AF_APPLETALK:
155                 return (AF_APPLETALK);
156         }
157         return (-1);
158 }
159
160 static int
161 linux_to_bsd_sockopt_level(int level)
162 {
163
164         switch (level) {
165         case LINUX_SOL_SOCKET:
166                 return (SOL_SOCKET);
167         }
168         return (level);
169 }
170
171 static int
172 linux_to_bsd_ip_sockopt(int opt)
173 {
174
175         switch (opt) {
176         case LINUX_IP_TOS:
177                 return (IP_TOS);
178         case LINUX_IP_TTL:
179                 return (IP_TTL);
180         case LINUX_IP_OPTIONS:
181                 return (IP_OPTIONS);
182         case LINUX_IP_MULTICAST_IF:
183                 return (IP_MULTICAST_IF);
184         case LINUX_IP_MULTICAST_TTL:
185                 return (IP_MULTICAST_TTL);
186         case LINUX_IP_MULTICAST_LOOP:
187                 return (IP_MULTICAST_LOOP);
188         case LINUX_IP_ADD_MEMBERSHIP:
189                 return (IP_ADD_MEMBERSHIP);
190         case LINUX_IP_DROP_MEMBERSHIP:
191                 return (IP_DROP_MEMBERSHIP);
192         case LINUX_IP_HDRINCL:
193                 return (IP_HDRINCL);
194         }
195         return (-1);
196 }
197
198 static int
199 linux_to_bsd_so_sockopt(int opt)
200 {
201
202         switch (opt) {
203         case LINUX_SO_DEBUG:
204                 return (SO_DEBUG);
205         case LINUX_SO_REUSEADDR:
206                 return (SO_REUSEADDR);
207         case LINUX_SO_TYPE:
208                 return (SO_TYPE);
209         case LINUX_SO_ERROR:
210                 return (SO_ERROR);
211         case LINUX_SO_DONTROUTE:
212                 return (SO_DONTROUTE);
213         case LINUX_SO_BROADCAST:
214                 return (SO_BROADCAST);
215         case LINUX_SO_SNDBUF:
216                 return (SO_SNDBUF);
217         case LINUX_SO_RCVBUF:
218                 return (SO_RCVBUF);
219         case LINUX_SO_KEEPALIVE:
220                 return (SO_KEEPALIVE);
221         case LINUX_SO_OOBINLINE:
222                 return (SO_OOBINLINE);
223         case LINUX_SO_LINGER:
224                 return (SO_LINGER);
225         }
226         return (-1);
227 }
228
229 static int
230 linux_to_bsd_msg_flags(int flags)
231 {
232         int ret_flags = 0;
233
234         if (flags & LINUX_MSG_OOB)
235                 ret_flags |= MSG_OOB;
236         if (flags & LINUX_MSG_PEEK)
237                 ret_flags |= MSG_PEEK;
238         if (flags & LINUX_MSG_DONTROUTE)
239                 ret_flags |= MSG_DONTROUTE;
240         if (flags & LINUX_MSG_CTRUNC)
241                 ret_flags |= MSG_CTRUNC;
242         if (flags & LINUX_MSG_TRUNC)
243                 ret_flags |= MSG_TRUNC;
244         if (flags & LINUX_MSG_DONTWAIT)
245                 ret_flags |= MSG_DONTWAIT;
246         if (flags & LINUX_MSG_EOR)
247                 ret_flags |= MSG_EOR;
248         if (flags & LINUX_MSG_WAITALL)
249                 ret_flags |= MSG_WAITALL;
250 #if 0 /* not handled */
251         if (flags & LINUX_MSG_PROXY)
252                 ;
253         if (flags & LINUX_MSG_FIN)
254                 ;
255         if (flags & LINUX_MSG_SYN)
256                 ;
257         if (flags & LINUX_MSG_CONFIRM)
258                 ;
259         if (flags & LINUX_MSG_RST)
260                 ;
261         if (flags & LINUX_MSG_ERRQUEUE)
262                 ;
263         if (flags & LINUX_MSG_NOSIGNAL)
264                 ;
265 #endif
266         return ret_flags;
267 }
268
269 struct linux_socket_args {
270         int domain;
271         int type;
272         int protocol;
273 };
274
275 static int
276 linux_socket(struct linux_socket_args *args, int *res)
277 {
278         struct linux_socket_args linux_args;
279         struct sockopt sopt;
280         int error, domain, optval;
281
282         error = copyin(args, &linux_args, sizeof(linux_args));
283         if (error)
284                 return (error);
285
286         domain = linux_to_bsd_domain(linux_args.domain);
287         if (domain == -1)
288                 return (EINVAL);
289
290         error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
291
292         /* Copy back the return value from socket() */
293         if (error == 0 && linux_args.type == SOCK_RAW &&
294             (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
295             linux_args.domain == AF_INET) {
296                 /* It's a raw IP socket: set the IP_HDRINCL option. */
297                 optval = 1;
298                 sopt.sopt_dir = SOPT_SET;
299                 sopt.sopt_level = IPPROTO_IP;
300                 sopt.sopt_name = IP_HDRINCL;
301                 sopt.sopt_val = &optval;
302                 sopt.sopt_valsize = sizeof(optval);
303                 sopt.sopt_td = NULL;
304
305                 /* We ignore any error returned by setsockopt() */
306                 kern_setsockopt(*res, &sopt);
307         }
308
309         return (error);
310 }
311
312 struct linux_bind_args {
313         int s;
314         struct sockaddr *name;
315         int namelen;
316 };
317
318 static int
319 linux_bind(struct linux_bind_args *args, int *res)
320 {
321         struct linux_bind_args linux_args;
322         struct sockaddr *sa;
323         int error;
324
325         error = copyin(args, &linux_args, sizeof(linux_args));
326         if (error)
327                 return (error);
328         error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
329         if (error)
330                 return (error);
331
332         error = kern_bind(linux_args.s, sa);
333         FREE(sa, M_SONAME);
334
335         return (error);
336 }
337
338 struct linux_connect_args {
339         int s;
340         struct sockaddr * name;
341         int namelen;
342 };
343
344 static int
345 linux_connect(struct linux_connect_args *args, int *res)
346 {
347         struct thread *td = curthread;  /* XXX */
348         struct proc *p = td->td_proc;
349         struct linux_connect_args linux_args;
350         struct sockaddr *sa;
351         struct socket *so;
352         struct file *fp;
353         int error;
354
355         KKASSERT(p);
356
357         error = copyin(args, &linux_args, sizeof(linux_args));
358         if (error)
359                 return (error);
360         error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
361         if (error)
362                 return (error);
363
364         error = kern_connect(linux_args.s, 0, sa);
365         FREE(sa, M_SONAME);
366
367         if (error != EISCONN)
368                 return (error);
369
370         /*
371          * Linux doesn't return EISCONN the first time it occurs,
372          * when on a non-blocking socket. Instead it returns the
373          * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
374          */
375         error = holdsock(p->p_fd, linux_args.s, &fp);
376         if (error)
377                 return (error);
378         error = EISCONN;
379         if (fp->f_flag & FNONBLOCK) {
380                 so = (struct socket *)fp->f_data;
381                 if (so->so_emuldata == 0)
382                         error = so->so_error;
383                 so->so_emuldata = (void *)1;
384         }
385         fdrop(fp);
386         return (error);
387 }
388
389 struct linux_listen_args {
390         int s;
391         int backlog;
392 };
393
394 static int
395 linux_listen(struct linux_listen_args *args, int *res)
396 {
397         struct linux_listen_args linux_args;
398         int error;
399
400         error = copyin(args, &linux_args, sizeof(linux_args));
401         if (error)
402                 return (error);
403
404         error = kern_listen(linux_args.s, linux_args.backlog);
405
406         return(error);
407 }
408
409 struct linux_accept_args {
410         int s;
411         struct sockaddr *addr;
412         int *namelen;
413 };
414
415 static int
416 linux_accept(struct linux_accept_args *args, int *res)
417 {
418         struct thread *td = curthread;
419         struct linux_accept_args linux_args;
420         struct sockaddr *sa = NULL;
421         union fcntl_dat dat = { 0 };
422         int error, sa_len;
423
424         error = copyin(args, &linux_args, sizeof(linux_args));
425         if (error)
426                 return (error);
427
428         if (linux_args.addr) {
429                 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
430                 if (error)
431                         return (error);
432
433                 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res);
434
435                 if (error) {
436                         /*
437                          * Return a namelen of zero for older code which
438                          * might ignore the return value from accept().
439                          */
440                         sa_len = 0;
441                         copyout(&sa_len, linux_args.namelen,
442                             sizeof(*linux_args.namelen));
443                 } else {
444                         error = linux_copyout_sockaddr(sa, linux_args.addr,
445                             sa_len);
446                         if (error == 0) {
447                                 error = copyout(&sa_len, linux_args.namelen,
448                                     sizeof(*linux_args.namelen));
449                         }
450                 }
451                 if (sa)
452                         FREE(sa, M_SONAME);
453         } else {
454                 error = kern_accept(linux_args.s, 0, NULL, 0, res);
455         }
456
457         if (error)
458                 return (error);
459
460         /*
461          * linux appears not to copy flags from the parent socket to the
462          * accepted one, so we must clear the flags in the new descriptor.
463          * Ignore any errors, because we already have an open fd.
464          */
465         kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
466         return (0);
467 }
468
469 struct linux_getsockname_args {
470         int s;
471         struct sockaddr *addr;
472         int *namelen;
473 };
474
475 static int
476 linux_getsockname(struct linux_getsockname_args *args, int *res)
477 {
478         struct linux_getsockname_args linux_args;
479         struct sockaddr *sa = NULL;
480         int error, sa_len;
481          
482
483         error = copyin(args, &linux_args, sizeof(linux_args));
484         if (error)
485                 return (error);
486         error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
487         if (error)
488                 return (error);
489
490         error = kern_getsockname(linux_args.s, &sa, &sa_len);
491
492         if (error == 0)
493                 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
494         if (error == 0)
495                 error = copyout(&sa_len, linux_args.namelen,
496                     sizeof(*linux_args.namelen));
497         if (sa)
498                 FREE(sa, M_SONAME);
499         return(error);
500 }
501
502 struct linux_getpeername_args {
503         int s;
504         struct sockaddr *addr;
505         int *namelen;
506 };
507
508 static int
509 linux_getpeername(struct linux_getpeername_args *args, int *res)
510 {
511         struct linux_getpeername_args linux_args;
512         struct sockaddr *sa = NULL;
513         int error, sa_len;
514
515         error = copyin(args, &linux_args, sizeof(linux_args));
516         if (error)
517                 return (error);
518         error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
519         if (error)
520                 return (error);
521
522         error = kern_getpeername(linux_args.s, &sa, &sa_len);
523
524         if (error == 0)
525                 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
526         if (error == 0)
527                 error = copyout(&sa_len, linux_args.namelen,
528                     sizeof(*linux_args.namelen));
529         if (sa)
530                 FREE(sa, M_SONAME);
531         return(error);
532 }
533
534 struct linux_socketpair_args {
535         int domain;
536         int type;
537         int protocol;
538         int *rsv;
539 };
540
541 static int
542 linux_socketpair(struct linux_socketpair_args *args, int *res)
543 {
544         struct linux_socketpair_args linux_args;
545         int error, domain, sockv[2];
546
547         error = copyin(args, &linux_args, sizeof(linux_args));
548         if (error)
549                 return (error);
550
551         domain = linux_to_bsd_domain(linux_args.domain);
552         if (domain == -1)
553                 return (EINVAL);
554         error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
555             sockv);
556
557         if (error == 0)
558                 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
559         return(error);
560 }
561
562 struct linux_send_args {
563         int s;
564         void *msg;
565         int len;
566         int flags;
567 };
568
569 static int
570 linux_send(struct linux_send_args *args, size_t *res)
571 {
572         struct linux_send_args linux_args;
573         struct thread *td = curthread;
574         struct uio auio;
575         struct iovec aiov;
576         int error;
577
578         error = copyin(args, &linux_args, sizeof(linux_args));
579         if (error)
580                 return (error);
581
582         aiov.iov_base = linux_args.msg;
583         aiov.iov_len = linux_args.len;
584         auio.uio_iov = &aiov;
585         auio.uio_iovcnt = 1;
586         auio.uio_offset = 0;
587         auio.uio_resid = linux_args.len;
588         auio.uio_segflg = UIO_USERSPACE;
589         auio.uio_rw = UIO_WRITE;
590         auio.uio_td = td;
591
592         error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
593                              linux_args.flags, res);
594
595         return(error);
596 }
597
598 struct linux_recv_args {
599         int s;
600         void *msg;
601         int len;
602         int flags;
603 };
604
605 static int
606 linux_recv(struct linux_recv_args *args, size_t *res)
607 {
608         struct linux_recv_args linux_args;
609         struct thread *td = curthread;
610         struct uio auio;
611         struct iovec aiov;
612         int error;
613
614         error = copyin(args, &linux_args, sizeof(linux_args));
615         if (error)
616                 return (error);
617
618         aiov.iov_base = linux_args.msg;
619         aiov.iov_len = linux_args.len;
620         auio.uio_iov = &aiov;
621         auio.uio_iovcnt = 1;
622         auio.uio_offset = 0;
623         auio.uio_resid = linux_args.len;
624         auio.uio_segflg = UIO_USERSPACE;
625         auio.uio_rw = UIO_READ;
626         auio.uio_td = td;
627
628         error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
629                              &linux_args.flags, res);
630
631         return(error);
632 }
633
634 struct linux_sendto_args {
635         int s;
636         void *msg;
637         int len;
638         int flags;
639         struct sockaddr *to;
640         int tolen;
641 };
642
643 static int
644 linux_sendto(struct linux_sendto_args *args, size_t *res)
645 {
646         struct linux_sendto_args linux_args;
647         struct thread *td = curthread;
648         struct uio auio;
649         struct iovec aiov;
650         struct sockopt sopt;
651         struct sockaddr *sa = NULL;
652         caddr_t msg = NULL;
653         int error, optval;
654
655         error = copyin(args, &linux_args, sizeof(linux_args));
656         if (error)
657                 return (error);
658
659         if (linux_args.to) {
660                 error = linux_getsockaddr(&sa, linux_args.to,
661                     linux_args.tolen);
662                 if (error)
663                         return (error);
664         }
665
666         /*
667          * Check to see if the IP_HDRINCL option is set.
668          */
669         sopt.sopt_dir = SOPT_GET;
670         sopt.sopt_level = IPPROTO_IP;
671         sopt.sopt_name = IP_HDRINCL;
672         sopt.sopt_val = &optval;
673         sopt.sopt_valsize = sizeof(optval);
674         sopt.sopt_td = NULL;
675
676         if (kern_getsockopt(linux_args.s, &sopt) != 0)
677                 optval = 0;
678
679         if (optval == 0) {
680                 /*
681                  * IP_HDRINCL is not set.  Package the message as usual.
682                  */
683                 aiov.iov_base = linux_args.msg;
684                 aiov.iov_len = linux_args.len;
685                 auio.uio_iov = &aiov;
686                 auio.uio_iovcnt = 1;
687                 auio.uio_offset = 0;
688                 auio.uio_resid = linux_args.len;
689                 auio.uio_segflg = UIO_USERSPACE;
690                 auio.uio_rw = UIO_WRITE;
691                 auio.uio_td = td;
692         } else {
693                 /*
694                  * IP_HDRINCL is set.  We must convert the beginning of
695                  * the packet header so we can feed it to the BSD kernel.
696                  */
697
698                 /*
699                  * Check that the packet header is long enough to contain
700                  * the fields of interest.  This relies on the fact that
701                  * the fragment offset field comes after the length field.
702                  */
703                 if (linux_args.len < offsetof(struct ip, ip_off))
704                         return (EINVAL);
705
706                 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
707                 error = copyin(linux_args.msg, msg, linux_args.len);
708                 if (error)
709                         goto cleanup;
710
711                 /* Fix the ip_len and ip_off fields.  */
712                 ((struct ip *)msg)->ip_len = linux_args.len;
713                 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
714
715                 aiov.iov_base = msg;
716                 aiov.iov_len = linux_args.len;
717                 auio.uio_iov = &aiov;
718                 auio.uio_iovcnt = 1;
719                 auio.uio_offset = 0;
720                 auio.uio_resid = linux_args.len;
721                 auio.uio_segflg = UIO_SYSSPACE;
722                 auio.uio_rw = UIO_WRITE;
723                 auio.uio_td = td;
724         }
725
726         error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
727                              linux_args.flags, res);
728
729 cleanup:
730         if (sa)
731                 FREE(sa, M_SONAME);
732         if (msg)
733                 FREE(msg, M_LINUX);
734         return(error);
735 }
736
737 struct linux_recvfrom_args {
738         int s;
739         void *buf;
740         int len;
741         int flags;
742         struct sockaddr *from;
743         int *fromlen;
744 };
745
746 static int
747 linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
748 {
749         struct linux_recvfrom_args linux_args;
750         struct thread *td = curthread;
751         struct uio auio;
752         struct iovec aiov;
753         struct sockaddr *sa = NULL;
754         int error, fromlen, flags;
755
756         error = copyin(args, &linux_args, sizeof(linux_args));
757         if (error)
758                 return (error);
759
760         if (linux_args.from && linux_args.fromlen) {
761                 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
762                 if (error)
763                         return (error);
764                 if (fromlen < 0)
765                         return (EINVAL);
766         } else {
767                 fromlen = 0;
768         }
769         aiov.iov_base = linux_args.buf;
770         aiov.iov_len = linux_args.len;
771         auio.uio_iov = &aiov;
772         auio.uio_iovcnt = 1;
773         auio.uio_offset = 0;
774         auio.uio_resid = linux_args.len;
775         auio.uio_segflg = UIO_USERSPACE;
776         auio.uio_rw = UIO_READ;
777         auio.uio_td = td;
778
779         flags = linux_to_bsd_msg_flags(linux_args.flags);
780
781         error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
782                              NULL, &flags, res);
783
784         if (error == 0 && linux_args.from) {
785                 if (sa != NULL) {
786                         fromlen = MIN(fromlen, sa->sa_len);
787                         error = linux_copyout_sockaddr(sa, linux_args.from,
788                                                         fromlen);
789                 } else
790                         fromlen = 0;
791                 if (error == 0)
792                         copyout(&fromlen, linux_args.fromlen,
793                             sizeof(fromlen));
794         }
795         if (sa)
796                 FREE(sa, M_SONAME);
797
798         return(error);
799 }
800
801 struct linux_sendmsg_args {
802         int s;
803         struct msghdr *msg;
804         int flags;
805 };
806
807 static int
808 linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
809 {
810         struct linux_sendmsg_args linux_args;
811         struct thread *td = curthread;
812         struct msghdr msg;
813         struct uio auio;
814         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
815         struct sockaddr *sa = NULL;
816         struct mbuf *control = NULL;
817         int error;
818
819         error = copyin(args, &linux_args, sizeof(linux_args));
820         if (error)
821                 return (error);
822
823         error = copyin(linux_args.msg, &msg, sizeof(msg));
824         if (error)
825                 return (error);
826
827         /*
828          * Conditionally copyin msg.msg_name.
829          */
830         if (msg.msg_name) {
831                 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
832                 if (error)
833                         return (error);
834         }
835
836         /*
837          * Populate auio.
838          */
839         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
840                              &auio.uio_resid);
841         if (error)
842                 goto cleanup2;
843         auio.uio_iov = iov;
844         auio.uio_iovcnt = msg.msg_iovlen;
845         auio.uio_offset = 0;
846         auio.uio_segflg = UIO_USERSPACE;
847         auio.uio_rw = UIO_WRITE;
848         auio.uio_td = td;
849
850         /*
851          * Conditionally copyin msg.msg_control.
852          */
853         if (msg.msg_control) {
854                 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
855                     msg.msg_controllen > MLEN) {
856                         error = EINVAL;
857                         goto cleanup;
858                 }
859                 control = m_get(MB_WAIT, MT_CONTROL);
860                 if (control == NULL) {
861                         error = ENOBUFS;
862                         goto cleanup;
863                 }
864                 control->m_len = msg.msg_controllen;
865                 error = copyin(msg.msg_control, mtod(control, caddr_t),
866                     msg.msg_controllen);
867                 if (error) {
868                         m_free(control);
869                         goto cleanup;
870                 }
871                 /*
872                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
873                  * wants anything else with an option level of SOL_SOCKET,
874                  * we don't support it.
875                  */
876                 if (mtod(control, struct cmsghdr *)->cmsg_level ==
877                     SOL_SOCKET &&
878                     mtod(control, struct cmsghdr *)->cmsg_type !=
879                     SCM_RIGHTS) {
880                         m_free(control);
881                         error = EINVAL;
882                         goto cleanup;
883                 }
884         }
885
886         error = kern_sendmsg(linux_args.s, sa, &auio, control,
887                              linux_args.flags, res);
888
889 cleanup:
890         iovec_free(&iov, aiov);
891 cleanup2:
892         if (sa)
893                 FREE(sa, M_SONAME);
894         return (error);
895 }
896
897 struct linux_recvmsg_args {
898         int s;
899         struct msghdr *msg;
900         int flags;
901 };
902
903 static int
904 linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
905 {
906         struct linux_recvmsg_args linux_args;
907         struct thread *td = curthread;
908         struct msghdr msg;
909         struct uio auio;
910         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
911         struct mbuf *m, *control = NULL;
912         struct sockaddr *sa = NULL;
913         caddr_t ctlbuf;
914         socklen_t *ufromlenp, *ucontrollenp;
915         int error, fromlen, controllen, len, flags, *uflagsp;
916
917         error = copyin(args, &linux_args, sizeof(linux_args));
918         if (error)
919                 return (error);
920
921         error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
922         if (error)
923                 return (error);
924
925         if (msg.msg_name && msg.msg_namelen < 0)
926                 return (EINVAL);
927         if (msg.msg_control && msg.msg_controllen < 0)
928                 return (EINVAL);
929
930         ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
931             offsetof(struct msghdr, msg_namelen));
932         ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
933             offsetof(struct msghdr, msg_controllen));
934         uflagsp = (int *)((caddr_t)linux_args.msg +
935             offsetof(struct msghdr, msg_flags));
936
937         /*
938          * Populate auio.
939          */
940         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
941                              &auio.uio_resid);
942         if (error)
943                 return (error);
944         auio.uio_iov = iov;
945         auio.uio_iovcnt = msg.msg_iovlen;
946         auio.uio_offset = 0;
947         auio.uio_segflg = UIO_USERSPACE;
948         auio.uio_rw = UIO_READ;
949         auio.uio_td = td;
950
951         flags = linux_to_bsd_msg_flags(linux_args.flags);
952
953         error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
954                              msg.msg_control ? &control : NULL, &flags, res);
955
956         /*
957          * Copyout msg.msg_name and msg.msg_namelen.
958          */
959         if (error == 0 && msg.msg_name) {
960                 if (sa != NULL) {
961                         fromlen = MIN(msg.msg_namelen, sa->sa_len);
962                         error = linux_copyout_sockaddr(sa, msg.msg_name,
963                                                         fromlen);
964                 } else
965                         fromlen = 0;
966                 if (error == 0)
967                         error = copyout(&fromlen, ufromlenp,
968                             sizeof(*ufromlenp));
969         }
970
971         /*
972          * Copyout msg.msg_control and msg.msg_controllen.
973          */
974         if (error == 0 && msg.msg_control) {
975                 /*
976                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
977                  * wants anything else with an option level of SOL_SOCKET,
978                  * we don't support it.
979                  */
980                 if (mtod((struct mbuf *)msg.msg_control,
981                     struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
982                     mtod((struct mbuf *)msg.msg_control,
983                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
984                         error = EINVAL;
985                         goto cleanup;
986                 }
987
988                 len = msg.msg_controllen;
989                 m = control;
990                 ctlbuf = (caddr_t)msg.msg_control;
991
992                 while (m && len > 0) {
993                         unsigned int tocopy;
994
995                         if (len >= m->m_len) {
996                                 tocopy = m->m_len;
997                         } else {
998                                 msg.msg_flags |= MSG_CTRUNC;
999                                 tocopy = len;
1000                         }
1001
1002                         error = copyout(mtod(m, caddr_t), ctlbuf,
1003                             tocopy);
1004                         if (error)
1005                                 goto cleanup;
1006
1007                         ctlbuf += tocopy;
1008                         len -= tocopy;
1009                         m = m->m_next;
1010                 }
1011                 controllen = ctlbuf - (caddr_t)msg.msg_control;
1012                 error = copyout(&controllen, ucontrollenp,
1013                     sizeof(*ucontrollenp));
1014         }
1015
1016         if (error == 0)
1017                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1018
1019 cleanup:
1020         if (sa)
1021                 FREE(sa, M_SONAME);
1022         iovec_free(&iov, aiov);
1023         if (control)
1024                 m_freem(control);
1025         return (error);
1026 }
1027
1028 struct linux_shutdown_args {
1029         int s;
1030         int how;
1031 };
1032
1033 static int
1034 linux_shutdown(struct linux_shutdown_args *args, int *res)
1035 {
1036         struct linux_shutdown_args linux_args;
1037         int error;
1038
1039         error = copyin(args, &linux_args, sizeof(linux_args));
1040         if (error)
1041                 return (error);
1042
1043         error = kern_shutdown(linux_args.s, linux_args.how);
1044
1045         return (error);
1046 }
1047
1048 struct linux_setsockopt_args {
1049         int s;
1050         int level;
1051         int optname;
1052         void *optval;
1053         int optlen;
1054 };
1055
1056 static int
1057 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1058 {
1059         struct linux_setsockopt_args linux_args;
1060         struct thread *td = curthread;
1061         struct sockopt sopt;
1062         int error, name, level;
1063
1064         error = copyin(args, &linux_args, sizeof(linux_args));
1065         if (error)
1066                 return (error);
1067
1068         level = linux_to_bsd_sockopt_level(linux_args.level);
1069         switch (level) {
1070         case SOL_SOCKET:
1071                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1072                 break;
1073         case IPPROTO_IP:
1074                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1075                 break;
1076         case IPPROTO_TCP:
1077                 /* Linux TCP option values match BSD's */
1078                 name = linux_args.optname;
1079                 break;
1080         default:
1081                 name = -1;
1082                 break;
1083         }
1084         if (name == -1)
1085                 return (EINVAL);
1086
1087         sopt.sopt_dir = SOPT_SET;
1088         sopt.sopt_level = level;
1089         sopt.sopt_name = name;
1090         sopt.sopt_valsize = linux_args.optlen;
1091         sopt.sopt_td = td;
1092
1093         if (sopt.sopt_valsize < 0 || sopt.sopt_valsize > SOMAXOPT_SIZE)
1094                 return (EINVAL);
1095
1096         if (linux_args.optval) {
1097                 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1098                 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1099                 if (error)
1100                         goto out;
1101         } else {
1102                 sopt.sopt_val = NULL;
1103         }
1104         error = kern_setsockopt(linux_args.s, &sopt);
1105         if (error)
1106                 goto out;
1107         if (linux_args.optval)
1108                 error = copyout(sopt.sopt_val, linux_args.optval,
1109                                 sopt.sopt_valsize);
1110 out:
1111         if (linux_args.optval)
1112                 kfree(sopt.sopt_val, M_TEMP);
1113         return(error);
1114 }
1115
1116 struct linux_getsockopt_args {
1117         int s;
1118         int level;
1119         int optname;
1120         void *optval;
1121         int *optlen;
1122 };
1123
1124 static int
1125 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1126 {
1127         struct linux_getsockopt_args linux_args;
1128         struct thread *td = curthread;
1129         struct sockopt sopt;
1130         int error, name, valsize, level;
1131
1132         error = copyin(args, &linux_args, sizeof(linux_args));
1133         if (error)
1134                 return (error);
1135
1136         if (linux_args.optval) {
1137                 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1138                 if (error)
1139                         return (error);
1140                 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1141                         return (EINVAL);
1142         } else {
1143                 valsize = 0;
1144         }
1145
1146         level = linux_to_bsd_sockopt_level(linux_args.level);
1147         switch (level) {
1148         case SOL_SOCKET:
1149                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1150                 break;
1151         case IPPROTO_IP:
1152                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1153                 break;
1154         case IPPROTO_TCP:
1155                 /* Linux TCP option values match BSD's */
1156                 name = linux_args.optname;
1157                 break;
1158         default:
1159                 name = -1;
1160                 break;
1161         }
1162         if (name == -1)
1163                 return (EINVAL);
1164
1165         sopt.sopt_dir = SOPT_GET;
1166         sopt.sopt_level = level;
1167         sopt.sopt_name = name;
1168         sopt.sopt_valsize = valsize;
1169         sopt.sopt_td = td;
1170
1171         if (linux_args.optval) {
1172                 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1173                 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1174                 if (error)
1175                         goto out;
1176         } else {
1177                 sopt.sopt_val = NULL;
1178         }
1179         error = kern_getsockopt(linux_args.s, &sopt);
1180         if (error)
1181                 goto out;
1182         valsize = sopt.sopt_valsize;
1183         error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1184         if (error)
1185                 goto out;
1186         if (linux_args.optval)
1187                 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1188 out:
1189         if (linux_args.optval)
1190                 kfree(sopt.sopt_val, M_TEMP);
1191         return(error);
1192 }
1193
1194 /*
1195  * MPALMOSTSAFE
1196  */
1197 int
1198 sys_linux_socketcall(struct linux_socketcall_args *args)
1199 {
1200         void *arg = (void *)args->args;
1201
1202         get_mplock();
1203
1204         switch (args->what) {
1205         case LINUX_SOCKET:
1206                 return (linux_socket(arg, &args->sysmsg_result));
1207         case LINUX_BIND:
1208                 return (linux_bind(arg, &args->sysmsg_result));
1209         case LINUX_CONNECT:
1210                 return (linux_connect(arg, &args->sysmsg_result));
1211         case LINUX_LISTEN:
1212                 return (linux_listen(arg, &args->sysmsg_result));
1213         case LINUX_ACCEPT:
1214                 return (linux_accept(arg, &args->sysmsg_result));
1215         case LINUX_GETSOCKNAME:
1216                 return (linux_getsockname(arg, &args->sysmsg_result));
1217         case LINUX_GETPEERNAME:
1218                 return (linux_getpeername(arg, &args->sysmsg_result));
1219         case LINUX_SOCKETPAIR:
1220                 return (linux_socketpair(arg, &args->sysmsg_result));
1221         case LINUX_SEND:
1222                 return (linux_send(arg, &args->sysmsg_szresult));
1223         case LINUX_RECV:
1224                 return (linux_recv(arg, &args->sysmsg_szresult));
1225         case LINUX_SENDTO:
1226                 return (linux_sendto(arg, &args->sysmsg_szresult));
1227         case LINUX_RECVFROM:
1228                 return (linux_recvfrom(arg, &args->sysmsg_szresult));
1229         case LINUX_SHUTDOWN:
1230                 return (linux_shutdown(arg, &args->sysmsg_result));
1231         case LINUX_SETSOCKOPT:
1232                 return (linux_setsockopt(arg, &args->sysmsg_result));
1233         case LINUX_GETSOCKOPT:
1234                 return (linux_getsockopt(arg, &args->sysmsg_result));
1235         case LINUX_SENDMSG:
1236                 return (linux_sendmsg(arg, &args->sysmsg_szresult));
1237         case LINUX_RECVMSG:
1238                 return (linux_recvmsg(arg, &args->sysmsg_szresult));
1239         }
1240         rel_mplock();
1241
1242         uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1243         return (ENOSYS);
1244 }