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