Make setthetime() static per the prototype.
[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.18 2004/06/02 14:42:57 eirikn 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         if (kern_getsockopt(linux_args.s, &sopt) != 0)
681                 optval = 0;
682
683         if (optval == 0) {
684                 /*
685                  * IP_HDRINCL is not set.  Package the message as usual.
686                  */
687                 aiov.iov_base = linux_args.msg;
688                 aiov.iov_len = linux_args.len;
689                 auio.uio_iov = &aiov;
690                 auio.uio_iovcnt = 1;
691                 auio.uio_offset = 0;
692                 auio.uio_resid = linux_args.len;
693                 auio.uio_segflg = UIO_USERSPACE;
694                 auio.uio_rw = UIO_WRITE;
695                 auio.uio_td = td;
696         } else {
697                 /*
698                  * IP_HDRINCL is set.  We must convert the beginning of
699                  * the packet header so we can feed it to the BSD kernel.
700                  */
701
702                 /*
703                  * Check that the packet header is long enough to contain
704                  * the fields of interest.  This relies on the fact that
705                  * the fragment offset field comes after the length field.
706                  */
707                 if (linux_args.len < offsetof(struct ip, ip_off))
708                         return (EINVAL);
709
710                 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
711                 error = copyin(linux_args.msg, msg, linux_args.len);
712                 if (error)
713                         goto cleanup;
714
715                 /* Fix the ip_len and ip_off fields.  */
716                 ((struct ip *)msg)->ip_len = linux_args.len;
717                 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
718
719                 aiov.iov_base = msg;
720                 aiov.iov_len = linux_args.len;
721                 auio.uio_iov = &aiov;
722                 auio.uio_iovcnt = 1;
723                 auio.uio_offset = 0;
724                 auio.uio_resid = linux_args.len;
725                 auio.uio_segflg = UIO_SYSSPACE;
726                 auio.uio_rw = UIO_WRITE;
727                 auio.uio_td = td;
728         }
729
730         error = kern_sendmsg(linux_args.s, sa, &auio, NULL, linux_args.flags,
731             res);
732
733 cleanup:
734         if (sa)
735                 FREE(sa, M_SONAME);
736         if (msg)
737                 FREE(msg, M_LINUX);
738         return(error);
739 }
740
741 struct linux_recvfrom_args {
742         int s;
743         void *buf;
744         int len;
745         int flags;
746         struct sockaddr *from;
747         int *fromlen;
748 };
749
750 static int
751 linux_recvfrom(struct linux_recvfrom_args *args, int *res)
752 {
753         struct linux_recvfrom_args linux_args;
754         struct thread *td = curthread;
755         struct uio auio;
756         struct iovec aiov;
757         struct sockaddr *sa = NULL;
758         int error, fromlen, flags;
759
760         error = copyin(args, &linux_args, sizeof(linux_args));
761         if (error)
762                 return (error);
763
764         if (linux_args.from && linux_args.fromlen) {
765                 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
766                 if (error)
767                         return (error);
768                 if (fromlen < 0)
769                         return (EINVAL);
770         } else {
771                 fromlen = 0;
772         }
773         aiov.iov_base = linux_args.buf;
774         aiov.iov_len = linux_args.len;
775         auio.uio_iov = &aiov;
776         auio.uio_iovcnt = 1;
777         auio.uio_offset = 0;
778         auio.uio_resid = linux_args.len;
779         auio.uio_segflg = UIO_USERSPACE;
780         auio.uio_rw = UIO_READ;
781         auio.uio_td = td;
782
783         flags = linux_to_bsd_msg_flags(linux_args.flags);
784
785         error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
786             NULL, &flags, res);
787
788         if (error == 0 && linux_args.from) {
789                 fromlen = MIN(fromlen, sa->sa_len);
790                 error = linux_copyout_sockaddr(sa, linux_args.from, fromlen);
791                 if (error == 0)
792                         copyout(&fromlen, linux_args.fromlen,
793                             sizeof(fromlen));
794         }
795         if (sa)
796                 FREE(sa, M_SONAME);
797
798         return(error);
799 }
800
801 struct linux_sendmsg_args {
802         int s;
803         struct msghdr *msg;
804         int flags;
805 };
806
807 static int
808 linux_sendmsg(struct linux_sendmsg_args *args, int *res)
809 {
810         struct linux_sendmsg_args linux_args;
811         struct thread *td = curthread;
812         struct msghdr msg;
813         struct uio auio;
814         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
815         struct sockaddr *sa = NULL;
816         struct mbuf *control = NULL;
817         int error;
818
819         error = copyin(args, &linux_args, sizeof(linux_args));
820         if (error)
821                 return (error);
822
823         error = copyin(linux_args.msg, &msg, sizeof(msg));
824         if (error)
825                 return (error);
826
827         /*
828          * Conditionally copyin msg.msg_name.
829          */
830         if (msg.msg_name) {
831                 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
832                 if (error)
833                         return (error);
834         }
835
836         /*
837          * Populate auio.
838          */
839         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
840            &auio.uio_resid);
841         if (error)
842                 goto cleanup;
843         auio.uio_iov = iov;
844         auio.uio_iovcnt = msg.msg_iovlen;
845         auio.uio_offset = 0;
846         auio.uio_segflg = UIO_USERSPACE;
847         auio.uio_rw = UIO_WRITE;
848         auio.uio_td = td;
849
850         /*
851          * Conditionally copyin msg.msg_control.
852          */
853         if (msg.msg_control) {
854                 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
855                     msg.msg_controllen > MLEN) {
856                         error = EINVAL;
857                         goto cleanup;
858                 }
859                 control = m_get(MB_WAIT, MT_CONTROL);
860                 if (control == NULL) {
861                         error = ENOBUFS;
862                         goto cleanup;
863                 }
864                 control->m_len = msg.msg_controllen;
865                 error = copyin(msg.msg_control, mtod(control, caddr_t),
866                     msg.msg_controllen);
867                 if (error) {
868                         m_free(control);
869                         goto cleanup;
870                 }
871                 /*
872                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
873                  * wants anything else with an option level of SOL_SOCKET,
874                  * we don't support it.
875                  */
876                 if (mtod(control, struct cmsghdr *)->cmsg_level ==
877                     SOL_SOCKET &&
878                     mtod(control, struct cmsghdr *)->cmsg_type !=
879                     SCM_RIGHTS) {
880                         m_free(control);
881                         error = EINVAL;
882                         goto cleanup;
883                 }
884         }
885
886         error = kern_sendmsg(linux_args.s, sa, &auio, control,
887             linux_args.flags, res);
888
889 cleanup:
890         if (sa)
891                 FREE(sa, M_SONAME);
892         iovec_free(&iov, aiov);
893         return (error);
894 }
895
896 struct linux_recvmsg_args {
897         int s;
898         struct msghdr *msg;
899         int flags;
900 };
901
902 static int
903 linux_recvmsg(struct linux_recvmsg_args *args, int *res)
904 {
905         struct linux_recvmsg_args linux_args;
906         struct thread *td = curthread;
907         struct msghdr msg;
908         struct uio auio;
909         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
910         struct mbuf *m, *control = NULL;
911         struct sockaddr *sa = NULL;
912         caddr_t ctlbuf;
913         socklen_t *ufromlenp, *ucontrollenp;
914         int error, fromlen, controllen, len, flags, *uflagsp;
915
916         error = copyin(args, &linux_args, sizeof(linux_args));
917         if (error)
918                 return (error);
919
920         error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
921         if (error)
922                 return (error);
923
924         if (msg.msg_name && msg.msg_namelen < 0)
925                 return (EINVAL);
926         if (msg.msg_control && msg.msg_controllen < 0)
927                 return (EINVAL);
928
929         ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
930             offsetof(struct msghdr, msg_namelen));
931         ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
932             offsetof(struct msghdr, msg_controllen));
933         uflagsp = (int *)((caddr_t)linux_args.msg +
934             offsetof(struct msghdr, msg_flags));
935
936         /*
937          * Populate auio.
938          */
939         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
940             &auio.uio_resid);
941         if (error)
942                 return (error);
943         auio.uio_iov = iov;
944         auio.uio_iovcnt = msg.msg_iovlen;
945         auio.uio_offset = 0;
946         auio.uio_segflg = UIO_USERSPACE;
947         auio.uio_rw = UIO_READ;
948         auio.uio_td = td;
949
950         flags = linux_to_bsd_msg_flags(linux_args.flags);
951
952         error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
953             msg.msg_control ? &control : NULL, &flags, res);
954
955         /*
956          * Copyout msg.msg_name and msg.msg_namelen.
957          */
958         if (error == 0 && msg.msg_name) {
959                 fromlen = MIN(msg.msg_namelen, sa->sa_len);
960                 error = linux_copyout_sockaddr(sa, msg.msg_name, fromlen);
961                 if (error == 0)
962                         error = copyout(&fromlen, ufromlenp,
963                             sizeof(*ufromlenp));
964         }
965
966         /*
967          * Copyout msg.msg_control and msg.msg_controllen.
968          */
969         if (error == 0 && msg.msg_control) {
970                 /*
971                  * Linux and BSD both support SCM_RIGHTS.  If a linux binary
972                  * wants anything else with an option level of SOL_SOCKET,
973                  * we don't support it.
974                  */
975                 if (mtod((struct mbuf *)msg.msg_control,
976                     struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
977                     mtod((struct mbuf *)msg.msg_control,
978                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
979                         error = EINVAL;
980                         goto cleanup;
981                 }
982
983                 len = msg.msg_controllen;
984                 m = control;
985                 ctlbuf = (caddr_t)msg.msg_control;
986
987                 while (m && len > 0) {
988                         unsigned int tocopy;
989
990                         if (len >= m->m_len) {
991                                 tocopy = m->m_len;
992                         } else {
993                                 msg.msg_flags |= MSG_CTRUNC;
994                                 tocopy = len;
995                         }
996
997                         error = copyout(mtod(m, caddr_t), ctlbuf,
998                             tocopy);
999                         if (error)
1000                                 goto cleanup;
1001
1002                         ctlbuf += tocopy;
1003                         len -= tocopy;
1004                         m = m->m_next;
1005                 }
1006                 controllen = ctlbuf - (caddr_t)msg.msg_control;
1007                 error = copyout(&controllen, ucontrollenp,
1008                     sizeof(*ucontrollenp));
1009         }
1010
1011         if (error == 0)
1012                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1013
1014 cleanup:
1015         if (sa)
1016                 FREE(sa, M_SONAME);
1017         iovec_free(&iov, aiov);
1018         if (control)
1019                 m_freem(control);
1020         return (error);
1021 }
1022
1023 struct linux_shutdown_args {
1024         int s;
1025         int how;
1026 };
1027
1028 static int
1029 linux_shutdown(struct linux_shutdown_args *args, int *res)
1030 {
1031         struct linux_shutdown_args linux_args;
1032         int error;
1033
1034         error = copyin(args, &linux_args, sizeof(linux_args));
1035         if (error)
1036                 return (error);
1037
1038         error = kern_shutdown(linux_args.s, linux_args.how);
1039
1040         return (error);
1041 }
1042
1043 struct linux_setsockopt_args {
1044         int s;
1045         int level;
1046         int optname;
1047         void *optval;
1048         int optlen;
1049 };
1050
1051 static int
1052 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1053 {
1054         struct linux_setsockopt_args linux_args;
1055         struct thread *td = curthread;
1056         struct sockopt sopt;
1057         int error, name, level;
1058
1059         error = copyin(args, &linux_args, sizeof(linux_args));
1060         if (error)
1061                 return (error);
1062
1063         level = linux_to_bsd_sockopt_level(linux_args.level);
1064         switch (level) {
1065         case SOL_SOCKET:
1066                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1067                 break;
1068         case IPPROTO_IP:
1069                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1070                 break;
1071         case IPPROTO_TCP:
1072                 /* Linux TCP option values match BSD's */
1073                 name = linux_args.optname;
1074                 break;
1075         default:
1076                 name = -1;
1077                 break;
1078         }
1079         if (name == -1)
1080                 return (EINVAL);
1081
1082         sopt.sopt_dir = SOPT_SET;
1083         sopt.sopt_level = level;
1084         sopt.sopt_name = name;
1085         sopt.sopt_val = linux_args.optval;
1086         sopt.sopt_valsize = linux_args.optlen;
1087         sopt.sopt_td = td;
1088
1089         error = kern_setsockopt(linux_args.s, &sopt);
1090         return(error);
1091 }
1092
1093 struct linux_getsockopt_args {
1094         int s;
1095         int level;
1096         int optname;
1097         void *optval;
1098         int *optlen;
1099 };
1100
1101 static int
1102 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1103 {
1104         struct linux_getsockopt_args linux_args;
1105         struct thread *td = curthread;
1106         struct sockopt sopt;
1107         int error, name, valsize, level;
1108
1109         error = copyin(args, &linux_args, sizeof(linux_args));
1110         if (error)
1111                 return (error);
1112
1113         if (linux_args.optval) {
1114                 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1115                 if (error)
1116                         return (error);
1117                 if (valsize < 0)
1118                         return (EINVAL);
1119         } else {
1120                 valsize = 0;
1121         }
1122
1123         level = linux_to_bsd_sockopt_level(linux_args.level);
1124         switch (level) {
1125         case SOL_SOCKET:
1126                 name = linux_to_bsd_so_sockopt(linux_args.optname);
1127                 break;
1128         case IPPROTO_IP:
1129                 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1130                 break;
1131         case IPPROTO_TCP:
1132                 /* Linux TCP option values match BSD's */
1133                 name = linux_args.optname;
1134                 break;
1135         default:
1136                 name = -1;
1137                 break;
1138         }
1139         if (name == -1)
1140                 return (EINVAL);
1141
1142         sopt.sopt_dir = SOPT_GET;
1143         sopt.sopt_level = level;
1144         sopt.sopt_name = name;
1145         sopt.sopt_val = linux_args.optval;
1146         sopt.sopt_valsize = valsize;
1147         sopt.sopt_td = td;
1148
1149         error = kern_getsockopt(linux_args.s, &sopt);
1150         if (error == 0) {
1151                 valsize = sopt.sopt_valsize;
1152                 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1153         }
1154         return(error);
1155 }
1156
1157 int
1158 linux_socketcall(struct linux_socketcall_args *args)
1159 {
1160         void *arg = (void *)args->args;
1161
1162         switch (args->what) {
1163         case LINUX_SOCKET:
1164                 return (linux_socket(arg, &args->sysmsg_result));
1165         case LINUX_BIND:
1166                 return (linux_bind(arg, &args->sysmsg_result));
1167         case LINUX_CONNECT:
1168                 return (linux_connect(arg, &args->sysmsg_result));
1169         case LINUX_LISTEN:
1170                 return (linux_listen(arg, &args->sysmsg_result));
1171         case LINUX_ACCEPT:
1172                 return (linux_accept(arg, &args->sysmsg_result));
1173         case LINUX_GETSOCKNAME:
1174                 return (linux_getsockname(arg, &args->sysmsg_result));
1175         case LINUX_GETPEERNAME:
1176                 return (linux_getpeername(arg, &args->sysmsg_result));
1177         case LINUX_SOCKETPAIR:
1178                 return (linux_socketpair(arg, &args->sysmsg_result));
1179         case LINUX_SEND:
1180                 return (linux_send(arg, &args->sysmsg_result));
1181         case LINUX_RECV:
1182                 return (linux_recv(arg, &args->sysmsg_result));
1183         case LINUX_SENDTO:
1184                 return (linux_sendto(arg, &args->sysmsg_result));
1185         case LINUX_RECVFROM:
1186                 return (linux_recvfrom(arg, &args->sysmsg_result));
1187         case LINUX_SHUTDOWN:
1188                 return (linux_shutdown(arg, &args->sysmsg_result));
1189         case LINUX_SETSOCKOPT:
1190                 return (linux_setsockopt(arg, &args->sysmsg_result));
1191         case LINUX_GETSOCKOPT:
1192                 return (linux_getsockopt(arg, &args->sysmsg_result));
1193         case LINUX_SENDMSG:
1194                 return (linux_sendmsg(arg, &args->sysmsg_result));
1195         case LINUX_RECVMSG:
1196                 return (linux_recvmsg(arg, &args->sysmsg_result));
1197         }
1198
1199         uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1200         return (ENOSYS);
1201 }
1202 #endif  /*!__alpha__*/