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