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.4 2003/06/25 03:55:44 dillon Exp $
32 /* XXX we use functions that might not exist. */
33 #include "opt_compat.h"
36 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
39 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/fcntl.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
53 #include <machine/../linux/linux.h>
54 #include <machine/../linux/linux_proto.h>
55 #include <compat/linux/linux_socket.h>
56 #include <compat/linux/linux_util.h>
59 * FreeBSD's socket calls require the sockaddr struct length to agree
60 * with the address family. Linux does not, so we must force it.
63 linux_to_bsd_namelen(caddr_t name, int namelen)
65 uint16_t family; /* XXX must match Linux sockaddr */
67 if (copyin(name, &family, sizeof(family)))
72 return sizeof(struct sockaddr_in);
74 return sizeof(struct sockaddr_in6);
81 linux_to_bsd_domain(int domain)
95 case LINUX_AF_APPLETALK:
96 return (AF_APPLETALK);
102 linux_to_bsd_sockopt_level(int level)
106 case LINUX_SOL_SOCKET:
113 linux_to_bsd_ip_sockopt(int opt)
121 case LINUX_IP_OPTIONS:
123 case LINUX_IP_MULTICAST_IF:
124 return (IP_MULTICAST_IF);
125 case LINUX_IP_MULTICAST_TTL:
126 return (IP_MULTICAST_TTL);
127 case LINUX_IP_MULTICAST_LOOP:
128 return (IP_MULTICAST_LOOP);
129 case LINUX_IP_ADD_MEMBERSHIP:
130 return (IP_ADD_MEMBERSHIP);
131 case LINUX_IP_DROP_MEMBERSHIP:
132 return (IP_DROP_MEMBERSHIP);
133 case LINUX_IP_HDRINCL:
140 linux_to_bsd_so_sockopt(int opt)
146 case LINUX_SO_REUSEADDR:
147 return (SO_REUSEADDR);
152 case LINUX_SO_DONTROUTE:
153 return (SO_DONTROUTE);
154 case LINUX_SO_BROADCAST:
155 return (SO_BROADCAST);
156 case LINUX_SO_SNDBUF:
158 case LINUX_SO_RCVBUF:
160 case LINUX_SO_KEEPALIVE:
161 return (SO_KEEPALIVE);
162 case LINUX_SO_OOBINLINE:
163 return (SO_OOBINLINE);
164 case LINUX_SO_LINGER:
171 linux_to_bsd_msg_flags(int flags)
175 if (flags & LINUX_MSG_OOB)
176 ret_flags |= MSG_OOB;
177 if (flags & LINUX_MSG_PEEK)
178 ret_flags |= MSG_PEEK;
179 if (flags & LINUX_MSG_DONTROUTE)
180 ret_flags |= MSG_DONTROUTE;
181 if (flags & LINUX_MSG_CTRUNC)
182 ret_flags |= MSG_CTRUNC;
183 if (flags & LINUX_MSG_TRUNC)
184 ret_flags |= MSG_TRUNC;
185 if (flags & LINUX_MSG_DONTWAIT)
186 ret_flags |= MSG_DONTWAIT;
187 if (flags & LINUX_MSG_EOR)
188 ret_flags |= MSG_EOR;
189 if (flags & LINUX_MSG_WAITALL)
190 ret_flags |= MSG_WAITALL;
191 #if 0 /* not handled */
192 if (flags & LINUX_MSG_PROXY)
194 if (flags & LINUX_MSG_FIN)
196 if (flags & LINUX_MSG_SYN)
198 if (flags & LINUX_MSG_CONFIRM)
200 if (flags & LINUX_MSG_RST)
202 if (flags & LINUX_MSG_ERRQUEUE)
204 if (flags & LINUX_MSG_NOSIGNAL)
210 /* Return 0 if IP_HDRINCL is set for the given socket. */
212 linux_check_hdrincl(int s)
214 struct getsockopt_args /* {
222 caddr_t sg, val, valsize;
223 int size_val = sizeof val;
226 sg = stackgap_init();
227 val = stackgap_alloc(&sg, sizeof(int));
228 valsize = stackgap_alloc(&sg, sizeof(int));
230 if ((error = copyout(&size_val, valsize, sizeof(size_val))))
234 bsd_args.level = IPPROTO_IP;
235 bsd_args.name = IP_HDRINCL;
237 bsd_args.avalsize = (int *)valsize;
238 if ((error = getsockopt(&bsd_args)))
241 if ((error = copyin(val, &optval, sizeof(optval))))
244 return (optval == 0);
248 * Updated sendto() when IP_HDRINCL is set:
249 * tweak endian-dependent fields in the IP packet.
252 linux_sendto_hdrincl(struct sendto_args *bsd_args)
255 * linux_ip_copysize defines how many bytes we should copy
256 * from the beginning of the IP packet before we customize it for BSD.
257 * It should include all the fields we modify (ip_len and ip_off)
258 * and be as small as possible to minimize copying overhead.
260 #define linux_ip_copysize 8
268 struct sendmsg_args /* {
274 /* Check the packet isn't too small before we mess with it */
275 if (bsd_args->len < linux_ip_copysize)
279 * Tweaking the user buffer in place would be bad manners.
280 * We create a corrected IP header with just the needed length,
281 * then use an iovec to glue it to the rest of the user packet
282 * when calling sendmsg().
284 sg = stackgap_init();
285 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
286 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
287 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
289 /* Make a copy of the beginning of the packet to be sent */
290 if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
293 /* Convert fields from Linux to BSD raw IP socket format */
294 packet->ip_len = bsd_args->len;
295 packet->ip_off = ntohs(packet->ip_off);
297 /* Prepare the msghdr and iovec structures describing the new packet */
298 msg->msg_name = bsd_args->to;
299 msg->msg_namelen = bsd_args->tolen;
302 msg->msg_control = NULL;
303 msg->msg_controllen = 0;
305 iov[0].iov_base = (char *)packet;
306 iov[0].iov_len = linux_ip_copysize;
307 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
308 iov[1].iov_len = bsd_args->len - linux_ip_copysize;
310 sendmsg_args.s = bsd_args->s;
311 sendmsg_args.msg = (caddr_t)msg;
312 sendmsg_args.flags = bsd_args->flags;
313 return (sendmsg(&sendmsg_args));
316 struct linux_socket_args {
323 linux_socket(struct linux_socket_args *args)
325 struct proc *p = curproc;
326 struct linux_socket_args linux_args;
327 struct socket_args /* {
335 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
338 bsd_args.protocol = linux_args.protocol;
339 bsd_args.type = linux_args.type;
340 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
341 if (bsd_args.domain == -1)
344 retval_socket = socket(&bsd_args);
345 if (bsd_args.type == SOCK_RAW
346 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
347 && bsd_args.domain == AF_INET
348 && retval_socket >= 0) {
349 /* It's a raw IP socket: set the IP_HDRINCL option. */
350 struct setsockopt_args /* {
356 } */ bsd_setsockopt_args;
360 sg = stackgap_init();
361 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
363 bsd_setsockopt_args.s = p->p_retval[0];
364 bsd_setsockopt_args.level = IPPROTO_IP;
365 bsd_setsockopt_args.name = IP_HDRINCL;
366 bsd_setsockopt_args.val = (caddr_t)hdrincl;
367 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
368 /* We ignore any error returned by setsockopt() */
369 setsockopt(&bsd_setsockopt_args);
370 /* Copy back the return value from socket() */
371 p->p_retval[0] = bsd_setsockopt_args.s;
374 return (retval_socket);
377 struct linux_bind_args {
379 struct sockaddr *name;
384 linux_bind(struct linux_bind_args *args)
386 struct linux_bind_args linux_args;
387 struct bind_args /* {
394 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
397 bsd_args.s = linux_args.s;
398 bsd_args.name = (caddr_t)linux_args.name;
399 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
401 return (bind(&bsd_args));
404 struct linux_connect_args {
406 struct sockaddr * name;
409 int linux_connect(struct linux_connect_args *);
410 #endif /* !__alpha__*/
413 linux_connect(struct linux_connect_args *args)
415 struct thread *td = curthread; /* XXX */
416 struct proc *p = td->td_proc;
417 struct linux_connect_args linux_args;
418 struct connect_args /* {
430 bcopy(args, &linux_args, sizeof(linux_args));
432 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
434 #endif /* __alpha__ */
436 bsd_args.s = linux_args.s;
437 bsd_args.name = (caddr_t)linux_args.name;
438 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
440 error = connect(&bsd_args);
441 if (error != EISCONN)
445 * Linux doesn't return EISCONN the first time it occurs,
446 * when on a non-blocking socket. Instead it returns the
447 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
449 error = holdsock(p->p_fd, linux_args.s, &fp);
453 if (fp->f_flag & FNONBLOCK) {
454 so = (struct socket *)fp->f_data;
455 if (so->so_emuldata == 0)
456 error = so->so_error;
457 so->so_emuldata = (void *)1;
465 struct linux_listen_args {
471 linux_listen(struct linux_listen_args *args)
473 struct linux_listen_args linux_args;
474 struct listen_args /* {
480 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
483 bsd_args.s = linux_args.s;
484 bsd_args.backlog = linux_args.backlog;
485 return (listen(&bsd_args));
488 struct linux_accept_args {
490 struct sockaddr *addr;
495 linux_accept(struct linux_accept_args *args)
497 struct proc *p = curproc;
498 struct linux_accept_args linux_args;
499 struct accept_args /* {
504 struct fcntl_args /* {
511 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
514 bsd_args.s = linux_args.s;
515 bsd_args.name = (caddr_t)linux_args.addr;
516 bsd_args.anamelen = linux_args.namelen;
517 error = oaccept(&bsd_args);
522 * linux appears not to copy flags from the parent socket to the
523 * accepted one, so we must clear the flags in the new descriptor.
524 * Ignore any errors, because we already have an open fd.
526 f_args.fd = p->p_retval[0];
527 f_args.cmd = F_SETFL;
529 (void)fcntl(&f_args);
530 p->p_retval[0] = f_args.fd;
534 struct linux_getsockname_args {
536 struct sockaddr *addr;
541 linux_getsockname(struct linux_getsockname_args *args)
543 struct linux_getsockname_args linux_args;
544 struct getsockname_args /* {
551 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
554 bsd_args.fdes = linux_args.s;
555 bsd_args.asa = (caddr_t) linux_args.addr;
556 bsd_args.alen = linux_args.namelen;
557 return (ogetsockname(&bsd_args));
560 struct linux_getpeername_args {
562 struct sockaddr *addr;
567 linux_getpeername(struct linux_getpeername_args *args)
569 struct linux_getpeername_args linux_args;
570 struct ogetpeername_args /* {
577 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
580 bsd_args.fdes = linux_args.s;
581 bsd_args.asa = (caddr_t) linux_args.addr;
582 bsd_args.alen = linux_args.namelen;
583 return (ogetpeername(&bsd_args));
586 struct linux_socketpair_args {
594 linux_socketpair(struct linux_socketpair_args *args)
596 struct linux_socketpair_args linux_args;
597 struct socketpair_args /* {
605 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
608 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
609 if (bsd_args.domain == -1)
612 bsd_args.type = linux_args.type;
613 bsd_args.protocol = linux_args.protocol;
614 bsd_args.rsv = linux_args.rsv;
615 return (socketpair(&bsd_args));
618 struct linux_send_args {
626 linux_send(struct linux_send_args *args)
628 struct linux_send_args linux_args;
629 struct osend_args /* {
637 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
640 bsd_args.s = linux_args.s;
641 bsd_args.buf = linux_args.msg;
642 bsd_args.len = linux_args.len;
643 bsd_args.flags = linux_args.flags;
644 return (osend(&bsd_args));
647 struct linux_recv_args {
655 linux_recv(struct linux_recv_args *args)
657 struct linux_recv_args linux_args;
658 struct orecv_args /* {
666 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
669 bsd_args.s = linux_args.s;
670 bsd_args.buf = linux_args.msg;
671 bsd_args.len = linux_args.len;
672 bsd_args.flags = linux_args.flags;
673 return (orecv(&bsd_args));
676 struct linux_sendto_args {
686 linux_sendto(struct linux_sendto_args *args)
688 struct linux_sendto_args linux_args;
689 struct sendto_args /* {
699 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
702 bsd_args.s = linux_args.s;
703 bsd_args.buf = linux_args.msg;
704 bsd_args.len = linux_args.len;
705 bsd_args.flags = linux_args.flags;
706 bsd_args.to = linux_args.to;
707 bsd_args.tolen = linux_args.tolen;
709 if (linux_check_hdrincl(linux_args.s) == 0)
710 /* IP_HDRINCL set, tweak the packet before sending */
711 return (linux_sendto_hdrincl(&bsd_args));
713 return (sendto(&bsd_args));
716 struct linux_recvfrom_args {
726 linux_recvfrom(struct linux_recvfrom_args *args)
728 struct linux_recvfrom_args linux_args;
729 struct recvfrom_args /* {
739 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
742 bsd_args.s = linux_args.s;
743 bsd_args.buf = linux_args.buf;
744 bsd_args.len = linux_args.len;
745 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
746 bsd_args.from = linux_args.from;
747 bsd_args.fromlenaddr = linux_args.fromlen;
748 return (orecvfrom(&bsd_args));
751 struct linux_recvmsg_args {
758 linux_recvmsg(struct linux_recvmsg_args *args)
760 struct linux_recvmsg_args linux_args;
761 struct recvmsg_args /* {
768 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
771 bsd_args.s = linux_args.s;
772 bsd_args.msg = linux_args.msg;
773 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
774 return (recvmsg(&bsd_args));
777 struct linux_shutdown_args {
783 linux_shutdown(struct linux_shutdown_args *args)
785 struct linux_shutdown_args linux_args;
786 struct shutdown_args /* {
792 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
795 bsd_args.s = linux_args.s;
796 bsd_args.how = linux_args.how;
797 return (shutdown(&bsd_args));
800 struct linux_setsockopt_args {
809 linux_setsockopt(struct linux_setsockopt_args *args)
811 struct linux_setsockopt_args linux_args;
812 struct setsockopt_args /* {
821 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
824 bsd_args.s = linux_args.s;
825 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
826 switch (bsd_args.level) {
828 name = linux_to_bsd_so_sockopt(linux_args.optname);
831 name = linux_to_bsd_ip_sockopt(linux_args.optname);
834 /* Linux TCP option values match BSD's */
835 name = linux_args.optname;
844 bsd_args.name = name;
845 bsd_args.val = linux_args.optval;
846 bsd_args.valsize = linux_args.optlen;
847 return (setsockopt(&bsd_args));
850 struct linux_getsockopt_args {
859 linux_getsockopt(struct linux_getsockopt_args *args)
861 struct linux_getsockopt_args linux_args;
862 struct getsockopt_args /* {
871 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
874 bsd_args.s = linux_args.s;
875 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
876 switch (bsd_args.level) {
878 name = linux_to_bsd_so_sockopt(linux_args.optname);
881 name = linux_to_bsd_ip_sockopt(linux_args.optname);
884 /* Linux TCP option values match BSD's */
885 name = linux_args.optname;
894 bsd_args.name = name;
895 bsd_args.val = linux_args.optval;
896 bsd_args.avalsize = linux_args.optlen;
897 return (getsockopt(&bsd_args));
901 linux_socketcall(struct linux_socketcall_args *args)
903 void *arg = (void *)args->args;
905 switch (args->what) {
907 return (linux_socket(arg));
909 return (linux_bind(arg));
911 return (linux_connect(arg));
913 return (linux_listen(arg));
915 return (linux_accept(arg));
916 case LINUX_GETSOCKNAME:
917 return (linux_getsockname(arg));
918 case LINUX_GETPEERNAME:
919 return (linux_getpeername(arg));
920 case LINUX_SOCKETPAIR:
921 return (linux_socketpair(arg));
923 return (linux_send(arg));
925 return (linux_recv(arg));
927 return (linux_sendto(arg));
929 return (linux_recvfrom(arg));
931 return (linux_shutdown(arg));
932 case LINUX_SETSOCKOPT:
933 return (linux_setsockopt(arg));
934 case LINUX_GETSOCKOPT:
935 return (linux_getsockopt(arg));
943 const struct msghdr *msg;
947 error = copyin(&uap->msg->msg_control, &control,
955 error = copyin(&((struct cmsghdr*)control)->cmsg_level,
956 &level, sizeof(int));
962 * Linux thinks that SOL_SOCKET is 1; we know
963 * that it's really 0xffff, of course.
966 error = copyout(&level,
967 &((struct cmsghdr *)control)->cmsg_level,
973 return (sendmsg(arg));
976 return (linux_recvmsg(arg));
979 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
982 #endif /*!__alpha__*/