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 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>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/fcntl.h>
38 #include <sys/kern_syscall.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
42 #include <sys/malloc.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()
70 linux_getsockaddr(struct sockaddr
**namp
, struct sockaddr
*uaddr
, size_t len
)
73 uint16_t family
; /* XXX: must match Linux sockaddr */
79 if (len
> SOCK_MAXADDRLEN
)
81 error
= copyin(uaddr
, &family
, sizeof(family
));
86 * Force the sa_len field to match the address family.
90 sa_len
= sizeof(struct sockaddr_in
);
93 sa_len
= sizeof(struct sockaddr_in6
);
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
102 sa_len
= offsetof(struct sockaddr
, sa_data
[0]);
108 MALLOC(sa
, struct sockaddr
*, sa_len
, M_SONAME
, M_WAITOK
);
109 error
= copyin(uaddr
, sa
, sa_len
);
114 * Convert to the 4.4BSD sockaddr structure.
116 sa
->sa_family
= *(sa_family_t
*)sa
;
125 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
126 * and copy it out to a user address.
129 linux_copyout_sockaddr(struct sockaddr
*sa
, struct sockaddr
*uaddr
, int sa_len
)
133 if (sa_len
< (int)sizeof(u_short
))
136 *(u_short
*)sa
= sa
->sa_family
;
137 error
= copyout(sa
, uaddr
, sa_len
);
143 linux_to_bsd_domain(int domain
)
147 case LINUX_AF_UNSPEC
:
157 case LINUX_AF_APPLETALK
:
158 return (AF_APPLETALK
);
164 linux_to_bsd_sockopt_level(int level
)
168 case LINUX_SOL_SOCKET
:
175 linux_to_bsd_ip_sockopt(int opt
)
183 case LINUX_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
:
202 linux_to_bsd_so_sockopt(int opt
)
208 case LINUX_SO_REUSEADDR
:
209 return (SO_REUSEADDR
);
214 case LINUX_SO_DONTROUTE
:
215 return (SO_DONTROUTE
);
216 case LINUX_SO_BROADCAST
:
217 return (SO_BROADCAST
);
218 case LINUX_SO_SNDBUF
:
220 case LINUX_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
:
228 case LINUX_SO_PEERCRED
:
229 return (LOCAL_PEERCRED
);
235 linux_to_bsd_msg_flags(int flags
)
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
)
274 struct linux_socket_args
{
281 linux_socket(struct linux_socket_args
*args
, int *res
)
283 struct linux_socket_args linux_args
;
285 int error
, domain
, optval
;
287 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
291 domain
= linux_to_bsd_domain(linux_args
.domain
);
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. */
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
);
310 /* We ignore any error returned by setsockopt() */
311 kern_setsockopt(*res
, &sopt
);
317 struct linux_bind_args
{
319 struct sockaddr
*name
;
324 linux_bind(struct linux_bind_args
*args
, int *res
)
326 struct linux_bind_args linux_args
;
330 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
333 error
= linux_getsockaddr(&sa
, linux_args
.name
, linux_args
.namelen
);
337 error
= kern_bind(linux_args
.s
, sa
);
343 struct linux_connect_args
{
345 struct sockaddr
* name
;
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
;
362 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
365 error
= linux_getsockaddr(&sa
, linux_args
.name
, linux_args
.namelen
);
369 error
= kern_connect(linux_args
.s
, 0, sa
);
372 if (error
!= EISCONN
)
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
);
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;
394 struct linux_listen_args
{
400 linux_listen(struct linux_listen_args
*args
, int *res
)
402 struct linux_listen_args linux_args
;
405 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
409 error
= kern_listen(linux_args
.s
, linux_args
.backlog
);
414 struct linux_accept_args
{
416 struct sockaddr
*addr
;
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 };
429 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
433 if (linux_args
.addr
) {
434 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
438 error
= kern_accept(linux_args
.s
, 0, &sa
, &sa_len
, res
);
442 * Return a namelen of zero for older code which
443 * might ignore the return value from accept().
446 copyout(&sa_len
, linux_args
.namelen
,
447 sizeof(*linux_args
.namelen
));
449 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
,
452 error
= copyout(&sa_len
, linux_args
.namelen
,
453 sizeof(*linux_args
.namelen
));
459 error
= kern_accept(linux_args
.s
, 0, NULL
, 0, res
);
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
);
474 struct linux_getsockname_args
{
476 struct sockaddr
*addr
;
481 linux_getsockname(struct linux_getsockname_args
*args
, int *res
)
483 struct linux_getsockname_args linux_args
;
484 struct sockaddr
*sa
= NULL
;
488 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
491 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
495 error
= kern_getsockname(linux_args
.s
, &sa
, &sa_len
);
498 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
, sa_len
);
500 error
= copyout(&sa_len
, linux_args
.namelen
,
501 sizeof(*linux_args
.namelen
));
507 struct linux_getpeername_args
{
509 struct sockaddr
*addr
;
514 linux_getpeername(struct linux_getpeername_args
*args
, int *res
)
516 struct linux_getpeername_args linux_args
;
517 struct sockaddr
*sa
= NULL
;
520 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
523 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
527 error
= kern_getpeername(linux_args
.s
, &sa
, &sa_len
);
530 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
, sa_len
);
532 error
= copyout(&sa_len
, linux_args
.namelen
,
533 sizeof(*linux_args
.namelen
));
539 struct linux_socketpair_args
{
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
));
556 domain
= linux_to_bsd_domain(linux_args
.domain
);
559 error
= kern_socketpair(domain
, linux_args
.type
, linux_args
.protocol
,
563 error
= copyout(sockv
, linux_args
.rsv
, sizeof(sockv
));
567 struct linux_send_args
{
575 linux_send(struct linux_send_args
*args
, size_t *res
)
577 struct linux_send_args linux_args
;
578 struct thread
*td
= curthread
;
583 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
587 aiov
.iov_base
= linux_args
.msg
;
588 aiov
.iov_len
= linux_args
.len
;
589 auio
.uio_iov
= &aiov
;
592 auio
.uio_resid
= linux_args
.len
;
593 auio
.uio_segflg
= UIO_USERSPACE
;
594 auio
.uio_rw
= UIO_WRITE
;
597 error
= kern_sendmsg(linux_args
.s
, NULL
, &auio
, NULL
,
598 linux_args
.flags
, res
);
603 struct linux_recv_args
{
611 linux_recv(struct linux_recv_args
*args
, size_t *res
)
613 struct linux_recv_args linux_args
;
614 struct thread
*td
= curthread
;
619 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
623 aiov
.iov_base
= linux_args
.msg
;
624 aiov
.iov_len
= linux_args
.len
;
625 auio
.uio_iov
= &aiov
;
628 auio
.uio_resid
= linux_args
.len
;
629 auio
.uio_segflg
= UIO_USERSPACE
;
630 auio
.uio_rw
= UIO_READ
;
633 error
= kern_recvmsg(linux_args
.s
, NULL
, &auio
, NULL
,
634 &linux_args
.flags
, res
);
639 struct linux_sendto_args
{
649 linux_sendto(struct linux_sendto_args
*args
, size_t *res
)
651 struct linux_sendto_args linux_args
;
652 struct thread
*td
= curthread
;
656 struct sockaddr
*sa
= NULL
;
660 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
665 error
= linux_getsockaddr(&sa
, linux_args
.to
,
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
);
681 if (kern_getsockopt(linux_args
.s
, &sopt
) != 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
;
693 auio
.uio_resid
= linux_args
.len
;
694 auio
.uio_segflg
= UIO_USERSPACE
;
695 auio
.uio_rw
= UIO_WRITE
;
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
))
711 MALLOC(msg
, caddr_t
, linux_args
.len
, M_LINUX
, M_WAITOK
);
712 error
= copyin(linux_args
.msg
, msg
, linux_args
.len
);
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
);
721 aiov
.iov_len
= linux_args
.len
;
722 auio
.uio_iov
= &aiov
;
725 auio
.uio_resid
= linux_args
.len
;
726 auio
.uio_segflg
= UIO_SYSSPACE
;
727 auio
.uio_rw
= UIO_WRITE
;
731 error
= kern_sendmsg(linux_args
.s
, sa
, &auio
, NULL
,
732 linux_args
.flags
, res
);
742 struct linux_recvfrom_args
{
747 struct sockaddr
*from
;
752 linux_recvfrom(struct linux_recvfrom_args
*args
, size_t *res
)
754 struct linux_recvfrom_args linux_args
;
755 struct thread
*td
= curthread
;
758 struct sockaddr
*sa
= NULL
;
759 int error
, fromlen
, flags
;
761 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
765 if (linux_args
.from
&& linux_args
.fromlen
) {
766 error
= copyin(linux_args
.fromlen
, &fromlen
, sizeof(fromlen
));
774 aiov
.iov_base
= linux_args
.buf
;
775 aiov
.iov_len
= linux_args
.len
;
776 auio
.uio_iov
= &aiov
;
779 auio
.uio_resid
= linux_args
.len
;
780 auio
.uio_segflg
= UIO_USERSPACE
;
781 auio
.uio_rw
= UIO_READ
;
784 flags
= linux_to_bsd_msg_flags(linux_args
.flags
);
786 error
= kern_recvmsg(linux_args
.s
, linux_args
.from
? &sa
: NULL
, &auio
,
789 if (error
== 0 && linux_args
.from
) {
791 fromlen
= MIN(fromlen
, sa
->sa_len
);
792 error
= linux_copyout_sockaddr(sa
, linux_args
.from
,
797 copyout(&fromlen
, linux_args
.fromlen
,
806 struct linux_sendmsg_args
{
813 linux_sendmsg(struct linux_sendmsg_args
*args
, size_t *res
)
815 struct linux_sendmsg_args linux_args
;
816 struct thread
*td
= curthread
;
819 struct iovec aiov
[UIO_SMALLIOV
], *iov
= NULL
;
820 struct sockaddr
*sa
= NULL
;
821 struct mbuf
*control
= NULL
;
824 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
828 error
= copyin(linux_args
.msg
, &msg
, sizeof(msg
));
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.
846 error
= linux_getsockaddr(&sa
, msg
.msg_name
, msg
.msg_namelen
);
854 error
= iovec_copyin(msg
.msg_iov
, &iov
, aiov
, msg
.msg_iovlen
,
859 auio
.uio_iovcnt
= msg
.msg_iovlen
;
861 auio
.uio_segflg
= UIO_USERSPACE
;
862 auio
.uio_rw
= UIO_WRITE
;
866 * Conditionally copyin msg.msg_control.
868 if (msg
.msg_control
) {
869 if (msg
.msg_controllen
< sizeof(struct cmsghdr
) ||
870 msg
.msg_controllen
> MLEN
) {
874 control
= m_get(MB_WAIT
, MT_CONTROL
);
875 if (control
== NULL
) {
879 control
->m_len
= msg
.msg_controllen
;
880 error
= copyin(msg
.msg_control
, mtod(control
, caddr_t
),
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
==
893 mtod(control
, struct cmsghdr
*)->cmsg_type
!=
901 error
= kern_sendmsg(linux_args
.s
, sa
, &auio
, control
,
902 linux_args
.flags
, res
);
905 iovec_free(&iov
, aiov
);
912 struct linux_recvmsg_args
{
919 linux_recvmsg(struct linux_recvmsg_args
*args
, size_t *res
)
921 struct linux_recvmsg_args linux_args
;
922 struct thread
*td
= curthread
;
925 struct iovec aiov
[UIO_SMALLIOV
], *iov
= NULL
;
926 struct mbuf
*m
, *control
= NULL
;
927 struct sockaddr
*sa
= NULL
;
929 socklen_t
*ufromlenp
, *ucontrollenp
;
930 int error
, fromlen
, controllen
, len
, flags
, *uflagsp
;
932 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
936 error
= copyin(linux_args
.msg
, &msg
, sizeof(struct msghdr
));
940 if (msg
.msg_name
&& msg
.msg_namelen
< 0)
942 if (msg
.msg_control
&& msg
.msg_controllen
< 0)
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
));
955 error
= iovec_copyin(msg
.msg_iov
, &iov
, aiov
, msg
.msg_iovlen
,
960 auio
.uio_iovcnt
= msg
.msg_iovlen
;
962 auio
.uio_segflg
= UIO_USERSPACE
;
963 auio
.uio_rw
= UIO_READ
;
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
) {
976 fromlen
= MIN(msg
.msg_namelen
, sa
->sa_len
);
977 error
= linux_copyout_sockaddr(sa
, msg
.msg_name
,
982 error
= copyout(&fromlen
, 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
) {
1003 len
= msg
.msg_controllen
;
1005 ctlbuf
= (caddr_t
)msg
.msg_control
;
1007 while (m
&& len
> 0) {
1008 unsigned int tocopy
;
1010 if (len
>= m
->m_len
) {
1013 msg
.msg_flags
|= MSG_CTRUNC
;
1017 error
= copyout(mtod(m
, caddr_t
), ctlbuf
,
1026 controllen
= ctlbuf
- (caddr_t
)msg
.msg_control
;
1027 error
= copyout(&controllen
, ucontrollenp
,
1028 sizeof(*ucontrollenp
));
1032 error
= copyout(&flags
, uflagsp
, sizeof(*uflagsp
));
1037 iovec_free(&iov
, aiov
);
1043 struct linux_shutdown_args
{
1049 linux_shutdown(struct linux_shutdown_args
*args
, int *res
)
1051 struct linux_shutdown_args linux_args
;
1054 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
1058 error
= kern_shutdown(linux_args
.s
, linux_args
.how
);
1063 struct linux_setsockopt_args
{
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
;
1079 int error
, name
, level
;
1081 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
1085 level
= linux_to_bsd_sockopt_level(linux_args
.level
);
1088 name
= linux_to_bsd_so_sockopt(linux_args
.optname
);
1093 error
= copyin(linux_args
.optval
, &linux_tv
,
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
;
1105 return (kern_setsockopt(linux_args
.s
, &sopt
));
1113 name
= linux_to_bsd_ip_sockopt(linux_args
.optname
);
1116 /* Linux TCP option values match BSD's */
1117 name
= linux_args
.optname
;
1124 return (ENOPROTOOPT
);
1126 if (linux_args
.optlen
< 0 || linux_args
.optlen
> SOMAXOPT_SIZE
)
1128 if (linux_args
.optval
!= NULL
&& linux_args
.optlen
== 0)
1130 if (linux_args
.optval
== NULL
&& linux_args
.optlen
!= 0)
1133 sopt
.sopt_dir
= SOPT_SET
;
1134 sopt
.sopt_level
= level
;
1135 sopt
.sopt_name
= name
;
1136 sopt
.sopt_valsize
= linux_args
.optlen
;
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
);
1145 sopt
.sopt_val
= NULL
;
1147 error
= kern_setsockopt(linux_args
.s
, &sopt
);
1150 if (linux_args
.optval
)
1151 error
= copyout(sopt
.sopt_val
, linux_args
.optval
,
1154 if (linux_args
.optval
)
1155 kfree(sopt
.sopt_val
, M_TEMP
);
1159 struct linux_getsockopt_args
{
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
;
1177 int error
, name
, valsize
, level
;
1179 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
1183 if (linux_args
.optlen
) {
1184 error
= copyin(linux_args
.optlen
, &valsize
, sizeof(valsize
));
1191 if (valsize
< 0 || valsize
> SOMAXOPT_SIZE
)
1193 if (linux_args
.optval
!= NULL
&& valsize
== 0)
1195 if (linux_args
.optval
== NULL
&& valsize
!= 0)
1198 level
= linux_to_bsd_sockopt_level(linux_args
.level
);
1201 name
= linux_to_bsd_so_sockopt(linux_args
.optname
);
1206 sopt
.sopt_dir
= SOPT_GET
;
1207 sopt
.sopt_level
= level
;
1208 sopt
.sopt_name
= name
;
1209 sopt
.sopt_valsize
= sizeof(tv
);
1211 sopt
.sopt_val
= &tv
;
1212 error
= kern_getsockopt(linux_args
.s
, &sopt
);
1215 linux_tv
.tv_sec
= tv
.tv_sec
;
1216 linux_tv
.tv_usec
= tv
.tv_usec
;
1217 return (copyout(&linux_tv
, linux_args
.optval
,
1221 case LOCAL_PEERCRED
:
1222 if (valsize
!= sizeof(lxu
))
1224 sopt
.sopt_dir
= SOPT_GET
;
1225 sopt
.sopt_level
= level
;
1226 sopt
.sopt_name
= name
;
1227 sopt
.sopt_valsize
= sizeof(xu
);
1229 sopt
.sopt_val
= &xu
;
1230 error
= kern_getsockopt(linux_args
.s
, &sopt
);
1234 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1237 lxu
.uid
= xu
.cr_uid
;
1238 lxu
.gid
= xu
.cr_gid
;
1239 return (copyout(&lxu
, linux_args
.optval
, sizeof(lxu
)));
1247 name
= linux_to_bsd_ip_sockopt(linux_args
.optname
);
1250 /* Linux TCP option values match BSD's */
1251 name
= linux_args
.optname
;
1258 return (EOPNOTSUPP
);
1262 sopt
.sopt_dir
= SOPT_GET
;
1263 sopt
.sopt_level
= level
;
1264 sopt
.sopt_name
= name
;
1265 sopt
.sopt_valsize
= valsize
;
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
);
1274 sopt
.sopt_val
= NULL
;
1276 error
= kern_getsockopt(linux_args
.s
, &sopt
);
1278 if (error
== EINVAL
)
1279 error
= ENOPROTOOPT
;
1282 valsize
= sopt
.sopt_valsize
;
1283 error
= copyout(&valsize
, linux_args
.optlen
, sizeof(valsize
));
1286 if (linux_args
.optval
)
1287 error
= copyout(sopt
.sopt_val
, linux_args
.optval
, sopt
.sopt_valsize
);
1289 if (linux_args
.optval
)
1290 kfree(sopt
.sopt_val
, M_TEMP
);
1298 sys_linux_socketcall(struct linux_socketcall_args
*args
)
1300 void *arg
= (void *)args
->args
;
1305 switch (args
->what
) {
1307 error
= linux_socket(arg
, &args
->sysmsg_result
);
1310 error
= linux_bind(arg
, &args
->sysmsg_result
);
1313 error
= linux_connect(arg
, &args
->sysmsg_result
);
1316 error
= linux_listen(arg
, &args
->sysmsg_result
);
1319 error
= linux_accept(arg
, &args
->sysmsg_result
);
1321 case LINUX_GETSOCKNAME
:
1322 error
= linux_getsockname(arg
, &args
->sysmsg_result
);
1324 case LINUX_GETPEERNAME
:
1325 error
= linux_getpeername(arg
, &args
->sysmsg_result
);
1327 case LINUX_SOCKETPAIR
:
1328 error
= linux_socketpair(arg
, &args
->sysmsg_result
);
1331 error
= linux_send(arg
, &args
->sysmsg_szresult
);
1334 error
= linux_recv(arg
, &args
->sysmsg_szresult
);
1337 error
= linux_sendto(arg
, &args
->sysmsg_szresult
);
1339 case LINUX_RECVFROM
:
1340 error
= linux_recvfrom(arg
, &args
->sysmsg_szresult
);
1342 case LINUX_SHUTDOWN
:
1343 error
= linux_shutdown(arg
, &args
->sysmsg_result
);
1345 case LINUX_SETSOCKOPT
:
1346 error
= linux_setsockopt(arg
, &args
->sysmsg_result
);
1348 case LINUX_GETSOCKOPT
:
1349 error
= linux_getsockopt(arg
, &args
->sysmsg_result
);
1352 error
= linux_sendmsg(arg
, &args
->sysmsg_szresult
);
1355 error
= linux_recvmsg(arg
, &args
->sysmsg_szresult
);
1358 uprintf("LINUX: 'socket' typ=%d not implemented\n",