AMD64 - Move fdisk and nextboot up one level and remove src/sbin/i386.
[dragonfly.git] / sys / emulation / linux / linux_socket.c
blobd7749eb6326029bea57739346909d2de836b3562
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>
45 #include <netinet/in.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/ip.h>
49 #include <arch_linux/linux.h>
50 #include <arch_linux/linux_proto.h>
51 #include "linux_socket.h"
52 #include "linux_util.h"
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.
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.
63 * This function should only need to be called from linux_connect()
64 * and linux_bind().
66 static int
67 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
69 struct sockaddr *sa;
70 uint16_t family; /* XXX: must match Linux sockaddr */
71 int error;
72 int sa_len;
74 *namp = NULL;
76 if (len > SOCK_MAXADDRLEN)
77 return ENAMETOOLONG;
78 error = copyin(uaddr, &family, sizeof(family));
79 if (error)
80 return (error);
83 * Force the sa_len field to match the address family.
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:
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.
99 sa_len = offsetof(struct sockaddr, sa_data[0]);
100 if (sa_len < len)
101 sa_len = len;
102 break;
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 {
111 * Convert to the 4.4BSD sockaddr structure.
113 sa->sa_family = *(sa_family_t *)sa;
114 sa->sa_len = sa_len;
115 *namp = sa;
118 return (error);
122 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
123 * and copy it out to a user address.
125 static int
126 linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
128 int error;
130 if (sa_len < (int)sizeof(u_short))
131 return (EINVAL);
133 *(u_short *)sa = sa->sa_family;
134 error = copyout(sa, uaddr, sa_len);
136 return (error);
139 static int
140 linux_to_bsd_domain(int domain)
143 switch (domain) {
144 case LINUX_AF_UNSPEC:
145 return (AF_UNSPEC);
146 case LINUX_AF_UNIX:
147 return (AF_LOCAL);
148 case LINUX_AF_INET:
149 return (AF_INET);
150 case LINUX_AF_AX25:
151 return (AF_CCITT);
152 case LINUX_AF_IPX:
153 return (AF_IPX);
154 case LINUX_AF_APPLETALK:
155 return (AF_APPLETALK);
157 return (-1);
160 static int
161 linux_to_bsd_sockopt_level(int level)
164 switch (level) {
165 case LINUX_SOL_SOCKET:
166 return (SOL_SOCKET);
168 return (level);
171 static int
172 linux_to_bsd_ip_sockopt(int opt)
175 switch (opt) {
176 case LINUX_IP_TOS:
177 return (IP_TOS);
178 case LINUX_IP_TTL:
179 return (IP_TTL);
180 case LINUX_IP_OPTIONS:
181 return (IP_OPTIONS);
182 case LINUX_IP_MULTICAST_IF:
183 return (IP_MULTICAST_IF);
184 case LINUX_IP_MULTICAST_TTL:
185 return (IP_MULTICAST_TTL);
186 case LINUX_IP_MULTICAST_LOOP:
187 return (IP_MULTICAST_LOOP);
188 case LINUX_IP_ADD_MEMBERSHIP:
189 return (IP_ADD_MEMBERSHIP);
190 case LINUX_IP_DROP_MEMBERSHIP:
191 return (IP_DROP_MEMBERSHIP);
192 case LINUX_IP_HDRINCL:
193 return (IP_HDRINCL);
195 return (-1);
198 static int
199 linux_to_bsd_so_sockopt(int opt)
202 switch (opt) {
203 case LINUX_SO_DEBUG:
204 return (SO_DEBUG);
205 case LINUX_SO_REUSEADDR:
206 return (SO_REUSEADDR);
207 case LINUX_SO_TYPE:
208 return (SO_TYPE);
209 case LINUX_SO_ERROR:
210 return (SO_ERROR);
211 case LINUX_SO_DONTROUTE:
212 return (SO_DONTROUTE);
213 case LINUX_SO_BROADCAST:
214 return (SO_BROADCAST);
215 case LINUX_SO_SNDBUF:
216 return (SO_SNDBUF);
217 case LINUX_SO_RCVBUF:
218 return (SO_RCVBUF);
219 case LINUX_SO_KEEPALIVE:
220 return (SO_KEEPALIVE);
221 case LINUX_SO_OOBINLINE:
222 return (SO_OOBINLINE);
223 case LINUX_SO_LINGER:
224 return (SO_LINGER);
226 return (-1);
229 static int
230 linux_to_bsd_msg_flags(int flags)
232 int ret_flags = 0;
234 if (flags & LINUX_MSG_OOB)
235 ret_flags |= MSG_OOB;
236 if (flags & LINUX_MSG_PEEK)
237 ret_flags |= MSG_PEEK;
238 if (flags & LINUX_MSG_DONTROUTE)
239 ret_flags |= MSG_DONTROUTE;
240 if (flags & LINUX_MSG_CTRUNC)
241 ret_flags |= MSG_CTRUNC;
242 if (flags & LINUX_MSG_TRUNC)
243 ret_flags |= MSG_TRUNC;
244 if (flags & LINUX_MSG_DONTWAIT)
245 ret_flags |= MSG_DONTWAIT;
246 if (flags & LINUX_MSG_EOR)
247 ret_flags |= MSG_EOR;
248 if (flags & LINUX_MSG_WAITALL)
249 ret_flags |= MSG_WAITALL;
250 #if 0 /* not handled */
251 if (flags & LINUX_MSG_PROXY)
253 if (flags & LINUX_MSG_FIN)
255 if (flags & LINUX_MSG_SYN)
257 if (flags & LINUX_MSG_CONFIRM)
259 if (flags & LINUX_MSG_RST)
261 if (flags & LINUX_MSG_ERRQUEUE)
263 if (flags & LINUX_MSG_NOSIGNAL)
265 #endif
266 return ret_flags;
269 struct linux_socket_args {
270 int domain;
271 int type;
272 int protocol;
275 static int
276 linux_socket(struct linux_socket_args *args, int *res)
278 struct linux_socket_args linux_args;
279 struct sockopt sopt;
280 int error, domain, optval;
282 error = copyin(args, &linux_args, sizeof(linux_args));
283 if (error)
284 return (error);
286 domain = linux_to_bsd_domain(linux_args.domain);
287 if (domain == -1)
288 return (EINVAL);
290 error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
292 /* Copy back the return value from socket() */
293 if (error == 0 && linux_args.type == SOCK_RAW &&
294 (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
295 linux_args.domain == AF_INET) {
296 /* It's a raw IP socket: set the IP_HDRINCL option. */
297 optval = 1;
298 sopt.sopt_dir = SOPT_SET;
299 sopt.sopt_level = IPPROTO_IP;
300 sopt.sopt_name = IP_HDRINCL;
301 sopt.sopt_val = &optval;
302 sopt.sopt_valsize = sizeof(optval);
303 sopt.sopt_td = NULL;
305 /* We ignore any error returned by setsockopt() */
306 kern_setsockopt(*res, &sopt);
309 return (error);
312 struct linux_bind_args {
313 int s;
314 struct sockaddr *name;
315 int namelen;
318 static int
319 linux_bind(struct linux_bind_args *args, int *res)
321 struct linux_bind_args linux_args;
322 struct sockaddr *sa;
323 int error;
325 error = copyin(args, &linux_args, sizeof(linux_args));
326 if (error)
327 return (error);
328 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
329 if (error)
330 return (error);
332 error = kern_bind(linux_args.s, sa);
333 FREE(sa, M_SONAME);
335 return (error);
338 struct linux_connect_args {
339 int s;
340 struct sockaddr * name;
341 int namelen;
344 static int
345 linux_connect(struct linux_connect_args *args, int *res)
347 struct thread *td = curthread; /* XXX */
348 struct proc *p = td->td_proc;
349 struct linux_connect_args linux_args;
350 struct sockaddr *sa;
351 struct socket *so;
352 struct file *fp;
353 int error;
355 KKASSERT(p);
357 error = copyin(args, &linux_args, sizeof(linux_args));
358 if (error)
359 return (error);
360 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
361 if (error)
362 return (error);
364 error = kern_connect(linux_args.s, 0, sa);
365 FREE(sa, M_SONAME);
367 if (error != EISCONN)
368 return (error);
371 * Linux doesn't return EISCONN the first time it occurs,
372 * when on a non-blocking socket. Instead it returns the
373 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
375 error = holdsock(p->p_fd, linux_args.s, &fp);
376 if (error)
377 return (error);
378 error = EISCONN;
379 if (fp->f_flag & FNONBLOCK) {
380 so = (struct socket *)fp->f_data;
381 if (so->so_emuldata == 0)
382 error = so->so_error;
383 so->so_emuldata = (void *)1;
385 fdrop(fp);
386 return (error);
389 struct linux_listen_args {
390 int s;
391 int backlog;
394 static int
395 linux_listen(struct linux_listen_args *args, int *res)
397 struct linux_listen_args linux_args;
398 int error;
400 error = copyin(args, &linux_args, sizeof(linux_args));
401 if (error)
402 return (error);
404 error = kern_listen(linux_args.s, linux_args.backlog);
406 return(error);
409 struct linux_accept_args {
410 int s;
411 struct sockaddr *addr;
412 int *namelen;
415 static int
416 linux_accept(struct linux_accept_args *args, int *res)
418 struct linux_accept_args linux_args;
419 struct sockaddr *sa = NULL;
420 union fcntl_dat dat = { 0 };
421 int error, sa_len;
423 error = copyin(args, &linux_args, sizeof(linux_args));
424 if (error)
425 return (error);
427 if (linux_args.addr) {
428 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
429 if (error)
430 return (error);
432 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res);
434 if (error) {
436 * Return a namelen of zero for older code which
437 * might ignore the return value from accept().
439 sa_len = 0;
440 copyout(&sa_len, linux_args.namelen,
441 sizeof(*linux_args.namelen));
442 } else {
443 error = linux_copyout_sockaddr(sa, linux_args.addr,
444 sa_len);
445 if (error == 0) {
446 error = copyout(&sa_len, linux_args.namelen,
447 sizeof(*linux_args.namelen));
450 if (sa)
451 FREE(sa, M_SONAME);
452 } else {
453 error = kern_accept(linux_args.s, 0, NULL, 0, res);
456 if (error)
457 return (error);
460 * linux appears not to copy flags from the parent socket to the
461 * accepted one, so we must clear the flags in the new descriptor.
462 * Ignore any errors, because we already have an open fd.
464 kern_fcntl(*res, F_SETFL, &dat, curproc->p_ucred);
465 return (0);
468 struct linux_getsockname_args {
469 int s;
470 struct sockaddr *addr;
471 int *namelen;
474 static int
475 linux_getsockname(struct linux_getsockname_args *args, int *res)
477 struct linux_getsockname_args linux_args;
478 struct sockaddr *sa = NULL;
479 int error, sa_len;
482 error = copyin(args, &linux_args, sizeof(linux_args));
483 if (error)
484 return (error);
485 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
486 if (error)
487 return (error);
489 error = kern_getsockname(linux_args.s, &sa, &sa_len);
491 if (error == 0)
492 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
493 if (error == 0)
494 error = copyout(&sa_len, linux_args.namelen,
495 sizeof(*linux_args.namelen));
496 if (sa)
497 FREE(sa, M_SONAME);
498 return(error);
501 struct linux_getpeername_args {
502 int s;
503 struct sockaddr *addr;
504 int *namelen;
507 static int
508 linux_getpeername(struct linux_getpeername_args *args, int *res)
510 struct linux_getpeername_args linux_args;
511 struct sockaddr *sa = NULL;
512 int error, sa_len;
514 error = copyin(args, &linux_args, sizeof(linux_args));
515 if (error)
516 return (error);
517 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
518 if (error)
519 return (error);
521 error = kern_getpeername(linux_args.s, &sa, &sa_len);
523 if (error == 0)
524 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
525 if (error == 0)
526 error = copyout(&sa_len, linux_args.namelen,
527 sizeof(*linux_args.namelen));
528 if (sa)
529 FREE(sa, M_SONAME);
530 return(error);
533 struct linux_socketpair_args {
534 int domain;
535 int type;
536 int protocol;
537 int *rsv;
540 static int
541 linux_socketpair(struct linux_socketpair_args *args, int *res)
543 struct linux_socketpair_args linux_args;
544 int error, domain, sockv[2];
546 error = copyin(args, &linux_args, sizeof(linux_args));
547 if (error)
548 return (error);
550 domain = linux_to_bsd_domain(linux_args.domain);
551 if (domain == -1)
552 return (EINVAL);
553 error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
554 sockv);
556 if (error == 0)
557 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
558 return(error);
561 struct linux_send_args {
562 int s;
563 void *msg;
564 int len;
565 int flags;
568 static int
569 linux_send(struct linux_send_args *args, int *res)
571 struct linux_send_args linux_args;
572 struct thread *td = curthread;
573 struct uio auio;
574 struct iovec aiov;
575 int error;
577 error = copyin(args, &linux_args, sizeof(linux_args));
578 if (error)
579 return (error);
581 aiov.iov_base = linux_args.msg;
582 aiov.iov_len = linux_args.len;
583 auio.uio_iov = &aiov;
584 auio.uio_iovcnt = 1;
585 auio.uio_offset = 0;
586 auio.uio_resid = linux_args.len;
587 auio.uio_segflg = UIO_USERSPACE;
588 auio.uio_rw = UIO_WRITE;
589 auio.uio_td = td;
591 error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
592 linux_args.flags, res);
594 return(error);
597 struct linux_recv_args {
598 int s;
599 void *msg;
600 int len;
601 int flags;
604 static int
605 linux_recv(struct linux_recv_args *args, int *res)
607 struct linux_recv_args linux_args;
608 struct thread *td = curthread;
609 struct uio auio;
610 struct iovec aiov;
611 int error;
613 error = copyin(args, &linux_args, sizeof(linux_args));
614 if (error)
615 return (error);
617 aiov.iov_base = linux_args.msg;
618 aiov.iov_len = linux_args.len;
619 auio.uio_iov = &aiov;
620 auio.uio_iovcnt = 1;
621 auio.uio_offset = 0;
622 auio.uio_resid = linux_args.len;
623 auio.uio_segflg = UIO_USERSPACE;
624 auio.uio_rw = UIO_READ;
625 auio.uio_td = td;
627 error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
628 &linux_args.flags, res);
630 return(error);
633 struct linux_sendto_args {
634 int s;
635 void *msg;
636 int len;
637 int flags;
638 struct sockaddr *to;
639 int tolen;
642 static int
643 linux_sendto(struct linux_sendto_args *args, int *res)
645 struct linux_sendto_args linux_args;
646 struct thread *td = curthread;
647 struct uio auio;
648 struct iovec aiov;
649 struct sockopt sopt;
650 struct sockaddr *sa = NULL;
651 caddr_t msg = NULL;
652 int error, optval;
654 error = copyin(args, &linux_args, sizeof(linux_args));
655 if (error)
656 return (error);
658 if (linux_args.to) {
659 error = linux_getsockaddr(&sa, linux_args.to,
660 linux_args.tolen);
661 if (error)
662 return (error);
666 * Check to see if the IP_HDRINCL option is set.
668 sopt.sopt_dir = SOPT_GET;
669 sopt.sopt_level = IPPROTO_IP;
670 sopt.sopt_name = IP_HDRINCL;
671 sopt.sopt_val = &optval;
672 sopt.sopt_valsize = sizeof(optval);
673 sopt.sopt_td = NULL;
675 if (kern_getsockopt(linux_args.s, &sopt) != 0)
676 optval = 0;
678 if (optval == 0) {
680 * IP_HDRINCL is not set. Package the message as usual.
682 aiov.iov_base = linux_args.msg;
683 aiov.iov_len = linux_args.len;
684 auio.uio_iov = &aiov;
685 auio.uio_iovcnt = 1;
686 auio.uio_offset = 0;
687 auio.uio_resid = linux_args.len;
688 auio.uio_segflg = UIO_USERSPACE;
689 auio.uio_rw = UIO_WRITE;
690 auio.uio_td = td;
691 } else {
693 * IP_HDRINCL is set. We must convert the beginning of
694 * the packet header so we can feed it to the BSD kernel.
698 * Check that the packet header is long enough to contain
699 * the fields of interest. This relies on the fact that
700 * the fragment offset field comes after the length field.
702 if (linux_args.len < offsetof(struct ip, ip_off))
703 return (EINVAL);
705 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
706 error = copyin(linux_args.msg, msg, linux_args.len);
707 if (error)
708 goto cleanup;
710 /* Fix the ip_len and ip_off fields. */
711 ((struct ip *)msg)->ip_len = linux_args.len;
712 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
714 aiov.iov_base = msg;
715 aiov.iov_len = linux_args.len;
716 auio.uio_iov = &aiov;
717 auio.uio_iovcnt = 1;
718 auio.uio_offset = 0;
719 auio.uio_resid = linux_args.len;
720 auio.uio_segflg = UIO_SYSSPACE;
721 auio.uio_rw = UIO_WRITE;
722 auio.uio_td = td;
725 error = kern_sendmsg(linux_args.s, sa, &auio, NULL, linux_args.flags,
726 res);
728 cleanup:
729 if (sa)
730 FREE(sa, M_SONAME);
731 if (msg)
732 FREE(msg, M_LINUX);
733 return(error);
736 struct linux_recvfrom_args {
737 int s;
738 void *buf;
739 int len;
740 int flags;
741 struct sockaddr *from;
742 int *fromlen;
745 static int
746 linux_recvfrom(struct linux_recvfrom_args *args, int *res)
748 struct linux_recvfrom_args linux_args;
749 struct thread *td = curthread;
750 struct uio auio;
751 struct iovec aiov;
752 struct sockaddr *sa = NULL;
753 int error, fromlen, flags;
755 error = copyin(args, &linux_args, sizeof(linux_args));
756 if (error)
757 return (error);
759 if (linux_args.from && linux_args.fromlen) {
760 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
761 if (error)
762 return (error);
763 if (fromlen < 0)
764 return (EINVAL);
765 } else {
766 fromlen = 0;
768 aiov.iov_base = linux_args.buf;
769 aiov.iov_len = linux_args.len;
770 auio.uio_iov = &aiov;
771 auio.uio_iovcnt = 1;
772 auio.uio_offset = 0;
773 auio.uio_resid = linux_args.len;
774 auio.uio_segflg = UIO_USERSPACE;
775 auio.uio_rw = UIO_READ;
776 auio.uio_td = td;
778 flags = linux_to_bsd_msg_flags(linux_args.flags);
780 error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
781 NULL, &flags, res);
783 if (error == 0 && linux_args.from) {
784 if (sa != NULL) {
785 fromlen = MIN(fromlen, sa->sa_len);
786 error = linux_copyout_sockaddr(sa, linux_args.from,
787 fromlen);
788 } else
789 fromlen = 0;
790 if (error == 0)
791 copyout(&fromlen, linux_args.fromlen,
792 sizeof(fromlen));
794 if (sa)
795 FREE(sa, M_SONAME);
797 return(error);
800 struct linux_sendmsg_args {
801 int s;
802 struct msghdr *msg;
803 int flags;
806 static int
807 linux_sendmsg(struct linux_sendmsg_args *args, int *res)
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;
818 error = copyin(args, &linux_args, sizeof(linux_args));
819 if (error)
820 return (error);
822 error = copyin(linux_args.msg, &msg, sizeof(msg));
823 if (error)
824 return (error);
827 * Conditionally copyin msg.msg_name.
829 if (msg.msg_name) {
830 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
831 if (error)
832 return (error);
836 * Populate auio.
838 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
839 &auio.uio_resid);
840 if (error)
841 goto cleanup2;
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;
850 * Conditionally copyin msg.msg_control.
852 if (msg.msg_control) {
853 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
854 msg.msg_controllen > MLEN) {
855 error = EINVAL;
856 goto cleanup;
858 control = m_get(MB_WAIT, MT_CONTROL);
859 if (control == NULL) {
860 error = ENOBUFS;
861 goto cleanup;
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;
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.
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;
885 error = kern_sendmsg(linux_args.s, sa, &auio, control,
886 linux_args.flags, res);
888 cleanup:
889 iovec_free(&iov, aiov);
890 cleanup2:
891 if (sa)
892 FREE(sa, M_SONAME);
893 return (error);
896 struct linux_recvmsg_args {
897 int s;
898 struct msghdr *msg;
899 int flags;
902 static int
903 linux_recvmsg(struct linux_recvmsg_args *args, int *res)
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;
916 error = copyin(args, &linux_args, sizeof(linux_args));
917 if (error)
918 return (error);
920 error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
921 if (error)
922 return (error);
924 if (msg.msg_name && msg.msg_namelen < 0)
925 return (EINVAL);
926 if (msg.msg_control && msg.msg_controllen < 0)
927 return (EINVAL);
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));
937 * Populate auio.
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;
950 flags = linux_to_bsd_msg_flags(linux_args.flags);
952 error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
953 msg.msg_control ? &control : NULL, &flags, res);
956 * Copyout msg.msg_name and msg.msg_namelen.
958 if (error == 0 && msg.msg_name) {
959 if (sa != NULL) {
960 fromlen = MIN(msg.msg_namelen, sa->sa_len);
961 error = linux_copyout_sockaddr(sa, msg.msg_name,
962 fromlen);
963 } else
964 fromlen = 0;
965 if (error == 0)
966 error = copyout(&fromlen, ufromlenp,
967 sizeof(*ufromlenp));
971 * Copyout msg.msg_control and msg.msg_controllen.
973 if (error == 0 && msg.msg_control) {
975 * Linux and BSD both support SCM_RIGHTS. If a linux binary
976 * wants anything else with an option level of SOL_SOCKET,
977 * we don't support it.
979 if (mtod((struct mbuf *)msg.msg_control,
980 struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
981 mtod((struct mbuf *)msg.msg_control,
982 struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
983 error = EINVAL;
984 goto cleanup;
987 len = msg.msg_controllen;
988 m = control;
989 ctlbuf = (caddr_t)msg.msg_control;
991 while (m && len > 0) {
992 unsigned int tocopy;
994 if (len >= m->m_len) {
995 tocopy = m->m_len;
996 } else {
997 msg.msg_flags |= MSG_CTRUNC;
998 tocopy = len;
1001 error = copyout(mtod(m, caddr_t), ctlbuf,
1002 tocopy);
1003 if (error)
1004 goto cleanup;
1006 ctlbuf += tocopy;
1007 len -= tocopy;
1008 m = m->m_next;
1010 controllen = ctlbuf - (caddr_t)msg.msg_control;
1011 error = copyout(&controllen, ucontrollenp,
1012 sizeof(*ucontrollenp));
1015 if (error == 0)
1016 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1018 cleanup:
1019 if (sa)
1020 FREE(sa, M_SONAME);
1021 iovec_free(&iov, aiov);
1022 if (control)
1023 m_freem(control);
1024 return (error);
1027 struct linux_shutdown_args {
1028 int s;
1029 int how;
1032 static int
1033 linux_shutdown(struct linux_shutdown_args *args, int *res)
1035 struct linux_shutdown_args linux_args;
1036 int error;
1038 error = copyin(args, &linux_args, sizeof(linux_args));
1039 if (error)
1040 return (error);
1042 error = kern_shutdown(linux_args.s, linux_args.how);
1044 return (error);
1047 struct linux_setsockopt_args {
1048 int s;
1049 int level;
1050 int optname;
1051 void *optval;
1052 int optlen;
1055 static int
1056 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1058 struct linux_setsockopt_args linux_args;
1059 struct thread *td = curthread;
1060 struct sockopt sopt;
1061 int error, name, level;
1063 error = copyin(args, &linux_args, sizeof(linux_args));
1064 if (error)
1065 return (error);
1067 level = linux_to_bsd_sockopt_level(linux_args.level);
1068 switch (level) {
1069 case SOL_SOCKET:
1070 name = linux_to_bsd_so_sockopt(linux_args.optname);
1071 break;
1072 case IPPROTO_IP:
1073 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1074 break;
1075 case IPPROTO_TCP:
1076 /* Linux TCP option values match BSD's */
1077 name = linux_args.optname;
1078 break;
1079 default:
1080 name = -1;
1081 break;
1083 if (name == -1)
1084 return (EINVAL);
1086 sopt.sopt_dir = SOPT_SET;
1087 sopt.sopt_level = level;
1088 sopt.sopt_name = name;
1089 sopt.sopt_valsize = linux_args.optlen;
1090 sopt.sopt_td = td;
1092 if (sopt.sopt_valsize < 0 || sopt.sopt_valsize > SOMAXOPT_SIZE)
1093 return (EINVAL);
1095 if (linux_args.optval) {
1096 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1097 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1098 if (error)
1099 goto out;
1100 } else {
1101 sopt.sopt_val = NULL;
1103 error = kern_setsockopt(linux_args.s, &sopt);
1104 if (error)
1105 goto out;
1106 if (linux_args.optval)
1107 error = copyout(sopt.sopt_val, linux_args.optval,
1108 sopt.sopt_valsize);
1109 out:
1110 if (linux_args.optval)
1111 kfree(sopt.sopt_val, M_TEMP);
1112 return(error);
1115 struct linux_getsockopt_args {
1116 int s;
1117 int level;
1118 int optname;
1119 void *optval;
1120 int *optlen;
1123 static int
1124 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1126 struct linux_getsockopt_args linux_args;
1127 struct thread *td = curthread;
1128 struct sockopt sopt;
1129 int error, name, valsize, level;
1131 error = copyin(args, &linux_args, sizeof(linux_args));
1132 if (error)
1133 return (error);
1135 if (linux_args.optval) {
1136 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1137 if (error)
1138 return (error);
1139 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1140 return (EINVAL);
1141 } else {
1142 valsize = 0;
1145 level = linux_to_bsd_sockopt_level(linux_args.level);
1146 switch (level) {
1147 case SOL_SOCKET:
1148 name = linux_to_bsd_so_sockopt(linux_args.optname);
1149 break;
1150 case IPPROTO_IP:
1151 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1152 break;
1153 case IPPROTO_TCP:
1154 /* Linux TCP option values match BSD's */
1155 name = linux_args.optname;
1156 break;
1157 default:
1158 name = -1;
1159 break;
1161 if (name == -1)
1162 return (EINVAL);
1164 sopt.sopt_dir = SOPT_GET;
1165 sopt.sopt_level = level;
1166 sopt.sopt_name = name;
1167 sopt.sopt_valsize = valsize;
1168 sopt.sopt_td = td;
1170 if (linux_args.optval) {
1171 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1172 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1173 if (error)
1174 goto out;
1175 } else {
1176 sopt.sopt_val = NULL;
1178 error = kern_getsockopt(linux_args.s, &sopt);
1179 if (error)
1180 goto out;
1181 valsize = sopt.sopt_valsize;
1182 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1183 if (error)
1184 goto out;
1185 if (linux_args.optval)
1186 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1187 out:
1188 if (linux_args.optval)
1189 kfree(sopt.sopt_val, M_TEMP);
1190 return(error);
1194 sys_linux_socketcall(struct linux_socketcall_args *args)
1196 void *arg = (void *)args->args;
1198 switch (args->what) {
1199 case LINUX_SOCKET:
1200 return (linux_socket(arg, &args->sysmsg_result));
1201 case LINUX_BIND:
1202 return (linux_bind(arg, &args->sysmsg_result));
1203 case LINUX_CONNECT:
1204 return (linux_connect(arg, &args->sysmsg_result));
1205 case LINUX_LISTEN:
1206 return (linux_listen(arg, &args->sysmsg_result));
1207 case LINUX_ACCEPT:
1208 return (linux_accept(arg, &args->sysmsg_result));
1209 case LINUX_GETSOCKNAME:
1210 return (linux_getsockname(arg, &args->sysmsg_result));
1211 case LINUX_GETPEERNAME:
1212 return (linux_getpeername(arg, &args->sysmsg_result));
1213 case LINUX_SOCKETPAIR:
1214 return (linux_socketpair(arg, &args->sysmsg_result));
1215 case LINUX_SEND:
1216 return (linux_send(arg, &args->sysmsg_result));
1217 case LINUX_RECV:
1218 return (linux_recv(arg, &args->sysmsg_result));
1219 case LINUX_SENDTO:
1220 return (linux_sendto(arg, &args->sysmsg_result));
1221 case LINUX_RECVFROM:
1222 return (linux_recvfrom(arg, &args->sysmsg_result));
1223 case LINUX_SHUTDOWN:
1224 return (linux_shutdown(arg, &args->sysmsg_result));
1225 case LINUX_SETSOCKOPT:
1226 return (linux_setsockopt(arg, &args->sysmsg_result));
1227 case LINUX_GETSOCKOPT:
1228 return (linux_getsockopt(arg, &args->sysmsg_result));
1229 case LINUX_SENDMSG:
1230 return (linux_sendmsg(arg, &args->sysmsg_result));
1231 case LINUX_RECVMSG:
1232 return (linux_recvmsg(arg, &args->sysmsg_result));
1235 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1236 return (ENOSYS);