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