kernel - linux emulation - fix linux socketcall MP mismatch
[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 <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         MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
108         error = copyin(uaddr, sa, sa_len);
109         if (error) {
110                 FREE(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         case LINUX_AF_APPLETALK:
157                 return (AF_APPLETALK);
158         }
159         return (-1);
160 }
161
162 static int
163 linux_to_bsd_sockopt_level(int level)
164 {
165
166         switch (level) {
167         case LINUX_SOL_SOCKET:
168                 return (SOL_SOCKET);
169         }
170         return (level);
171 }
172
173 static int
174 linux_to_bsd_ip_sockopt(int opt)
175 {
176
177         switch (opt) {
178         case LINUX_IP_TOS:
179                 return (IP_TOS);
180         case LINUX_IP_TTL:
181                 return (IP_TTL);
182         case LINUX_IP_OPTIONS:
183                 return (IP_OPTIONS);
184         case LINUX_IP_MULTICAST_IF:
185                 return (IP_MULTICAST_IF);
186         case LINUX_IP_MULTICAST_TTL:
187                 return (IP_MULTICAST_TTL);
188         case LINUX_IP_MULTICAST_LOOP:
189                 return (IP_MULTICAST_LOOP);
190         case LINUX_IP_ADD_MEMBERSHIP:
191                 return (IP_ADD_MEMBERSHIP);
192         case LINUX_IP_DROP_MEMBERSHIP:
193                 return (IP_DROP_MEMBERSHIP);
194         case LINUX_IP_HDRINCL:
195                 return (IP_HDRINCL);
196         }
197         return (-1);
198 }
199
200 static int
201 linux_to_bsd_so_sockopt(int opt)
202 {
203
204         switch (opt) {
205         case LINUX_SO_DEBUG:
206                 return (SO_DEBUG);
207         case LINUX_SO_REUSEADDR:
208                 return (SO_REUSEADDR);
209         case LINUX_SO_TYPE:
210                 return (SO_TYPE);
211         case LINUX_SO_ERROR:
212                 return (SO_ERROR);
213         case LINUX_SO_DONTROUTE:
214                 return (SO_DONTROUTE);
215         case LINUX_SO_BROADCAST:
216                 return (SO_BROADCAST);
217         case LINUX_SO_SNDBUF:
218                 return (SO_SNDBUF);
219         case LINUX_SO_RCVBUF:
220                 return (SO_RCVBUF);
221         case LINUX_SO_KEEPALIVE:
222                 return (SO_KEEPALIVE);
223         case LINUX_SO_OOBINLINE:
224                 return (SO_OOBINLINE);
225         case LINUX_SO_LINGER:
226                 return (SO_LINGER);
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         FREE(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         FREE(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
437                 if (error) {
438                         /*
439                          * Return a namelen of zero for older code which
440                          * might ignore the return value from accept().
441                          */
442                         sa_len = 0;
443                         copyout(&sa_len, linux_args.namelen,
444                             sizeof(*linux_args.namelen));
445                 } else {
446                         error = linux_copyout_sockaddr(sa, linux_args.addr,
447                             sa_len);
448                         if (error == 0) {
449                                 error = copyout(&sa_len, linux_args.namelen,
450                                     sizeof(*linux_args.namelen));
451                         }
452                 }
453                 if (sa)
454                         FREE(sa, M_SONAME);
455         } else {
456                 error = kern_accept(linux_args.s, 0, NULL, 0, res);
457         }
458
459         if (error)
460                 return (error);
461
462         /*
463          * linux appears not to copy flags from the parent socket to the
464          * accepted one, so we must clear the flags in the new descriptor.
465          * Ignore any errors, because we already have an open fd.
466          */
467         kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
468         return (0);
469 }
470
471 struct linux_getsockname_args {
472         int s;
473         struct sockaddr *addr;
474         int *namelen;
475 };
476
477 static int
478 linux_getsockname(struct linux_getsockname_args *args, int *res)
479 {
480         struct linux_getsockname_args linux_args;
481         struct sockaddr *sa = NULL;
482         int error, sa_len;
483          
484
485         error = copyin(args, &linux_args, sizeof(linux_args));
486         if (error)
487                 return (error);
488         error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
489         if (error)
490                 return (error);
491
492         error = kern_getsockname(linux_args.s, &sa, &sa_len);
493
494         if (error == 0)
495                 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
496         if (error == 0)
497                 error = copyout(&sa_len, linux_args.namelen,
498                     sizeof(*linux_args.namelen));
499         if (sa)
500                 FREE(sa, M_SONAME);
501         return(error);
502 }
503
504 struct linux_getpeername_args {
505         int s;
506         struct sockaddr *addr;
507         int *namelen;
508 };
509
510 static int
511 linux_getpeername(struct linux_getpeername_args *args, int *res)
512 {
513         struct linux_getpeername_args linux_args;
514         struct sockaddr *sa = NULL;
515         int error, sa_len;
516
517         error = copyin(args, &linux_args, sizeof(linux_args));
518         if (error)
519                 return (error);
520         error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
521         if (error)
522                 return (error);
523
524         error = kern_getpeername(linux_args.s, &sa, &sa_len);
525
526         if (error == 0)
527                 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
528         if (error == 0)
529                 error = copyout(&sa_len, linux_args.namelen,
530                     sizeof(*linux_args.namelen));
531         if (sa)
532                 FREE(sa, M_SONAME);
533         return(error);
534 }
535
536 struct linux_socketpair_args {
537         int domain;
538         int type;
539         int protocol;
540         int *rsv;
541 };
542
543 static int
544 linux_socketpair(struct linux_socketpair_args *args, int *res)
545 {
546         struct linux_socketpair_args linux_args;
547         int error, domain, sockv[2];
548
549         error = copyin(args, &linux_args, sizeof(linux_args));
550         if (error)
551                 return (error);
552
553         domain = linux_to_bsd_domain(linux_args.domain);
554         if (domain == -1)
555                 return (EINVAL);
556         error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
557             sockv);
558
559         if (error == 0)
560                 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
561         return(error);
562 }
563
564 struct linux_send_args {
565         int s;
566         void *msg;
567         int len;
568         int flags;
569 };
570
571 static int
572 linux_send(struct linux_send_args *args, size_t *res)
573 {
574         struct linux_send_args linux_args;
575         struct thread *td = curthread;
576         struct uio auio;
577         struct iovec aiov;
578         int error;
579
580         error = copyin(args, &linux_args, sizeof(linux_args));
581         if (error)
582                 return (error);
583
584         aiov.iov_base = linux_args.msg;
585         aiov.iov_len = linux_args.len;
586         auio.uio_iov = &aiov;
587         auio.uio_iovcnt = 1;
588         auio.uio_offset = 0;
589         auio.uio_resid = linux_args.len;
590         auio.uio_segflg = UIO_USERSPACE;
591         auio.uio_rw = UIO_WRITE;
592         auio.uio_td = td;
593
594         error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
595                              linux_args.flags, res);
596
597         return(error);
598 }
599
600 struct linux_recv_args {
601         int s;
602         void *msg;
603         int len;
604         int flags;
605 };
606
607 static int
608 linux_recv(struct linux_recv_args *args, size_t *res)
609 {
610         struct linux_recv_args linux_args;
611         struct thread *td = curthread;
612         struct uio auio;
613         struct iovec aiov;
614         int error;
615
616         error = copyin(args, &linux_args, sizeof(linux_args));
617         if (error)
618                 return (error);
619
620         aiov.iov_base = linux_args.msg;
621         aiov.iov_len = linux_args.len;
622         auio.uio_iov = &aiov;
623         auio.uio_iovcnt = 1;
624         auio.uio_offset = 0;
625         auio.uio_resid = linux_args.len;
626         auio.uio_segflg = UIO_USERSPACE;
627         auio.uio_rw = UIO_READ;
628         auio.uio_td = td;
629
630         error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
631                              &linux_args.flags, res);
632
633         return(error);
634 }
635
636 struct linux_sendto_args {
637         int s;
638         void *msg;
639         int len;
640         int flags;
641         struct sockaddr *to;
642         int tolen;
643 };
644
645 static int
646 linux_sendto(struct linux_sendto_args *args, size_t *res)
647 {
648         struct linux_sendto_args linux_args;
649         struct thread *td = curthread;
650         struct uio auio;
651         struct iovec aiov;
652         struct sockopt sopt;
653         struct sockaddr *sa = NULL;
654         caddr_t msg = NULL;
655         int error, optval;
656
657         error = copyin(args, &linux_args, sizeof(linux_args));
658         if (error)
659                 return (error);
660
661         if (linux_args.to) {
662                 error = linux_getsockaddr(&sa, linux_args.to,
663                     linux_args.tolen);
664                 if (error)
665                         return (error);
666         }
667
668         /*
669          * Check to see if the IP_HDRINCL option is set.
670          */
671         sopt.sopt_dir = SOPT_GET;
672         sopt.sopt_level = IPPROTO_IP;
673         sopt.sopt_name = IP_HDRINCL;
674         sopt.sopt_val = &optval;
675         sopt.sopt_valsize = sizeof(optval);
676         sopt.sopt_td = NULL;
677
678         if (kern_getsockopt(linux_args.s, &sopt) != 0)
679                 optval = 0;
680
681         if (optval == 0) {
682                 /*
683                  * IP_HDRINCL is not set.  Package the message as usual.
684                  */
685                 aiov.iov_base = linux_args.msg;
686                 aiov.iov_len = linux_args.len;
687                 auio.uio_iov = &aiov;
688                 auio.uio_iovcnt = 1;
689                 auio.uio_offset = 0;
690                 auio.uio_resid = linux_args.len;
691                 auio.uio_segflg = UIO_USERSPACE;
692                 auio.uio_rw = UIO_WRITE;
693                 auio.uio_td = td;
694         } else {
695                 /*
696                  * IP_HDRINCL is set.  We must convert the beginning of
697                  * the packet header so we can feed it to the BSD kernel.
698                  */
699
700                 /*
701                  * Check that the packet header is long enough to contain
702                  * the fields of interest.  This relies on the fact that
703                  * the fragment offset field comes after the length field.
704                  */
705                 if (linux_args.len < offsetof(struct ip, ip_off))
706                         return (EINVAL);
707
708                 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
709                 error = copyin(linux_args.msg, msg, linux_args.len);
710                 if (error)
711                         goto cleanup;
712
713                 /* Fix the ip_len and ip_off fields.  */
714                 ((struct ip *)msg)->ip_len = linux_args.len;
715                 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
716
717                 aiov.iov_base = msg;
718                 aiov.iov_len = linux_args.len;
719                 auio.uio_iov = &aiov;
720                 auio.uio_iovcnt = 1;
721                 auio.uio_offset = 0;
722                 auio.uio_resid = linux_args.len;
723                 auio.uio_segflg = UIO_SYSSPACE;
724                 auio.uio_rw = UIO_WRITE;
725                 auio.uio_td = td;
726         }
727
728         error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
729                              linux_args.flags, res);
730
731 cleanup:
732         if (sa)
733                 FREE(sa, M_SONAME);
734         if (msg)
735                 FREE(msg, M_LINUX);
736         return(error);
737 }
738
739 struct linux_recvfrom_args {
740         int s;
741         void *buf;
742         int len;
743         int flags;
744         struct sockaddr *from;
745         int *fromlen;
746 };
747
748 static int
749 linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
750 {
751         struct linux_recvfrom_args linux_args;
752         struct thread *td = curthread;
753         struct uio auio;
754         struct iovec aiov;
755         struct sockaddr *sa = NULL;
756         int error, fromlen, flags;
757
758         error = copyin(args, &linux_args, sizeof(linux_args));
759         if (error)
760                 return (error);
761
762         if (linux_args.from && linux_args.fromlen) {
763                 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
764                 if (error)
765                         return (error);
766                 if (fromlen < 0)
767                         return (EINVAL);
768         } else {
769                 fromlen = 0;
770         }
771         aiov.iov_base = linux_args.buf;
772         aiov.iov_len = linux_args.len;
773         auio.uio_iov = &aiov;
774         auio.uio_iovcnt = 1;
775         auio.uio_offset = 0;
776         auio.uio_resid = linux_args.len;
777         auio.uio_segflg = UIO_USERSPACE;
778         auio.uio_rw = UIO_READ;
779         auio.uio_td = td;
780
781         flags = linux_to_bsd_msg_flags(linux_args.flags);
782
783         error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
784                              NULL, &flags, res);
785
786         if (error == 0 && linux_args.from) {
787                 if (sa != NULL) {
788                         fromlen = MIN(fromlen, sa->sa_len);
789                         error = linux_copyout_sockaddr(sa, linux_args.from,
790                                                         fromlen);
791                 } else
792                         fromlen = 0;
793                 if (error == 0)
794                         copyout(&fromlen, linux_args.fromlen,
795                             sizeof(fromlen));
796         }
797         if (sa)
798                 FREE(sa, M_SONAME);
799
800         return(error);
801 }
802
803 struct linux_sendmsg_args {
804         int s;
805         struct msghdr *msg;
806         int flags;
807 };
808
809 static int
810 linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
811 {
812         struct linux_sendmsg_args linux_args;
813         struct thread *td = curthread;
814         struct msghdr msg;
815         struct uio auio;
816         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
817         struct sockaddr *sa = NULL;
818         struct mbuf *control = NULL;
819         int error;
820
821         error = copyin(args, &linux_args, sizeof(linux_args));
822         if (error)
823                 return (error);
824
825         error = copyin(linux_args.msg, &msg, sizeof(msg));
826         if (error)
827                 return (error);
828
829         /*
830          * Conditionally copyin msg.msg_name.
831          */
832         if (msg.msg_name) {
833                 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
834                 if (error)
835                         return (error);
836         }
837
838         /*
839          * Populate auio.
840          */
841         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
842                              &auio.uio_resid);
843         if (error)
844                 goto cleanup2;
845         auio.uio_iov = iov;
846         auio.uio_iovcnt = msg.msg_iovlen;
847         auio.uio_offset = 0;
848         auio.uio_segflg = UIO_USERSPACE;
849         auio.uio_rw = UIO_WRITE;
850         auio.uio_td = td;
851
852         /*
853          * Conditionally copyin msg.msg_control.
854          */
855         if (msg.msg_control) {
856                 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
857                     msg.msg_controllen > MLEN) {
858                         error = EINVAL;
859                         goto cleanup;
860                 }
861                 control = m_get(MB_WAIT, MT_CONTROL);
862                 if (control == NULL) {
863                         error = ENOBUFS;
864                         goto cleanup;
865                 }
866                 control->m_len = msg.msg_controllen;
867                 error = copyin(msg.msg_control, mtod(control, caddr_t),
868                     msg.msg_controllen);
869                 if (error) {
870                         m_free(control);
871                         goto cleanup;
872                 }
873                 /*
874                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
875                  * wants anything else with an option level of SOL_SOCKET,
876                  * we don't support it.
877                  */
878                 if (mtod(control, struct cmsghdr *)->cmsg_level ==
879                     SOL_SOCKET &&
880                     mtod(control, struct cmsghdr *)->cmsg_type !=
881                     SCM_RIGHTS) {
882                         m_free(control);
883                         error = EINVAL;
884                         goto cleanup;
885                 }
886         }
887
888         error = kern_sendmsg(linux_args.s, sa, &auio, control,
889                              linux_args.flags, res);
890
891 cleanup:
892         iovec_free(&iov, aiov);
893 cleanup2:
894         if (sa)
895                 FREE(sa, M_SONAME);
896         return (error);
897 }
898
899 struct linux_recvmsg_args {
900         int s;
901         struct msghdr *msg;
902         int flags;
903 };
904
905 static int
906 linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
907 {
908         struct linux_recvmsg_args linux_args;
909         struct thread *td = curthread;
910         struct msghdr msg;
911         struct uio auio;
912         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
913         struct mbuf *m, *control = NULL;
914         struct sockaddr *sa = NULL;
915         caddr_t ctlbuf;
916         socklen_t *ufromlenp, *ucontrollenp;
917         int error, fromlen, controllen, len, flags, *uflagsp;
918
919         error = copyin(args, &linux_args, sizeof(linux_args));
920         if (error)
921                 return (error);
922
923         error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
924         if (error)
925                 return (error);
926
927         if (msg.msg_name && msg.msg_namelen < 0)
928                 return (EINVAL);
929         if (msg.msg_control && msg.msg_controllen < 0)
930                 return (EINVAL);
931
932         ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
933             offsetof(struct msghdr, msg_namelen));
934         ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
935             offsetof(struct msghdr, msg_controllen));
936         uflagsp = (int *)((caddr_t)linux_args.msg +
937             offsetof(struct msghdr, msg_flags));
938
939         /*
940          * Populate auio.
941          */
942         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
943                              &auio.uio_resid);
944         if (error)
945                 return (error);
946         auio.uio_iov = iov;
947         auio.uio_iovcnt = msg.msg_iovlen;
948         auio.uio_offset = 0;
949         auio.uio_segflg = UIO_USERSPACE;
950         auio.uio_rw = UIO_READ;
951         auio.uio_td = td;
952
953         flags = linux_to_bsd_msg_flags(linux_args.flags);
954
955         error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
956                              msg.msg_control ? &control : NULL, &flags, res);
957
958         /*
959          * Copyout msg.msg_name and msg.msg_namelen.
960          */
961         if (error == 0 && msg.msg_name) {
962                 if (sa != NULL) {
963                         fromlen = MIN(msg.msg_namelen, sa->sa_len);
964                         error = linux_copyout_sockaddr(sa, msg.msg_name,
965                                                         fromlen);
966                 } else
967                         fromlen = 0;
968                 if (error == 0)
969                         error = copyout(&fromlen, ufromlenp,
970                             sizeof(*ufromlenp));
971         }
972
973         /*
974          * Copyout msg.msg_control and msg.msg_controllen.
975          */
976         if (error == 0 && msg.msg_control) {
977                 /*
978                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
979                  * wants anything else with an option level of SOL_SOCKET,
980                  * we don't support it.
981                  */
982                 if (mtod((struct mbuf *)msg.msg_control,
983                     struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
984                     mtod((struct mbuf *)msg.msg_control,
985                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
986                         error = EINVAL;
987                         goto cleanup;
988                 }
989
990                 len = msg.msg_controllen;
991                 m = control;
992                 ctlbuf = (caddr_t)msg.msg_control;
993
994                 while (m && len > 0) {
995                         unsigned int tocopy;
996
997                         if (len >= m->m_len) {
998                                 tocopy = m->m_len;
999                         } else {
1000                                 msg.msg_flags |= MSG_CTRUNC;
1001                                 tocopy = len;
1002                         }
1003
1004                         error = copyout(mtod(m, caddr_t), ctlbuf,
1005                             tocopy);
1006                         if (error)
1007                                 goto cleanup;
1008
1009                         ctlbuf += tocopy;
1010                         len -= tocopy;
1011                         m = m->m_next;
1012                 }
1013                 controllen = ctlbuf - (caddr_t)msg.msg_control;
1014                 error = copyout(&controllen, ucontrollenp,
1015                     sizeof(*ucontrollenp));
1016         }
1017
1018         if (error == 0)
1019                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1020
1021 cleanup:
1022         if (sa)
1023                 FREE(sa, M_SONAME);
1024         iovec_free(&iov, aiov);
1025         if (control)
1026                 m_freem(control);
1027         return (error);
1028 }
1029
1030 struct linux_shutdown_args {
1031         int s;
1032         int how;
1033 };
1034
1035 static int
1036 linux_shutdown(struct linux_shutdown_args *args, int *res)
1037 {
1038         struct linux_shutdown_args linux_args;
1039         int error;
1040
1041         error = copyin(args, &linux_args, sizeof(linux_args));
1042         if (error)
1043                 return (error);
1044
1045         error = kern_shutdown(linux_args.s, linux_args.how);
1046
1047         return (error);
1048 }
1049
1050 struct linux_setsockopt_args {
1051         int s;
1052         int level;
1053         int optname;
1054         void *optval;
1055         int optlen;
1056 };
1057
1058 static int
1059 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1060 {
1061         struct linux_setsockopt_args linux_args;
1062         struct thread *td = curthread;
1063         struct sockopt sopt;
1064         int error, name, level;
1065
1066         error = copyin(args, &linux_args, sizeof(linux_args));
1067         if (error)
1068                 return (error);
1069
1070         level = linux_to_bsd_sockopt_level(linux_args.level);
1071         switch (level) {
1072         case SOL_SOCKET:
1073                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1074                 break;
1075         case IPPROTO_IP:
1076                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1077                 break;
1078         case IPPROTO_TCP:
1079                 /* Linux TCP option values match BSD's */
1080                 name = linux_args.optname;
1081                 break;
1082         default:
1083                 name = -1;
1084                 break;
1085         }
1086         if (name == -1)
1087                 return (EINVAL);
1088
1089         sopt.sopt_dir = SOPT_SET;
1090         sopt.sopt_level = level;
1091         sopt.sopt_name = name;
1092         sopt.sopt_valsize = linux_args.optlen;
1093         sopt.sopt_td = td;
1094
1095         if (sopt.sopt_valsize < 0 || sopt.sopt_valsize > SOMAXOPT_SIZE)
1096                 return (EINVAL);
1097
1098         if (linux_args.optval) {
1099                 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1100                 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1101                 if (error)
1102                         goto out;
1103         } else {
1104                 sopt.sopt_val = NULL;
1105         }
1106         error = kern_setsockopt(linux_args.s, &sopt);
1107         if (error)
1108                 goto out;
1109         if (linux_args.optval)
1110                 error = copyout(sopt.sopt_val, linux_args.optval,
1111                                 sopt.sopt_valsize);
1112 out:
1113         if (linux_args.optval)
1114                 kfree(sopt.sopt_val, M_TEMP);
1115         return(error);
1116 }
1117
1118 struct linux_getsockopt_args {
1119         int s;
1120         int level;
1121         int optname;
1122         void *optval;
1123         int *optlen;
1124 };
1125
1126 static int
1127 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1128 {
1129         struct linux_getsockopt_args linux_args;
1130         struct thread *td = curthread;
1131         struct sockopt sopt;
1132         int error, name, valsize, level;
1133
1134         error = copyin(args, &linux_args, sizeof(linux_args));
1135         if (error)
1136                 return (error);
1137
1138         if (linux_args.optval) {
1139                 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1140                 if (error)
1141                         return (error);
1142                 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1143                         return (EINVAL);
1144         } else {
1145                 valsize = 0;
1146         }
1147
1148         level = linux_to_bsd_sockopt_level(linux_args.level);
1149         switch (level) {
1150         case SOL_SOCKET:
1151                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1152                 break;
1153         case IPPROTO_IP:
1154                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1155                 break;
1156         case IPPROTO_TCP:
1157                 /* Linux TCP option values match BSD's */
1158                 name = linux_args.optname;
1159                 break;
1160         default:
1161                 name = -1;
1162                 break;
1163         }
1164         if (name == -1)
1165                 return (EINVAL);
1166
1167         sopt.sopt_dir = SOPT_GET;
1168         sopt.sopt_level = level;
1169         sopt.sopt_name = name;
1170         sopt.sopt_valsize = valsize;
1171         sopt.sopt_td = td;
1172
1173         if (linux_args.optval) {
1174                 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1175                 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1176                 if (error)
1177                         goto out;
1178         } else {
1179                 sopt.sopt_val = NULL;
1180         }
1181         error = kern_getsockopt(linux_args.s, &sopt);
1182         if (error)
1183                 goto out;
1184         valsize = sopt.sopt_valsize;
1185         error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1186         if (error)
1187                 goto out;
1188         if (linux_args.optval)
1189                 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1190 out:
1191         if (linux_args.optval)
1192                 kfree(sopt.sopt_val, M_TEMP);
1193         return(error);
1194 }
1195
1196 /*
1197  * MPALMOSTSAFE
1198  */
1199 int
1200 sys_linux_socketcall(struct linux_socketcall_args *args)
1201 {
1202         void *arg = (void *)args->args;
1203         int error;
1204
1205         get_mplock();
1206
1207         switch (args->what) {
1208         case LINUX_SOCKET:
1209                 error = linux_socket(arg, &args->sysmsg_result);
1210                 break;
1211         case LINUX_BIND:
1212                 error = linux_bind(arg, &args->sysmsg_result);
1213                 break;
1214         case LINUX_CONNECT:
1215                 error = linux_connect(arg, &args->sysmsg_result);
1216                 break;
1217         case LINUX_LISTEN:
1218                 error = linux_listen(arg, &args->sysmsg_result);
1219                 break;
1220         case LINUX_ACCEPT:
1221                 error = linux_accept(arg, &args->sysmsg_result);
1222                 break;
1223         case LINUX_GETSOCKNAME:
1224                 error = linux_getsockname(arg, &args->sysmsg_result);
1225                 break;
1226         case LINUX_GETPEERNAME:
1227                 error = linux_getpeername(arg, &args->sysmsg_result);
1228                 break;
1229         case LINUX_SOCKETPAIR:
1230                 error = linux_socketpair(arg, &args->sysmsg_result);
1231                 break;
1232         case LINUX_SEND:
1233                 error = linux_send(arg, &args->sysmsg_szresult);
1234                 break;
1235         case LINUX_RECV:
1236                 error = linux_recv(arg, &args->sysmsg_szresult);
1237                 break;
1238         case LINUX_SENDTO:
1239                 error = linux_sendto(arg, &args->sysmsg_szresult);
1240                 break;
1241         case LINUX_RECVFROM:
1242                 error = linux_recvfrom(arg, &args->sysmsg_szresult);
1243                 break;
1244         case LINUX_SHUTDOWN:
1245                 error = linux_shutdown(arg, &args->sysmsg_result);
1246                 break;
1247         case LINUX_SETSOCKOPT:
1248                 error = linux_setsockopt(arg, &args->sysmsg_result);
1249                 break;
1250         case LINUX_GETSOCKOPT:
1251                 error = linux_getsockopt(arg, &args->sysmsg_result);
1252                 break;
1253         case LINUX_SENDMSG:
1254                 error = linux_sendmsg(arg, &args->sysmsg_szresult);
1255                 break;
1256         case LINUX_RECVMSG:
1257                 error = linux_recvmsg(arg, &args->sysmsg_szresult);
1258                 break;
1259         default:
1260                 uprintf("LINUX: 'socket' typ=%d not implemented\n",
1261                         args->what);
1262                 error = ENOSYS;
1263                 break;
1264         }
1265         rel_mplock();
1266 }