2 * Copyright (c) 1995 Søren Schmidt
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 without 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 $
31 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sysproto.h>
35 #include <sys/fcntl.h>
37 #include <sys/kern_syscall.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
41 #include <sys/malloc.h>
45 #include <sys/mplock2.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
51 #include <arch_linux/linux.h>
52 #include <arch_linux/linux_proto.h>
53 #include "linux_socket.h"
54 #include "linux_util.h"
57 * Copyin a sockaddr structure provided by a Linux binary. Linux uses
58 * the 4.3BSD sockaddr structure which has no sa_len field. We must
59 * pass 4.4BSD sockaddr structures when we call native functions in the
60 * BSD kernel. This function does the conversion for us.
62 * Also, our socket calls require the sockaddr structure length to agree
63 * with the address family. Linux does not, so we must force it.
65 * This function should only need to be called from linux_connect()
69 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
72 uint16_t family; /* XXX: must match Linux sockaddr */
78 if (len > SOCK_MAXADDRLEN)
80 error = copyin(uaddr, &family, sizeof(family));
85 * Force the sa_len field to match the address family.
89 sa_len = sizeof(struct sockaddr_in);
92 sa_len = sizeof(struct sockaddr_in6);
96 * This is the default behavior of the old
97 * linux_to_bsd_namelen() function. NOTE! The
98 * minimum length we allocate must cover sa->sa_len and
101 sa_len = offsetof(struct sockaddr, sa_data[0]);
107 sa = kmalloc(sa_len, M_SONAME, M_WAITOK);
108 error = copyin(uaddr, sa, sa_len);
113 * Convert to the 4.4BSD sockaddr structure.
115 sa->sa_family = *(sa_family_t *)sa;
124 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
125 * and copy it out to a user address.
128 linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
132 if (sa_len < (int)sizeof(u_short))
135 *(u_short *)sa = sa->sa_family;
136 error = copyout(sa, uaddr, sa_len);
142 linux_to_bsd_domain(int domain)
146 case LINUX_AF_UNSPEC:
161 linux_to_bsd_sockopt_level(int level)
165 case LINUX_SOL_SOCKET:
172 linux_to_bsd_ip_sockopt(int opt)
180 case LINUX_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:
199 linux_to_bsd_so_sockopt(int opt)
205 case LINUX_SO_REUSEADDR:
206 return (SO_REUSEADDR);
211 case LINUX_SO_DONTROUTE:
212 return (SO_DONTROUTE);
213 case LINUX_SO_BROADCAST:
214 return (SO_BROADCAST);
215 case LINUX_SO_SNDBUF:
217 case LINUX_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:
225 case LINUX_SO_PEERCRED:
226 return (LOCAL_PEERCRED);
232 linux_to_bsd_msg_flags(int flags)
236 if (flags & LINUX_MSG_OOB)
237 ret_flags |= MSG_OOB;
238 if (flags & LINUX_MSG_PEEK)
239 ret_flags |= MSG_PEEK;
240 if (flags & LINUX_MSG_DONTROUTE)
241 ret_flags |= MSG_DONTROUTE;
242 if (flags & LINUX_MSG_CTRUNC)
243 ret_flags |= MSG_CTRUNC;
244 if (flags & LINUX_MSG_TRUNC)
245 ret_flags |= MSG_TRUNC;
246 if (flags & LINUX_MSG_DONTWAIT)
247 ret_flags |= MSG_DONTWAIT;
248 if (flags & LINUX_MSG_EOR)
249 ret_flags |= MSG_EOR;
250 if (flags & LINUX_MSG_WAITALL)
251 ret_flags |= MSG_WAITALL;
252 #if 0 /* not handled */
253 if (flags & LINUX_MSG_PROXY)
255 if (flags & LINUX_MSG_FIN)
257 if (flags & LINUX_MSG_SYN)
259 if (flags & LINUX_MSG_CONFIRM)
261 if (flags & LINUX_MSG_RST)
263 if (flags & LINUX_MSG_ERRQUEUE)
265 if (flags & LINUX_MSG_NOSIGNAL)
271 struct linux_socket_args {
278 linux_socket(struct linux_socket_args *args, int *res)
280 struct linux_socket_args linux_args;
282 int error, domain, optval;
284 error = copyin(args, &linux_args, sizeof(linux_args));
288 domain = linux_to_bsd_domain(linux_args.domain);
292 error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
294 /* Copy back the return value from socket() */
295 if (error == 0 && linux_args.type == SOCK_RAW &&
296 (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
297 linux_args.domain == AF_INET) {
298 /* It's a raw IP socket: set the IP_HDRINCL option. */
300 sopt.sopt_dir = SOPT_SET;
301 sopt.sopt_level = IPPROTO_IP;
302 sopt.sopt_name = IP_HDRINCL;
303 sopt.sopt_val = &optval;
304 sopt.sopt_valsize = sizeof(optval);
307 /* We ignore any error returned by setsockopt() */
308 kern_setsockopt(*res, &sopt);
314 struct linux_bind_args {
316 struct sockaddr *name;
321 linux_bind(struct linux_bind_args *args, int *res)
323 struct linux_bind_args linux_args;
327 error = copyin(args, &linux_args, sizeof(linux_args));
330 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
334 error = kern_bind(linux_args.s, sa);
340 struct linux_connect_args {
342 struct sockaddr * name;
347 linux_connect(struct linux_connect_args *args, int *res)
349 struct thread *td = curthread; /* XXX */
350 struct proc *p = td->td_proc;
351 struct linux_connect_args linux_args;
359 error = copyin(args, &linux_args, sizeof(linux_args));
362 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
366 error = kern_connect(linux_args.s, 0, sa);
369 if (error != EISCONN)
373 * Linux doesn't return EISCONN the first time it occurs,
374 * when on a non-blocking socket. Instead it returns the
375 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
377 error = holdsock(p->p_fd, linux_args.s, &fp);
381 if (fp->f_flag & FNONBLOCK) {
382 so = (struct socket *)fp->f_data;
383 if (so->so_emuldata == 0)
384 error = so->so_error;
385 so->so_emuldata = (void *)1;
391 struct linux_listen_args {
397 linux_listen(struct linux_listen_args *args, int *res)
399 struct linux_listen_args linux_args;
402 error = copyin(args, &linux_args, sizeof(linux_args));
406 error = kern_listen(linux_args.s, linux_args.backlog);
411 struct linux_accept_args {
413 struct sockaddr *addr;
418 linux_accept(struct linux_accept_args *args, int *res)
420 struct thread *td = curthread;
421 struct linux_accept_args linux_args;
422 struct sockaddr *sa = NULL;
423 union fcntl_dat dat = { 0 };
426 error = copyin(args, &linux_args, sizeof(linux_args));
430 if (linux_args.addr) {
431 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
435 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res,
436 SOCK_KERN_NOINHERIT);
440 * Return a namelen of zero for older code which
441 * might ignore the return value from accept().
444 copyout(&sa_len, linux_args.namelen,
445 sizeof(*linux_args.namelen));
447 error = linux_copyout_sockaddr(sa, linux_args.addr,
450 error = copyout(&sa_len, linux_args.namelen,
451 sizeof(*linux_args.namelen));
457 error = kern_accept(linux_args.s, 0, NULL, 0, res);
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.
468 kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
472 struct linux_getsockname_args {
474 struct sockaddr *addr;
479 linux_getsockname(struct linux_getsockname_args *args, int *res)
481 struct linux_getsockname_args linux_args;
482 struct sockaddr *sa = NULL;
486 error = copyin(args, &linux_args, sizeof(linux_args));
489 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
493 error = kern_getsockname(linux_args.s, &sa, &sa_len);
496 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
498 error = copyout(&sa_len, linux_args.namelen,
499 sizeof(*linux_args.namelen));
505 struct linux_getpeername_args {
507 struct sockaddr *addr;
512 linux_getpeername(struct linux_getpeername_args *args, int *res)
514 struct linux_getpeername_args linux_args;
515 struct sockaddr *sa = NULL;
518 error = copyin(args, &linux_args, sizeof(linux_args));
521 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
525 error = kern_getpeername(linux_args.s, &sa, &sa_len);
528 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
530 error = copyout(&sa_len, linux_args.namelen,
531 sizeof(*linux_args.namelen));
537 struct linux_socketpair_args {
545 linux_socketpair(struct linux_socketpair_args *args, int *res)
547 struct linux_socketpair_args linux_args;
548 int error, domain, sockv[2];
550 error = copyin(args, &linux_args, sizeof(linux_args));
554 domain = linux_to_bsd_domain(linux_args.domain);
557 error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
561 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
565 struct linux_send_args {
573 linux_send(struct linux_send_args *args, size_t *res)
575 struct linux_send_args linux_args;
576 struct thread *td = curthread;
581 error = copyin(args, &linux_args, sizeof(linux_args));
585 aiov.iov_base = linux_args.msg;
586 aiov.iov_len = linux_args.len;
587 auio.uio_iov = &aiov;
590 auio.uio_resid = linux_args.len;
591 auio.uio_segflg = UIO_USERSPACE;
592 auio.uio_rw = UIO_WRITE;
595 error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
596 linux_args.flags, res);
601 struct linux_recv_args {
609 linux_recv(struct linux_recv_args *args, size_t *res)
611 struct linux_recv_args linux_args;
612 struct thread *td = curthread;
617 error = copyin(args, &linux_args, sizeof(linux_args));
621 aiov.iov_base = linux_args.msg;
622 aiov.iov_len = linux_args.len;
623 auio.uio_iov = &aiov;
626 auio.uio_resid = linux_args.len;
627 auio.uio_segflg = UIO_USERSPACE;
628 auio.uio_rw = UIO_READ;
631 error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
632 &linux_args.flags, res);
637 struct linux_sendto_args {
647 linux_sendto(struct linux_sendto_args *args, size_t *res)
649 struct linux_sendto_args linux_args;
650 struct thread *td = curthread;
654 struct sockaddr *sa = NULL;
658 error = copyin(args, &linux_args, sizeof(linux_args));
663 error = linux_getsockaddr(&sa, linux_args.to,
670 * Check to see if the IP_HDRINCL option is set.
672 sopt.sopt_dir = SOPT_GET;
673 sopt.sopt_level = IPPROTO_IP;
674 sopt.sopt_name = IP_HDRINCL;
675 sopt.sopt_val = &optval;
676 sopt.sopt_valsize = sizeof(optval);
679 if (kern_getsockopt(linux_args.s, &sopt) != 0)
684 * IP_HDRINCL is not set. Package the message as usual.
686 aiov.iov_base = linux_args.msg;
687 aiov.iov_len = linux_args.len;
688 auio.uio_iov = &aiov;
691 auio.uio_resid = linux_args.len;
692 auio.uio_segflg = UIO_USERSPACE;
693 auio.uio_rw = UIO_WRITE;
697 * IP_HDRINCL is set. We must convert the beginning of
698 * the packet header so we can feed it to the BSD kernel.
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.
706 if (linux_args.len < offsetof(struct ip, ip_off))
709 msg = kmalloc(linux_args.len, M_LINUX, M_WAITOK);
710 error = copyin(linux_args.msg, msg, linux_args.len);
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);
719 aiov.iov_len = linux_args.len;
720 auio.uio_iov = &aiov;
723 auio.uio_resid = linux_args.len;
724 auio.uio_segflg = UIO_SYSSPACE;
725 auio.uio_rw = UIO_WRITE;
729 error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
730 linux_args.flags, res);
740 struct linux_recvfrom_args {
745 struct sockaddr *from;
750 linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
752 struct linux_recvfrom_args linux_args;
753 struct thread *td = curthread;
756 struct sockaddr *sa = NULL;
757 int error, fromlen, flags;
759 error = copyin(args, &linux_args, sizeof(linux_args));
763 if (linux_args.from && linux_args.fromlen) {
764 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
772 aiov.iov_base = linux_args.buf;
773 aiov.iov_len = linux_args.len;
774 auio.uio_iov = &aiov;
777 auio.uio_resid = linux_args.len;
778 auio.uio_segflg = UIO_USERSPACE;
779 auio.uio_rw = UIO_READ;
782 flags = linux_to_bsd_msg_flags(linux_args.flags);
784 error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
787 if (error == 0 && linux_args.from) {
789 fromlen = MIN(fromlen, sa->sa_len);
790 error = linux_copyout_sockaddr(sa, linux_args.from,
795 copyout(&fromlen, linux_args.fromlen,
804 struct linux_sendmsg_args {
811 linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
813 struct linux_sendmsg_args linux_args;
814 struct thread *td = curthread;
817 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
818 struct sockaddr *sa = NULL;
819 struct mbuf *control = NULL;
822 error = copyin(args, &linux_args, sizeof(linux_args));
826 error = copyin(linux_args.msg, &msg, sizeof(msg));
831 * XXX: I'm not sure atm how this relates to dragonfly, but
832 * just in case, I put it in.
833 * Ping on linux does pass 0 in controllen which is forbidden
834 * by FreeBSD but seems to be ok on Linux. This needs some
835 * checking but now it lets ping work.
837 if (msg.msg_control && msg.msg_controllen == 0)
838 msg.msg_control = NULL;
841 * Conditionally copyin msg.msg_name.
844 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
852 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
857 auio.uio_iovcnt = msg.msg_iovlen;
859 auio.uio_segflg = UIO_USERSPACE;
860 auio.uio_rw = UIO_WRITE;
864 * Conditionally copyin msg.msg_control.
866 if (msg.msg_control) {
867 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
868 msg.msg_controllen > MLEN) {
872 control = m_get(M_WAITOK, MT_CONTROL);
873 if (control == NULL) {
877 control->m_len = msg.msg_controllen;
878 error = copyin(msg.msg_control, mtod(control, caddr_t),
885 * Linux and BSD both support SCM_RIGHTS. If a linux binary
886 * wants anything else with an option level of SOL_SOCKET,
887 * we don't support it.
889 if (mtod(control, struct cmsghdr *)->cmsg_level ==
891 mtod(control, struct cmsghdr *)->cmsg_type !=
899 error = kern_sendmsg(linux_args.s, sa, &auio, control,
900 linux_args.flags, res);
903 iovec_free(&iov, aiov);
910 struct linux_recvmsg_args {
917 linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
919 struct linux_recvmsg_args linux_args;
920 struct thread *td = curthread;
923 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
924 struct mbuf *m, *control = NULL;
925 struct sockaddr *sa = NULL;
927 socklen_t *ufromlenp, *ucontrollenp;
928 int error, fromlen, controllen, len, flags, *uflagsp;
930 error = copyin(args, &linux_args, sizeof(linux_args));
934 error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
938 if (msg.msg_name && msg.msg_namelen < 0)
940 if (msg.msg_control && msg.msg_controllen < 0)
943 ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
944 offsetof(struct msghdr, msg_namelen));
945 ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
946 offsetof(struct msghdr, msg_controllen));
947 uflagsp = (int *)((caddr_t)linux_args.msg +
948 offsetof(struct msghdr, msg_flags));
953 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
958 auio.uio_iovcnt = msg.msg_iovlen;
960 auio.uio_segflg = UIO_USERSPACE;
961 auio.uio_rw = UIO_READ;
964 flags = linux_to_bsd_msg_flags(linux_args.flags);
966 error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
967 msg.msg_control ? &control : NULL, &flags, res);
970 * Copyout msg.msg_name and msg.msg_namelen.
972 if (error == 0 && msg.msg_name) {
974 fromlen = MIN(msg.msg_namelen, sa->sa_len);
975 error = linux_copyout_sockaddr(sa, msg.msg_name,
980 error = copyout(&fromlen, ufromlenp,
985 * Copyout msg.msg_control and msg.msg_controllen.
987 if (error == 0 && msg.msg_control) {
989 * Linux and BSD both support SCM_RIGHTS. If a linux binary
990 * wants anything else with an option level of SOL_SOCKET,
991 * we don't support it.
993 if (mtod((struct mbuf *)msg.msg_control,
994 struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
995 mtod((struct mbuf *)msg.msg_control,
996 struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
1001 len = msg.msg_controllen;
1003 ctlbuf = (caddr_t)msg.msg_control;
1005 while (m && len > 0) {
1006 unsigned int tocopy;
1008 if (len >= m->m_len) {
1011 msg.msg_flags |= MSG_CTRUNC;
1015 error = copyout(mtod(m, caddr_t), ctlbuf,
1024 controllen = ctlbuf - (caddr_t)msg.msg_control;
1025 error = copyout(&controllen, ucontrollenp,
1026 sizeof(*ucontrollenp));
1030 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1034 kfree(sa, M_SONAME);
1035 iovec_free(&iov, aiov);
1041 struct linux_shutdown_args {
1047 linux_shutdown(struct linux_shutdown_args *args, int *res)
1049 struct linux_shutdown_args linux_args;
1052 error = copyin(args, &linux_args, sizeof(linux_args));
1056 error = kern_shutdown(linux_args.s, linux_args.how);
1061 struct linux_setsockopt_args {
1070 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1072 struct linux_setsockopt_args linux_args;
1073 struct thread *td = curthread;
1074 struct sockopt sopt;
1077 int error, name, level;
1079 error = copyin(args, &linux_args, sizeof(linux_args));
1083 level = linux_to_bsd_sockopt_level(linux_args.level);
1086 name = linux_to_bsd_so_sockopt(linux_args.optname);
1091 error = copyin(linux_args.optval, &linux_tv,
1095 tv.tv_sec = linux_tv.tv_sec;
1096 tv.tv_usec = linux_tv.tv_usec;
1097 sopt.sopt_dir = SOPT_SET;
1098 sopt.sopt_level = level;
1099 sopt.sopt_name = name;
1100 sopt.sopt_valsize = sizeof(tv);
1101 sopt.sopt_val = &tv;
1103 return (kern_setsockopt(linux_args.s, &sopt));
1111 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1114 /* Linux TCP option values match BSD's */
1115 name = linux_args.optname;
1122 return (ENOPROTOOPT);
1124 if (linux_args.optlen < 0 || linux_args.optlen > SOMAXOPT_SIZE)
1126 if (linux_args.optval != NULL && linux_args.optlen == 0)
1128 if (linux_args.optval == NULL && linux_args.optlen != 0)
1131 sopt.sopt_dir = SOPT_SET;
1132 sopt.sopt_level = level;
1133 sopt.sopt_name = name;
1134 sopt.sopt_valsize = linux_args.optlen;
1137 if (linux_args.optval) {
1138 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1139 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1143 sopt.sopt_val = NULL;
1145 error = kern_setsockopt(linux_args.s, &sopt);
1148 if (linux_args.optval)
1149 error = copyout(sopt.sopt_val, linux_args.optval,
1152 if (linux_args.optval)
1153 kfree(sopt.sopt_val, M_TEMP);
1157 struct linux_getsockopt_args {
1166 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1168 struct linux_getsockopt_args linux_args;
1169 struct thread *td = curthread;
1170 struct sockopt sopt;
1175 int error, name, valsize, level;
1177 error = copyin(args, &linux_args, sizeof(linux_args));
1181 if (linux_args.optlen) {
1182 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1189 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1191 if (linux_args.optval != NULL && valsize == 0)
1193 if (linux_args.optval == NULL && valsize != 0)
1196 level = linux_to_bsd_sockopt_level(linux_args.level);
1199 name = linux_to_bsd_so_sockopt(linux_args.optname);
1204 sopt.sopt_dir = SOPT_GET;
1205 sopt.sopt_level = level;
1206 sopt.sopt_name = name;
1207 sopt.sopt_valsize = sizeof(tv);
1209 sopt.sopt_val = &tv;
1210 error = kern_getsockopt(linux_args.s, &sopt);
1213 linux_tv.tv_sec = tv.tv_sec;
1214 linux_tv.tv_usec = tv.tv_usec;
1215 return (copyout(&linux_tv, linux_args.optval,
1219 case LOCAL_PEERCRED:
1220 if (valsize != sizeof(lxu))
1222 sopt.sopt_dir = SOPT_GET;
1223 sopt.sopt_level = level;
1224 sopt.sopt_name = name;
1225 sopt.sopt_valsize = sizeof(xu);
1227 sopt.sopt_val = &xu;
1228 error = kern_getsockopt(linux_args.s, &sopt);
1232 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1235 lxu.uid = xu.cr_uid;
1236 lxu.gid = xu.cr_gid;
1237 return (copyout(&lxu, linux_args.optval, sizeof(lxu)));
1245 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1248 /* Linux TCP option values match BSD's */
1249 name = linux_args.optname;
1256 return (EOPNOTSUPP);
1260 sopt.sopt_dir = SOPT_GET;
1261 sopt.sopt_level = level;
1262 sopt.sopt_name = name;
1263 sopt.sopt_valsize = valsize;
1266 if (linux_args.optval) {
1267 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1268 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1272 sopt.sopt_val = NULL;
1274 error = kern_getsockopt(linux_args.s, &sopt);
1276 if (error == EINVAL)
1277 error = ENOPROTOOPT;
1280 valsize = sopt.sopt_valsize;
1281 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1284 if (linux_args.optval)
1285 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1287 if (linux_args.optval)
1288 kfree(sopt.sopt_val, M_TEMP);
1296 sys_linux_socketcall(struct linux_socketcall_args *args)
1298 void *arg = (void *)args->args;
1303 switch (args->what) {
1305 error = linux_socket(arg, &args->sysmsg_result);
1308 error = linux_bind(arg, &args->sysmsg_result);
1311 error = linux_connect(arg, &args->sysmsg_result);
1314 error = linux_listen(arg, &args->sysmsg_result);
1317 error = linux_accept(arg, &args->sysmsg_result);
1319 case LINUX_GETSOCKNAME:
1320 error = linux_getsockname(arg, &args->sysmsg_result);
1322 case LINUX_GETPEERNAME:
1323 error = linux_getpeername(arg, &args->sysmsg_result);
1325 case LINUX_SOCKETPAIR:
1326 error = linux_socketpair(arg, &args->sysmsg_result);
1329 error = linux_send(arg, &args->sysmsg_szresult);
1332 error = linux_recv(arg, &args->sysmsg_szresult);
1335 error = linux_sendto(arg, &args->sysmsg_szresult);
1337 case LINUX_RECVFROM:
1338 error = linux_recvfrom(arg, &args->sysmsg_szresult);
1340 case LINUX_SHUTDOWN:
1341 error = linux_shutdown(arg, &args->sysmsg_result);
1343 case LINUX_SETSOCKOPT:
1344 error = linux_setsockopt(arg, &args->sysmsg_result);
1346 case LINUX_GETSOCKOPT:
1347 error = linux_getsockopt(arg, &args->sysmsg_result);
1350 error = linux_sendmsg(arg, &args->sysmsg_szresult);
1353 error = linux_recvmsg(arg, &args->sysmsg_szresult);
1356 uprintf("LINUX: 'socket' typ=%d not implemented\n",