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>
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()
67 linux_getsockaddr(struct sockaddr
**namp
, struct sockaddr
*uaddr
, size_t len
)
70 uint16_t family
; /* XXX: must match Linux sockaddr */
76 if (len
> SOCK_MAXADDRLEN
)
78 error
= copyin(uaddr
, &family
, sizeof(family
));
83 * Force the sa_len field to match the address family.
87 sa_len
= sizeof(struct sockaddr_in
);
90 sa_len
= sizeof(struct sockaddr_in6
);
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
99 sa_len
= offsetof(struct sockaddr
, sa_data
[0]);
105 MALLOC(sa
, struct sockaddr
*, sa_len
, M_SONAME
, M_WAITOK
);
106 error
= copyin(uaddr
, sa
, sa_len
);
111 * Convert to the 4.4BSD sockaddr structure.
113 sa
->sa_family
= *(sa_family_t
*)sa
;
122 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
123 * and copy it out to a user address.
126 linux_copyout_sockaddr(struct sockaddr
*sa
, struct sockaddr
*uaddr
, int sa_len
)
130 if (sa_len
< (int)sizeof(u_short
))
133 *(u_short
*)sa
= sa
->sa_family
;
134 error
= copyout(sa
, uaddr
, sa_len
);
140 linux_to_bsd_domain(int domain
)
144 case LINUX_AF_UNSPEC
:
154 case LINUX_AF_APPLETALK
:
155 return (AF_APPLETALK
);
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
:
230 linux_to_bsd_msg_flags(int flags
)
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
)
269 struct linux_socket_args
{
276 linux_socket(struct linux_socket_args
*args
, int *res
)
278 struct linux_socket_args linux_args
;
280 int error
, domain
, optval
;
282 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
286 domain
= linux_to_bsd_domain(linux_args
.domain
);
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. */
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
);
305 /* We ignore any error returned by setsockopt() */
306 kern_setsockopt(*res
, &sopt
);
312 struct linux_bind_args
{
314 struct sockaddr
*name
;
319 linux_bind(struct linux_bind_args
*args
, int *res
)
321 struct linux_bind_args linux_args
;
325 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
328 error
= linux_getsockaddr(&sa
, linux_args
.name
, linux_args
.namelen
);
332 error
= kern_bind(linux_args
.s
, sa
);
338 struct linux_connect_args
{
340 struct sockaddr
* name
;
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
;
357 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
360 error
= linux_getsockaddr(&sa
, linux_args
.name
, linux_args
.namelen
);
364 error
= kern_connect(linux_args
.s
, 0, sa
);
367 if (error
!= EISCONN
)
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
);
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;
389 struct linux_listen_args
{
395 linux_listen(struct linux_listen_args
*args
, int *res
)
397 struct linux_listen_args linux_args
;
400 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
404 error
= kern_listen(linux_args
.s
, linux_args
.backlog
);
409 struct linux_accept_args
{
411 struct sockaddr
*addr
;
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 };
423 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
427 if (linux_args
.addr
) {
428 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
432 error
= kern_accept(linux_args
.s
, 0, &sa
, &sa_len
, res
);
436 * Return a namelen of zero for older code which
437 * might ignore the return value from accept().
440 copyout(&sa_len
, linux_args
.namelen
,
441 sizeof(*linux_args
.namelen
));
443 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
,
446 error
= copyout(&sa_len
, linux_args
.namelen
,
447 sizeof(*linux_args
.namelen
));
453 error
= kern_accept(linux_args
.s
, 0, NULL
, 0, res
);
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
);
468 struct linux_getsockname_args
{
470 struct sockaddr
*addr
;
475 linux_getsockname(struct linux_getsockname_args
*args
, int *res
)
477 struct linux_getsockname_args linux_args
;
478 struct sockaddr
*sa
= NULL
;
482 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
485 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
489 error
= kern_getsockname(linux_args
.s
, &sa
, &sa_len
);
492 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
, sa_len
);
494 error
= copyout(&sa_len
, linux_args
.namelen
,
495 sizeof(*linux_args
.namelen
));
501 struct linux_getpeername_args
{
503 struct sockaddr
*addr
;
508 linux_getpeername(struct linux_getpeername_args
*args
, int *res
)
510 struct linux_getpeername_args linux_args
;
511 struct sockaddr
*sa
= NULL
;
514 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
517 error
= copyin(linux_args
.namelen
, &sa_len
, sizeof(sa_len
));
521 error
= kern_getpeername(linux_args
.s
, &sa
, &sa_len
);
524 error
= linux_copyout_sockaddr(sa
, linux_args
.addr
, sa_len
);
526 error
= copyout(&sa_len
, linux_args
.namelen
,
527 sizeof(*linux_args
.namelen
));
533 struct linux_socketpair_args
{
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
));
550 domain
= linux_to_bsd_domain(linux_args
.domain
);
553 error
= kern_socketpair(domain
, linux_args
.type
, linux_args
.protocol
,
557 error
= copyout(sockv
, linux_args
.rsv
, sizeof(sockv
));
561 struct linux_send_args
{
569 linux_send(struct linux_send_args
*args
, size_t *res
)
571 struct linux_send_args linux_args
;
572 struct thread
*td
= curthread
;
577 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
581 aiov
.iov_base
= linux_args
.msg
;
582 aiov
.iov_len
= linux_args
.len
;
583 auio
.uio_iov
= &aiov
;
586 auio
.uio_resid
= linux_args
.len
;
587 auio
.uio_segflg
= UIO_USERSPACE
;
588 auio
.uio_rw
= UIO_WRITE
;
591 error
= kern_sendmsg(linux_args
.s
, NULL
, &auio
, NULL
,
592 linux_args
.flags
, res
);
597 struct linux_recv_args
{
605 linux_recv(struct linux_recv_args
*args
, size_t *res
)
607 struct linux_recv_args linux_args
;
608 struct thread
*td
= curthread
;
613 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
617 aiov
.iov_base
= linux_args
.msg
;
618 aiov
.iov_len
= linux_args
.len
;
619 auio
.uio_iov
= &aiov
;
622 auio
.uio_resid
= linux_args
.len
;
623 auio
.uio_segflg
= UIO_USERSPACE
;
624 auio
.uio_rw
= UIO_READ
;
627 error
= kern_recvmsg(linux_args
.s
, NULL
, &auio
, NULL
,
628 &linux_args
.flags
, res
);
633 struct linux_sendto_args
{
643 linux_sendto(struct linux_sendto_args
*args
, size_t *res
)
645 struct linux_sendto_args linux_args
;
646 struct thread
*td
= curthread
;
650 struct sockaddr
*sa
= NULL
;
654 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
659 error
= linux_getsockaddr(&sa
, linux_args
.to
,
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
);
675 if (kern_getsockopt(linux_args
.s
, &sopt
) != 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
;
687 auio
.uio_resid
= linux_args
.len
;
688 auio
.uio_segflg
= UIO_USERSPACE
;
689 auio
.uio_rw
= UIO_WRITE
;
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
))
705 MALLOC(msg
, caddr_t
, linux_args
.len
, M_LINUX
, M_WAITOK
);
706 error
= copyin(linux_args
.msg
, msg
, linux_args
.len
);
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
);
715 aiov
.iov_len
= linux_args
.len
;
716 auio
.uio_iov
= &aiov
;
719 auio
.uio_resid
= linux_args
.len
;
720 auio
.uio_segflg
= UIO_SYSSPACE
;
721 auio
.uio_rw
= UIO_WRITE
;
725 error
= kern_sendmsg(linux_args
.s
, sa
, &auio
, NULL
,
726 linux_args
.flags
, res
);
736 struct linux_recvfrom_args
{
741 struct sockaddr
*from
;
746 linux_recvfrom(struct linux_recvfrom_args
*args
, size_t *res
)
748 struct linux_recvfrom_args linux_args
;
749 struct thread
*td
= curthread
;
752 struct sockaddr
*sa
= NULL
;
753 int error
, fromlen
, flags
;
755 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
759 if (linux_args
.from
&& linux_args
.fromlen
) {
760 error
= copyin(linux_args
.fromlen
, &fromlen
, sizeof(fromlen
));
768 aiov
.iov_base
= linux_args
.buf
;
769 aiov
.iov_len
= linux_args
.len
;
770 auio
.uio_iov
= &aiov
;
773 auio
.uio_resid
= linux_args
.len
;
774 auio
.uio_segflg
= UIO_USERSPACE
;
775 auio
.uio_rw
= UIO_READ
;
778 flags
= linux_to_bsd_msg_flags(linux_args
.flags
);
780 error
= kern_recvmsg(linux_args
.s
, linux_args
.from
? &sa
: NULL
, &auio
,
783 if (error
== 0 && linux_args
.from
) {
785 fromlen
= MIN(fromlen
, sa
->sa_len
);
786 error
= linux_copyout_sockaddr(sa
, linux_args
.from
,
791 copyout(&fromlen
, linux_args
.fromlen
,
800 struct linux_sendmsg_args
{
807 linux_sendmsg(struct linux_sendmsg_args
*args
, size_t *res
)
809 struct linux_sendmsg_args linux_args
;
810 struct thread
*td
= curthread
;
813 struct iovec aiov
[UIO_SMALLIOV
], *iov
= NULL
;
814 struct sockaddr
*sa
= NULL
;
815 struct mbuf
*control
= NULL
;
818 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
822 error
= copyin(linux_args
.msg
, &msg
, sizeof(msg
));
827 * Conditionally copyin msg.msg_name.
830 error
= linux_getsockaddr(&sa
, msg
.msg_name
, msg
.msg_namelen
);
838 error
= iovec_copyin(msg
.msg_iov
, &iov
, aiov
, msg
.msg_iovlen
,
843 auio
.uio_iovcnt
= msg
.msg_iovlen
;
845 auio
.uio_segflg
= UIO_USERSPACE
;
846 auio
.uio_rw
= UIO_WRITE
;
850 * Conditionally copyin msg.msg_control.
852 if (msg
.msg_control
) {
853 if (msg
.msg_controllen
< sizeof(struct cmsghdr
) ||
854 msg
.msg_controllen
> MLEN
) {
858 control
= m_get(MB_WAIT
, MT_CONTROL
);
859 if (control
== NULL
) {
863 control
->m_len
= msg
.msg_controllen
;
864 error
= copyin(msg
.msg_control
, mtod(control
, caddr_t
),
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
==
877 mtod(control
, struct cmsghdr
*)->cmsg_type
!=
885 error
= kern_sendmsg(linux_args
.s
, sa
, &auio
, control
,
886 linux_args
.flags
, res
);
889 iovec_free(&iov
, aiov
);
896 struct linux_recvmsg_args
{
903 linux_recvmsg(struct linux_recvmsg_args
*args
, size_t *res
)
905 struct linux_recvmsg_args linux_args
;
906 struct thread
*td
= curthread
;
909 struct iovec aiov
[UIO_SMALLIOV
], *iov
= NULL
;
910 struct mbuf
*m
, *control
= NULL
;
911 struct sockaddr
*sa
= NULL
;
913 socklen_t
*ufromlenp
, *ucontrollenp
;
914 int error
, fromlen
, controllen
, len
, flags
, *uflagsp
;
916 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
920 error
= copyin(linux_args
.msg
, &msg
, sizeof(struct msghdr
));
924 if (msg
.msg_name
&& msg
.msg_namelen
< 0)
926 if (msg
.msg_control
&& msg
.msg_controllen
< 0)
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
));
939 error
= iovec_copyin(msg
.msg_iov
, &iov
, aiov
, msg
.msg_iovlen
,
944 auio
.uio_iovcnt
= msg
.msg_iovlen
;
946 auio
.uio_segflg
= UIO_USERSPACE
;
947 auio
.uio_rw
= UIO_READ
;
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
) {
960 fromlen
= MIN(msg
.msg_namelen
, sa
->sa_len
);
961 error
= linux_copyout_sockaddr(sa
, msg
.msg_name
,
966 error
= copyout(&fromlen
, 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
) {
987 len
= msg
.msg_controllen
;
989 ctlbuf
= (caddr_t
)msg
.msg_control
;
991 while (m
&& len
> 0) {
994 if (len
>= m
->m_len
) {
997 msg
.msg_flags
|= MSG_CTRUNC
;
1001 error
= copyout(mtod(m
, caddr_t
), ctlbuf
,
1010 controllen
= ctlbuf
- (caddr_t
)msg
.msg_control
;
1011 error
= copyout(&controllen
, ucontrollenp
,
1012 sizeof(*ucontrollenp
));
1016 error
= copyout(&flags
, uflagsp
, sizeof(*uflagsp
));
1021 iovec_free(&iov
, aiov
);
1027 struct linux_shutdown_args
{
1033 linux_shutdown(struct linux_shutdown_args
*args
, int *res
)
1035 struct linux_shutdown_args linux_args
;
1038 error
= copyin(args
, &linux_args
, sizeof(linux_args
));
1042 error
= kern_shutdown(linux_args
.s
, linux_args
.how
);
1047 struct linux_setsockopt_args
{
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
));
1067 level
= linux_to_bsd_sockopt_level(linux_args
.level
);
1070 name
= linux_to_bsd_so_sockopt(linux_args
.optname
);
1073 name
= linux_to_bsd_ip_sockopt(linux_args
.optname
);
1076 /* Linux TCP option values match BSD's */
1077 name
= linux_args
.optname
;
1086 sopt
.sopt_dir
= SOPT_SET
;
1087 sopt
.sopt_level
= level
;
1088 sopt
.sopt_name
= name
;
1089 sopt
.sopt_valsize
= linux_args
.optlen
;
1092 if (sopt
.sopt_valsize
< 0 || sopt
.sopt_valsize
> SOMAXOPT_SIZE
)
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
);
1101 sopt
.sopt_val
= NULL
;
1103 error
= kern_setsockopt(linux_args
.s
, &sopt
);
1106 if (linux_args
.optval
)
1107 error
= copyout(sopt
.sopt_val
, linux_args
.optval
,
1110 if (linux_args
.optval
)
1111 kfree(sopt
.sopt_val
, M_TEMP
);
1115 struct linux_getsockopt_args
{
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
));
1135 if (linux_args
.optval
) {
1136 error
= copyin(linux_args
.optlen
, &valsize
, sizeof(valsize
));
1139 if (valsize
< 0 || valsize
> SOMAXOPT_SIZE
)
1145 level
= linux_to_bsd_sockopt_level(linux_args
.level
);
1148 name
= linux_to_bsd_so_sockopt(linux_args
.optname
);
1151 name
= linux_to_bsd_ip_sockopt(linux_args
.optname
);
1154 /* Linux TCP option values match BSD's */
1155 name
= linux_args
.optname
;
1164 sopt
.sopt_dir
= SOPT_GET
;
1165 sopt
.sopt_level
= level
;
1166 sopt
.sopt_name
= name
;
1167 sopt
.sopt_valsize
= valsize
;
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
);
1176 sopt
.sopt_val
= NULL
;
1178 error
= kern_getsockopt(linux_args
.s
, &sopt
);
1181 valsize
= sopt
.sopt_valsize
;
1182 error
= copyout(&valsize
, linux_args
.optlen
, sizeof(valsize
));
1185 if (linux_args
.optval
)
1186 error
= copyout(sopt
.sopt_val
, linux_args
.optval
, sopt
.sopt_valsize
);
1188 if (linux_args
.optval
)
1189 kfree(sopt
.sopt_val
, M_TEMP
);
1194 sys_linux_socketcall(struct linux_socketcall_args
*args
)
1196 void *arg
= (void *)args
->args
;
1198 switch (args
->what
) {
1200 return (linux_socket(arg
, &args
->sysmsg_result
));
1202 return (linux_bind(arg
, &args
->sysmsg_result
));
1204 return (linux_connect(arg
, &args
->sysmsg_result
));
1206 return (linux_listen(arg
, &args
->sysmsg_result
));
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
));
1216 return (linux_send(arg
, &args
->sysmsg_szresult
));
1218 return (linux_recv(arg
, &args
->sysmsg_szresult
));
1220 return (linux_sendto(arg
, &args
->sysmsg_szresult
));
1221 case LINUX_RECVFROM
:
1222 return (linux_recvfrom(arg
, &args
->sysmsg_szresult
));
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
));
1230 return (linux_sendmsg(arg
, &args
->sysmsg_szresult
));
1232 return (linux_recvmsg(arg
, &args
->sysmsg_szresult
));
1235 uprintf("LINUX: 'socket' typ=%d not implemented\n", args
->what
);