linux emulation - Major update
[dragonfly.git] / sys / emulation / linux / linux_socket.c
bloba762e426d36e94e986f7a13cfb9043a7ce9a2519
1 /*-
2 * Copyright (c) 1995 Søren Schmidt
3 * All rights reserved.
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
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.
28 * $FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.19.2.8 2001/11/07 20:33:55 marcel Exp $
29 * $DragonFly: src/sys/emulation/linux/linux_socket.c,v 1.28 2008/07/10 00:19:27 aggelos Exp $
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 #include <sys/un.h>
46 #include <sys/mplock2.h>
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/ip.h>
52 #include <arch_linux/linux.h>
53 #include <arch_linux/linux_proto.h>
54 #include "linux_socket.h"
55 #include "linux_util.h"
58 * Copyin a sockaddr structure provided by a Linux binary. Linux uses
59 * the 4.3BSD sockaddr structure which has no sa_len field. We must
60 * pass 4.4BSD sockaddr structures when we call native functions in the
61 * BSD kernel. This function does the conversion for us.
63 * Also, our socket calls require the sockaddr structure length to agree
64 * with the address family. Linux does not, so we must force it.
66 * This function should only need to be called from linux_connect()
67 * and linux_bind().
69 static int
70 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
72 struct sockaddr *sa;
73 uint16_t family; /* XXX: must match Linux sockaddr */
74 int error;
75 int sa_len;
77 *namp = NULL;
79 if (len > SOCK_MAXADDRLEN)
80 return ENAMETOOLONG;
81 error = copyin(uaddr, &family, sizeof(family));
82 if (error)
83 return (error);
86 * Force the sa_len field to match the address family.
88 switch (family) {
89 case AF_INET:
90 sa_len = sizeof(struct sockaddr_in);
91 break;
92 case AF_INET6:
93 sa_len = sizeof(struct sockaddr_in6);
94 break;
95 default:
97 * This is the default behavior of the old
98 * linux_to_bsd_namelen() function. NOTE! The
99 * minimum length we allocate must cover sa->sa_len and
100 * sa->sa_family.
102 sa_len = offsetof(struct sockaddr, sa_data[0]);
103 if (sa_len < len)
104 sa_len = len;
105 break;
108 MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
109 error = copyin(uaddr, sa, sa_len);
110 if (error) {
111 FREE(sa, M_SONAME);
112 } else {
114 * Convert to the 4.4BSD sockaddr structure.
116 sa->sa_family = *(sa_family_t *)sa;
117 sa->sa_len = sa_len;
118 *namp = sa;
121 return (error);
125 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
126 * and copy it out to a user address.
128 static int
129 linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
131 int error;
133 if (sa_len < (int)sizeof(u_short))
134 return (EINVAL);
136 *(u_short *)sa = sa->sa_family;
137 error = copyout(sa, uaddr, sa_len);
139 return (error);
142 static int
143 linux_to_bsd_domain(int domain)
146 switch (domain) {
147 case LINUX_AF_UNSPEC:
148 return (AF_UNSPEC);
149 case LINUX_AF_UNIX:
150 return (AF_LOCAL);
151 case LINUX_AF_INET:
152 return (AF_INET);
153 case LINUX_AF_AX25:
154 return (AF_CCITT);
155 case LINUX_AF_IPX:
156 return (AF_IPX);
157 case LINUX_AF_APPLETALK:
158 return (AF_APPLETALK);
160 return (-1);
163 static int
164 linux_to_bsd_sockopt_level(int level)
167 switch (level) {
168 case LINUX_SOL_SOCKET:
169 return (SOL_SOCKET);
171 return (level);
174 static int
175 linux_to_bsd_ip_sockopt(int opt)
178 switch (opt) {
179 case LINUX_IP_TOS:
180 return (IP_TOS);
181 case LINUX_IP_TTL:
182 return (IP_TTL);
183 case LINUX_IP_OPTIONS:
184 return (IP_OPTIONS);
185 case LINUX_IP_MULTICAST_IF:
186 return (IP_MULTICAST_IF);
187 case LINUX_IP_MULTICAST_TTL:
188 return (IP_MULTICAST_TTL);
189 case LINUX_IP_MULTICAST_LOOP:
190 return (IP_MULTICAST_LOOP);
191 case LINUX_IP_ADD_MEMBERSHIP:
192 return (IP_ADD_MEMBERSHIP);
193 case LINUX_IP_DROP_MEMBERSHIP:
194 return (IP_DROP_MEMBERSHIP);
195 case LINUX_IP_HDRINCL:
196 return (IP_HDRINCL);
198 return (-1);
201 static int
202 linux_to_bsd_so_sockopt(int opt)
205 switch (opt) {
206 case LINUX_SO_DEBUG:
207 return (SO_DEBUG);
208 case LINUX_SO_REUSEADDR:
209 return (SO_REUSEADDR);
210 case LINUX_SO_TYPE:
211 return (SO_TYPE);
212 case LINUX_SO_ERROR:
213 return (SO_ERROR);
214 case LINUX_SO_DONTROUTE:
215 return (SO_DONTROUTE);
216 case LINUX_SO_BROADCAST:
217 return (SO_BROADCAST);
218 case LINUX_SO_SNDBUF:
219 return (SO_SNDBUF);
220 case LINUX_SO_RCVBUF:
221 return (SO_RCVBUF);
222 case LINUX_SO_KEEPALIVE:
223 return (SO_KEEPALIVE);
224 case LINUX_SO_OOBINLINE:
225 return (SO_OOBINLINE);
226 case LINUX_SO_LINGER:
227 return (SO_LINGER);
228 case LINUX_SO_PEERCRED:
229 return (LOCAL_PEERCRED);
231 return (-1);
234 static int
235 linux_to_bsd_msg_flags(int flags)
237 int ret_flags = 0;
239 if (flags & LINUX_MSG_OOB)
240 ret_flags |= MSG_OOB;
241 if (flags & LINUX_MSG_PEEK)
242 ret_flags |= MSG_PEEK;
243 if (flags & LINUX_MSG_DONTROUTE)
244 ret_flags |= MSG_DONTROUTE;
245 if (flags & LINUX_MSG_CTRUNC)
246 ret_flags |= MSG_CTRUNC;
247 if (flags & LINUX_MSG_TRUNC)
248 ret_flags |= MSG_TRUNC;
249 if (flags & LINUX_MSG_DONTWAIT)
250 ret_flags |= MSG_DONTWAIT;
251 if (flags & LINUX_MSG_EOR)
252 ret_flags |= MSG_EOR;
253 if (flags & LINUX_MSG_WAITALL)
254 ret_flags |= MSG_WAITALL;
255 #if 0 /* not handled */
256 if (flags & LINUX_MSG_PROXY)
258 if (flags & LINUX_MSG_FIN)
260 if (flags & LINUX_MSG_SYN)
262 if (flags & LINUX_MSG_CONFIRM)
264 if (flags & LINUX_MSG_RST)
266 if (flags & LINUX_MSG_ERRQUEUE)
268 if (flags & LINUX_MSG_NOSIGNAL)
270 #endif
271 return ret_flags;
274 struct linux_socket_args {
275 int domain;
276 int type;
277 int protocol;
280 static int
281 linux_socket(struct linux_socket_args *args, int *res)
283 struct linux_socket_args linux_args;
284 struct sockopt sopt;
285 int error, domain, optval;
287 error = copyin(args, &linux_args, sizeof(linux_args));
288 if (error)
289 return (error);
291 domain = linux_to_bsd_domain(linux_args.domain);
292 if (domain == -1)
293 return (EINVAL);
295 error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
297 /* Copy back the return value from socket() */
298 if (error == 0 && linux_args.type == SOCK_RAW &&
299 (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
300 linux_args.domain == AF_INET) {
301 /* It's a raw IP socket: set the IP_HDRINCL option. */
302 optval = 1;
303 sopt.sopt_dir = SOPT_SET;
304 sopt.sopt_level = IPPROTO_IP;
305 sopt.sopt_name = IP_HDRINCL;
306 sopt.sopt_val = &optval;
307 sopt.sopt_valsize = sizeof(optval);
308 sopt.sopt_td = NULL;
310 /* We ignore any error returned by setsockopt() */
311 kern_setsockopt(*res, &sopt);
314 return (error);
317 struct linux_bind_args {
318 int s;
319 struct sockaddr *name;
320 int namelen;
323 static int
324 linux_bind(struct linux_bind_args *args, int *res)
326 struct linux_bind_args linux_args;
327 struct sockaddr *sa;
328 int error;
330 error = copyin(args, &linux_args, sizeof(linux_args));
331 if (error)
332 return (error);
333 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
334 if (error)
335 return (error);
337 error = kern_bind(linux_args.s, sa);
338 FREE(sa, M_SONAME);
340 return (error);
343 struct linux_connect_args {
344 int s;
345 struct sockaddr * name;
346 int namelen;
349 static int
350 linux_connect(struct linux_connect_args *args, int *res)
352 struct thread *td = curthread; /* XXX */
353 struct proc *p = td->td_proc;
354 struct linux_connect_args linux_args;
355 struct sockaddr *sa;
356 struct socket *so;
357 struct file *fp;
358 int error;
360 KKASSERT(p);
362 error = copyin(args, &linux_args, sizeof(linux_args));
363 if (error)
364 return (error);
365 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
366 if (error)
367 return (error);
369 error = kern_connect(linux_args.s, 0, sa);
370 FREE(sa, M_SONAME);
372 if (error != EISCONN)
373 return (error);
376 * Linux doesn't return EISCONN the first time it occurs,
377 * when on a non-blocking socket. Instead it returns the
378 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
380 error = holdsock(p->p_fd, linux_args.s, &fp);
381 if (error)
382 return (error);
383 error = EISCONN;
384 if (fp->f_flag & FNONBLOCK) {
385 so = (struct socket *)fp->f_data;
386 if (so->so_emuldata == 0)
387 error = so->so_error;
388 so->so_emuldata = (void *)1;
390 fdrop(fp);
391 return (error);
394 struct linux_listen_args {
395 int s;
396 int backlog;
399 static int
400 linux_listen(struct linux_listen_args *args, int *res)
402 struct linux_listen_args linux_args;
403 int error;
405 error = copyin(args, &linux_args, sizeof(linux_args));
406 if (error)
407 return (error);
409 error = kern_listen(linux_args.s, linux_args.backlog);
411 return(error);
414 struct linux_accept_args {
415 int s;
416 struct sockaddr *addr;
417 int *namelen;
420 static int
421 linux_accept(struct linux_accept_args *args, int *res)
423 struct thread *td = curthread;
424 struct linux_accept_args linux_args;
425 struct sockaddr *sa = NULL;
426 union fcntl_dat dat = { 0 };
427 int error, sa_len;
429 error = copyin(args, &linux_args, sizeof(linux_args));
430 if (error)
431 return (error);
433 if (linux_args.addr) {
434 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
435 if (error)
436 return (error);
438 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res);
440 if (error) {
442 * Return a namelen of zero for older code which
443 * might ignore the return value from accept().
445 sa_len = 0;
446 copyout(&sa_len, linux_args.namelen,
447 sizeof(*linux_args.namelen));
448 } else {
449 error = linux_copyout_sockaddr(sa, linux_args.addr,
450 sa_len);
451 if (error == 0) {
452 error = copyout(&sa_len, linux_args.namelen,
453 sizeof(*linux_args.namelen));
456 if (sa)
457 FREE(sa, M_SONAME);
458 } else {
459 error = kern_accept(linux_args.s, 0, NULL, 0, res);
462 if (error)
463 return (error);
466 * linux appears not to copy flags from the parent socket to the
467 * accepted one, so we must clear the flags in the new descriptor.
468 * Ignore any errors, because we already have an open fd.
470 kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
471 return (0);
474 struct linux_getsockname_args {
475 int s;
476 struct sockaddr *addr;
477 int *namelen;
480 static int
481 linux_getsockname(struct linux_getsockname_args *args, int *res)
483 struct linux_getsockname_args linux_args;
484 struct sockaddr *sa = NULL;
485 int error, sa_len;
488 error = copyin(args, &linux_args, sizeof(linux_args));
489 if (error)
490 return (error);
491 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
492 if (error)
493 return (error);
495 error = kern_getsockname(linux_args.s, &sa, &sa_len);
497 if (error == 0)
498 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
499 if (error == 0)
500 error = copyout(&sa_len, linux_args.namelen,
501 sizeof(*linux_args.namelen));
502 if (sa)
503 FREE(sa, M_SONAME);
504 return(error);
507 struct linux_getpeername_args {
508 int s;
509 struct sockaddr *addr;
510 int *namelen;
513 static int
514 linux_getpeername(struct linux_getpeername_args *args, int *res)
516 struct linux_getpeername_args linux_args;
517 struct sockaddr *sa = NULL;
518 int error, sa_len;
520 error = copyin(args, &linux_args, sizeof(linux_args));
521 if (error)
522 return (error);
523 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
524 if (error)
525 return (error);
527 error = kern_getpeername(linux_args.s, &sa, &sa_len);
529 if (error == 0)
530 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
531 if (error == 0)
532 error = copyout(&sa_len, linux_args.namelen,
533 sizeof(*linux_args.namelen));
534 if (sa)
535 FREE(sa, M_SONAME);
536 return(error);
539 struct linux_socketpair_args {
540 int domain;
541 int type;
542 int protocol;
543 int *rsv;
546 static int
547 linux_socketpair(struct linux_socketpair_args *args, int *res)
549 struct linux_socketpair_args linux_args;
550 int error, domain, sockv[2];
552 error = copyin(args, &linux_args, sizeof(linux_args));
553 if (error)
554 return (error);
556 domain = linux_to_bsd_domain(linux_args.domain);
557 if (domain == -1)
558 return (EINVAL);
559 error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
560 sockv);
562 if (error == 0)
563 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
564 return(error);
567 struct linux_send_args {
568 int s;
569 void *msg;
570 int len;
571 int flags;
574 static int
575 linux_send(struct linux_send_args *args, size_t *res)
577 struct linux_send_args linux_args;
578 struct thread *td = curthread;
579 struct uio auio;
580 struct iovec aiov;
581 int error;
583 error = copyin(args, &linux_args, sizeof(linux_args));
584 if (error)
585 return (error);
587 aiov.iov_base = linux_args.msg;
588 aiov.iov_len = linux_args.len;
589 auio.uio_iov = &aiov;
590 auio.uio_iovcnt = 1;
591 auio.uio_offset = 0;
592 auio.uio_resid = linux_args.len;
593 auio.uio_segflg = UIO_USERSPACE;
594 auio.uio_rw = UIO_WRITE;
595 auio.uio_td = td;
597 error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
598 linux_args.flags, res);
600 return(error);
603 struct linux_recv_args {
604 int s;
605 void *msg;
606 int len;
607 int flags;
610 static int
611 linux_recv(struct linux_recv_args *args, size_t *res)
613 struct linux_recv_args linux_args;
614 struct thread *td = curthread;
615 struct uio auio;
616 struct iovec aiov;
617 int error;
619 error = copyin(args, &linux_args, sizeof(linux_args));
620 if (error)
621 return (error);
623 aiov.iov_base = linux_args.msg;
624 aiov.iov_len = linux_args.len;
625 auio.uio_iov = &aiov;
626 auio.uio_iovcnt = 1;
627 auio.uio_offset = 0;
628 auio.uio_resid = linux_args.len;
629 auio.uio_segflg = UIO_USERSPACE;
630 auio.uio_rw = UIO_READ;
631 auio.uio_td = td;
633 error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
634 &linux_args.flags, res);
636 return(error);
639 struct linux_sendto_args {
640 int s;
641 void *msg;
642 int len;
643 int flags;
644 struct sockaddr *to;
645 int tolen;
648 static int
649 linux_sendto(struct linux_sendto_args *args, size_t *res)
651 struct linux_sendto_args linux_args;
652 struct thread *td = curthread;
653 struct uio auio;
654 struct iovec aiov;
655 struct sockopt sopt;
656 struct sockaddr *sa = NULL;
657 caddr_t msg = NULL;
658 int error, optval;
660 error = copyin(args, &linux_args, sizeof(linux_args));
661 if (error)
662 return (error);
664 if (linux_args.to) {
665 error = linux_getsockaddr(&sa, linux_args.to,
666 linux_args.tolen);
667 if (error)
668 return (error);
672 * Check to see if the IP_HDRINCL option is set.
674 sopt.sopt_dir = SOPT_GET;
675 sopt.sopt_level = IPPROTO_IP;
676 sopt.sopt_name = IP_HDRINCL;
677 sopt.sopt_val = &optval;
678 sopt.sopt_valsize = sizeof(optval);
679 sopt.sopt_td = NULL;
681 if (kern_getsockopt(linux_args.s, &sopt) != 0)
682 optval = 0;
684 if (optval == 0) {
686 * IP_HDRINCL is not set. Package the message as usual.
688 aiov.iov_base = linux_args.msg;
689 aiov.iov_len = linux_args.len;
690 auio.uio_iov = &aiov;
691 auio.uio_iovcnt = 1;
692 auio.uio_offset = 0;
693 auio.uio_resid = linux_args.len;
694 auio.uio_segflg = UIO_USERSPACE;
695 auio.uio_rw = UIO_WRITE;
696 auio.uio_td = td;
697 } else {
699 * IP_HDRINCL is set. We must convert the beginning of
700 * the packet header so we can feed it to the BSD kernel.
704 * Check that the packet header is long enough to contain
705 * the fields of interest. This relies on the fact that
706 * the fragment offset field comes after the length field.
708 if (linux_args.len < offsetof(struct ip, ip_off))
709 return (EINVAL);
711 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
712 error = copyin(linux_args.msg, msg, linux_args.len);
713 if (error)
714 goto cleanup;
716 /* Fix the ip_len and ip_off fields. */
717 ((struct ip *)msg)->ip_len = linux_args.len;
718 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
720 aiov.iov_base = msg;
721 aiov.iov_len = linux_args.len;
722 auio.uio_iov = &aiov;
723 auio.uio_iovcnt = 1;
724 auio.uio_offset = 0;
725 auio.uio_resid = linux_args.len;
726 auio.uio_segflg = UIO_SYSSPACE;
727 auio.uio_rw = UIO_WRITE;
728 auio.uio_td = td;
731 error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
732 linux_args.flags, res);
734 cleanup:
735 if (sa)
736 FREE(sa, M_SONAME);
737 if (msg)
738 FREE(msg, M_LINUX);
739 return(error);
742 struct linux_recvfrom_args {
743 int s;
744 void *buf;
745 int len;
746 int flags;
747 struct sockaddr *from;
748 int *fromlen;
751 static int
752 linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
754 struct linux_recvfrom_args linux_args;
755 struct thread *td = curthread;
756 struct uio auio;
757 struct iovec aiov;
758 struct sockaddr *sa = NULL;
759 int error, fromlen, flags;
761 error = copyin(args, &linux_args, sizeof(linux_args));
762 if (error)
763 return (error);
765 if (linux_args.from && linux_args.fromlen) {
766 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
767 if (error)
768 return (error);
769 if (fromlen < 0)
770 return (EINVAL);
771 } else {
772 fromlen = 0;
774 aiov.iov_base = linux_args.buf;
775 aiov.iov_len = linux_args.len;
776 auio.uio_iov = &aiov;
777 auio.uio_iovcnt = 1;
778 auio.uio_offset = 0;
779 auio.uio_resid = linux_args.len;
780 auio.uio_segflg = UIO_USERSPACE;
781 auio.uio_rw = UIO_READ;
782 auio.uio_td = td;
784 flags = linux_to_bsd_msg_flags(linux_args.flags);
786 error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
787 NULL, &flags, res);
789 if (error == 0 && linux_args.from) {
790 if (sa != NULL) {
791 fromlen = MIN(fromlen, sa->sa_len);
792 error = linux_copyout_sockaddr(sa, linux_args.from,
793 fromlen);
794 } else
795 fromlen = 0;
796 if (error == 0)
797 copyout(&fromlen, linux_args.fromlen,
798 sizeof(fromlen));
800 if (sa)
801 FREE(sa, M_SONAME);
803 return(error);
806 struct linux_sendmsg_args {
807 int s;
808 struct msghdr *msg;
809 int flags;
812 static int
813 linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
815 struct linux_sendmsg_args linux_args;
816 struct thread *td = curthread;
817 struct msghdr msg;
818 struct uio auio;
819 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
820 struct sockaddr *sa = NULL;
821 struct mbuf *control = NULL;
822 int error;
824 error = copyin(args, &linux_args, sizeof(linux_args));
825 if (error)
826 return (error);
828 error = copyin(linux_args.msg, &msg, sizeof(msg));
829 if (error)
830 return (error);
833 * XXX: I'm not sure atm how this relates to dragonfly, but
834 * just in case, I put it in.
835 * Ping on linux does pass 0 in controllen which is forbidden
836 * by FreeBSD but seems to be ok on Linux. This needs some
837 * checking but now it lets ping work.
839 if (msg.msg_control && msg.msg_controllen == 0)
840 msg.msg_control = NULL;
843 * Conditionally copyin msg.msg_name.
845 if (msg.msg_name) {
846 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
847 if (error)
848 return (error);
852 * Populate auio.
854 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
855 &auio.uio_resid);
856 if (error)
857 goto cleanup2;
858 auio.uio_iov = iov;
859 auio.uio_iovcnt = msg.msg_iovlen;
860 auio.uio_offset = 0;
861 auio.uio_segflg = UIO_USERSPACE;
862 auio.uio_rw = UIO_WRITE;
863 auio.uio_td = td;
866 * Conditionally copyin msg.msg_control.
868 if (msg.msg_control) {
869 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
870 msg.msg_controllen > MLEN) {
871 error = EINVAL;
872 goto cleanup;
874 control = m_get(MB_WAIT, MT_CONTROL);
875 if (control == NULL) {
876 error = ENOBUFS;
877 goto cleanup;
879 control->m_len = msg.msg_controllen;
880 error = copyin(msg.msg_control, mtod(control, caddr_t),
881 msg.msg_controllen);
882 if (error) {
883 m_free(control);
884 goto cleanup;
887 * Linux and BSD both support SCM_RIGHTS. If a linux binary
888 * wants anything else with an option level of SOL_SOCKET,
889 * we don't support it.
891 if (mtod(control, struct cmsghdr *)->cmsg_level ==
892 SOL_SOCKET &&
893 mtod(control, struct cmsghdr *)->cmsg_type !=
894 SCM_RIGHTS) {
895 m_free(control);
896 error = EINVAL;
897 goto cleanup;
901 error = kern_sendmsg(linux_args.s, sa, &auio, control,
902 linux_args.flags, res);
904 cleanup:
905 iovec_free(&iov, aiov);
906 cleanup2:
907 if (sa)
908 FREE(sa, M_SONAME);
909 return (error);
912 struct linux_recvmsg_args {
913 int s;
914 struct msghdr *msg;
915 int flags;
918 static int
919 linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
921 struct linux_recvmsg_args linux_args;
922 struct thread *td = curthread;
923 struct msghdr msg;
924 struct uio auio;
925 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
926 struct mbuf *m, *control = NULL;
927 struct sockaddr *sa = NULL;
928 caddr_t ctlbuf;
929 socklen_t *ufromlenp, *ucontrollenp;
930 int error, fromlen, controllen, len, flags, *uflagsp;
932 error = copyin(args, &linux_args, sizeof(linux_args));
933 if (error)
934 return (error);
936 error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
937 if (error)
938 return (error);
940 if (msg.msg_name && msg.msg_namelen < 0)
941 return (EINVAL);
942 if (msg.msg_control && msg.msg_controllen < 0)
943 return (EINVAL);
945 ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
946 offsetof(struct msghdr, msg_namelen));
947 ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
948 offsetof(struct msghdr, msg_controllen));
949 uflagsp = (int *)((caddr_t)linux_args.msg +
950 offsetof(struct msghdr, msg_flags));
953 * Populate auio.
955 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
956 &auio.uio_resid);
957 if (error)
958 return (error);
959 auio.uio_iov = iov;
960 auio.uio_iovcnt = msg.msg_iovlen;
961 auio.uio_offset = 0;
962 auio.uio_segflg = UIO_USERSPACE;
963 auio.uio_rw = UIO_READ;
964 auio.uio_td = td;
966 flags = linux_to_bsd_msg_flags(linux_args.flags);
968 error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
969 msg.msg_control ? &control : NULL, &flags, res);
972 * Copyout msg.msg_name and msg.msg_namelen.
974 if (error == 0 && msg.msg_name) {
975 if (sa != NULL) {
976 fromlen = MIN(msg.msg_namelen, sa->sa_len);
977 error = linux_copyout_sockaddr(sa, msg.msg_name,
978 fromlen);
979 } else
980 fromlen = 0;
981 if (error == 0)
982 error = copyout(&fromlen, ufromlenp,
983 sizeof(*ufromlenp));
987 * Copyout msg.msg_control and msg.msg_controllen.
989 if (error == 0 && msg.msg_control) {
991 * Linux and BSD both support SCM_RIGHTS. If a linux binary
992 * wants anything else with an option level of SOL_SOCKET,
993 * we don't support it.
995 if (mtod((struct mbuf *)msg.msg_control,
996 struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
997 mtod((struct mbuf *)msg.msg_control,
998 struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
999 error = EINVAL;
1000 goto cleanup;
1003 len = msg.msg_controllen;
1004 m = control;
1005 ctlbuf = (caddr_t)msg.msg_control;
1007 while (m && len > 0) {
1008 unsigned int tocopy;
1010 if (len >= m->m_len) {
1011 tocopy = m->m_len;
1012 } else {
1013 msg.msg_flags |= MSG_CTRUNC;
1014 tocopy = len;
1017 error = copyout(mtod(m, caddr_t), ctlbuf,
1018 tocopy);
1019 if (error)
1020 goto cleanup;
1022 ctlbuf += tocopy;
1023 len -= tocopy;
1024 m = m->m_next;
1026 controllen = ctlbuf - (caddr_t)msg.msg_control;
1027 error = copyout(&controllen, ucontrollenp,
1028 sizeof(*ucontrollenp));
1031 if (error == 0)
1032 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1034 cleanup:
1035 if (sa)
1036 FREE(sa, M_SONAME);
1037 iovec_free(&iov, aiov);
1038 if (control)
1039 m_freem(control);
1040 return (error);
1043 struct linux_shutdown_args {
1044 int s;
1045 int how;
1048 static int
1049 linux_shutdown(struct linux_shutdown_args *args, int *res)
1051 struct linux_shutdown_args linux_args;
1052 int error;
1054 error = copyin(args, &linux_args, sizeof(linux_args));
1055 if (error)
1056 return (error);
1058 error = kern_shutdown(linux_args.s, linux_args.how);
1060 return (error);
1063 struct linux_setsockopt_args {
1064 int s;
1065 int level;
1066 int optname;
1067 void *optval;
1068 int optlen;
1071 static int
1072 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1074 struct linux_setsockopt_args linux_args;
1075 struct thread *td = curthread;
1076 struct sockopt sopt;
1077 l_timeval linux_tv;
1078 struct timeval tv;
1079 int error, name, level;
1081 error = copyin(args, &linux_args, sizeof(linux_args));
1082 if (error)
1083 return (error);
1085 level = linux_to_bsd_sockopt_level(linux_args.level);
1086 switch (level) {
1087 case SOL_SOCKET:
1088 name = linux_to_bsd_so_sockopt(linux_args.optname);
1089 switch (name) {
1090 case SO_RCVTIMEO:
1091 /* FALLTHROUGH */
1092 case SO_SNDTIMEO:
1093 error = copyin(linux_args.optval, &linux_tv,
1094 sizeof(linux_tv));
1095 if (error)
1096 return (error);
1097 tv.tv_sec = linux_tv.tv_sec;
1098 tv.tv_usec = linux_tv.tv_usec;
1099 sopt.sopt_dir = SOPT_SET;
1100 sopt.sopt_level = level;
1101 sopt.sopt_name = name;
1102 sopt.sopt_valsize = sizeof(tv);
1103 sopt.sopt_val = &tv;
1104 sopt.sopt_td = td;
1105 return (kern_setsockopt(linux_args.s, &sopt));
1106 /* NOTREACHED */
1107 break;
1108 default:
1109 break;
1111 break;
1112 case IPPROTO_IP:
1113 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1114 break;
1115 case IPPROTO_TCP:
1116 /* Linux TCP option values match BSD's */
1117 name = linux_args.optname;
1118 break;
1119 default:
1120 name = -1;
1121 break;
1123 if (name == -1)
1124 return (ENOPROTOOPT);
1126 if (linux_args.optlen < 0 || linux_args.optlen > SOMAXOPT_SIZE)
1127 return (EINVAL);
1128 if (linux_args.optval != NULL && linux_args.optlen == 0)
1129 return (EINVAL);
1130 if (linux_args.optval == NULL && linux_args.optlen != 0)
1131 return (EFAULT);
1133 sopt.sopt_dir = SOPT_SET;
1134 sopt.sopt_level = level;
1135 sopt.sopt_name = name;
1136 sopt.sopt_valsize = linux_args.optlen;
1137 sopt.sopt_td = td;
1139 if (linux_args.optval) {
1140 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1141 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1142 if (error)
1143 goto out;
1144 } else {
1145 sopt.sopt_val = NULL;
1147 error = kern_setsockopt(linux_args.s, &sopt);
1148 if (error)
1149 goto out;
1150 if (linux_args.optval)
1151 error = copyout(sopt.sopt_val, linux_args.optval,
1152 sopt.sopt_valsize);
1153 out:
1154 if (linux_args.optval)
1155 kfree(sopt.sopt_val, M_TEMP);
1156 return(error);
1159 struct linux_getsockopt_args {
1160 int s;
1161 int level;
1162 int optname;
1163 void *optval;
1164 int *optlen;
1167 static int
1168 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1170 struct linux_getsockopt_args linux_args;
1171 struct thread *td = curthread;
1172 struct sockopt sopt;
1173 l_timeval linux_tv;
1174 struct timeval tv;
1175 struct xucred xu;
1176 struct l_ucred lxu;
1177 int error, name, valsize, level;
1179 error = copyin(args, &linux_args, sizeof(linux_args));
1180 if (error)
1181 return (error);
1183 if (linux_args.optlen) {
1184 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1185 if (error)
1186 return (error);
1187 } else {
1188 valsize = 0;
1191 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1192 return (EINVAL);
1193 if (linux_args.optval != NULL && valsize == 0)
1194 return (EFAULT);
1195 if (linux_args.optval == NULL && valsize != 0)
1196 return (EFAULT);
1198 level = linux_to_bsd_sockopt_level(linux_args.level);
1199 switch (level) {
1200 case SOL_SOCKET:
1201 name = linux_to_bsd_so_sockopt(linux_args.optname);
1202 switch (name) {
1203 case SO_RCVTIMEO:
1204 /* FALLTHROUGH */
1205 case SO_SNDTIMEO:
1206 sopt.sopt_dir = SOPT_GET;
1207 sopt.sopt_level = level;
1208 sopt.sopt_name = name;
1209 sopt.sopt_valsize = sizeof(tv);
1210 sopt.sopt_td = td;
1211 sopt.sopt_val = &tv;
1212 error = kern_getsockopt(linux_args.s, &sopt);
1213 if (error)
1214 return (error);
1215 linux_tv.tv_sec = tv.tv_sec;
1216 linux_tv.tv_usec = tv.tv_usec;
1217 return (copyout(&linux_tv, linux_args.optval,
1218 sizeof(linux_tv)));
1219 /* NOTREACHED */
1220 break;
1221 case LOCAL_PEERCRED:
1222 if (valsize != sizeof(lxu))
1223 return (EINVAL);
1224 sopt.sopt_dir = SOPT_GET;
1225 sopt.sopt_level = level;
1226 sopt.sopt_name = name;
1227 sopt.sopt_valsize = sizeof(xu);
1228 sopt.sopt_td = td;
1229 sopt.sopt_val = &xu;
1230 error = kern_getsockopt(linux_args.s, &sopt);
1231 if (error)
1232 return (error);
1234 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1236 lxu.pid = 0;
1237 lxu.uid = xu.cr_uid;
1238 lxu.gid = xu.cr_gid;
1239 return (copyout(&lxu, linux_args.optval, sizeof(lxu)));
1240 /* NOTREACHED */
1241 break;
1242 default:
1243 break;
1245 break;
1246 case IPPROTO_IP:
1247 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1248 break;
1249 case IPPROTO_TCP:
1250 /* Linux TCP option values match BSD's */
1251 name = linux_args.optname;
1252 break;
1253 default:
1254 name = -1;
1255 break;
1257 if (name == -1)
1258 return (EOPNOTSUPP);
1262 sopt.sopt_dir = SOPT_GET;
1263 sopt.sopt_level = level;
1264 sopt.sopt_name = name;
1265 sopt.sopt_valsize = valsize;
1266 sopt.sopt_td = td;
1268 if (linux_args.optval) {
1269 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1270 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1271 if (error)
1272 goto out;
1273 } else {
1274 sopt.sopt_val = NULL;
1276 error = kern_getsockopt(linux_args.s, &sopt);
1277 if (error) {
1278 if (error == EINVAL)
1279 error = ENOPROTOOPT;
1280 goto out;
1282 valsize = sopt.sopt_valsize;
1283 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1284 if (error)
1285 goto out;
1286 if (linux_args.optval)
1287 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1288 out:
1289 if (linux_args.optval)
1290 kfree(sopt.sopt_val, M_TEMP);
1291 return(error);
1295 * MPALMOSTSAFE
1298 sys_linux_socketcall(struct linux_socketcall_args *args)
1300 void *arg = (void *)args->args;
1301 int error;
1303 get_mplock();
1305 switch (args->what) {
1306 case LINUX_SOCKET:
1307 error = linux_socket(arg, &args->sysmsg_result);
1308 break;
1309 case LINUX_BIND:
1310 error = linux_bind(arg, &args->sysmsg_result);
1311 break;
1312 case LINUX_CONNECT:
1313 error = linux_connect(arg, &args->sysmsg_result);
1314 break;
1315 case LINUX_LISTEN:
1316 error = linux_listen(arg, &args->sysmsg_result);
1317 break;
1318 case LINUX_ACCEPT:
1319 error = linux_accept(arg, &args->sysmsg_result);
1320 break;
1321 case LINUX_GETSOCKNAME:
1322 error = linux_getsockname(arg, &args->sysmsg_result);
1323 break;
1324 case LINUX_GETPEERNAME:
1325 error = linux_getpeername(arg, &args->sysmsg_result);
1326 break;
1327 case LINUX_SOCKETPAIR:
1328 error = linux_socketpair(arg, &args->sysmsg_result);
1329 break;
1330 case LINUX_SEND:
1331 error = linux_send(arg, &args->sysmsg_szresult);
1332 break;
1333 case LINUX_RECV:
1334 error = linux_recv(arg, &args->sysmsg_szresult);
1335 break;
1336 case LINUX_SENDTO:
1337 error = linux_sendto(arg, &args->sysmsg_szresult);
1338 break;
1339 case LINUX_RECVFROM:
1340 error = linux_recvfrom(arg, &args->sysmsg_szresult);
1341 break;
1342 case LINUX_SHUTDOWN:
1343 error = linux_shutdown(arg, &args->sysmsg_result);
1344 break;
1345 case LINUX_SETSOCKOPT:
1346 error = linux_setsockopt(arg, &args->sysmsg_result);
1347 break;
1348 case LINUX_GETSOCKOPT:
1349 error = linux_getsockopt(arg, &args->sysmsg_result);
1350 break;
1351 case LINUX_SENDMSG:
1352 error = linux_sendmsg(arg, &args->sysmsg_szresult);
1353 break;
1354 case LINUX_RECVMSG:
1355 error = linux_recvmsg(arg, &args->sysmsg_szresult);
1356 break;
1357 default:
1358 uprintf("LINUX: 'socket' typ=%d not implemented\n",
1359 args->what);
1360 error = ENOSYS;
1361 break;
1363 rel_mplock();
1365 return (error);