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