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.6 2003/07/30 00:19:13 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 bsd_args.sysmsg_result = 0;
239 if ((error = getsockopt(&bsd_args)))
241 /* return value not used */
243 if ((error = copyin(val, &optval, sizeof(optval))))
246 return (optval == 0);
250 * Updated sendto() when IP_HDRINCL is set:
251 * tweak endian-dependent fields in the IP packet.
254 linux_sendto_hdrincl(struct sendto_args *bsd_args)
257 * linux_ip_copysize defines how many bytes we should copy
258 * from the beginning of the IP packet before we customize it for BSD.
259 * It should include all the fields we modify (ip_len and ip_off)
260 * and be as small as possible to minimize copying overhead.
262 #define linux_ip_copysize 8
269 struct sendmsg_args /* {
275 /* Check the packet isn't too small before we mess with it */
276 if (bsd_args->len < linux_ip_copysize)
280 * Tweaking the user buffer in place would be bad manners.
281 * We create a corrected IP header with just the needed length,
282 * then use an iovec to glue it to the rest of the user packet
283 * when calling sendmsg().
285 sg = stackgap_init();
286 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
287 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
288 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
290 /* Make a copy of the beginning of the packet to be sent */
291 if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
294 /* Convert fields from Linux to BSD raw IP socket format */
295 packet->ip_len = bsd_args->len;
296 packet->ip_off = ntohs(packet->ip_off);
298 /* Prepare the msghdr and iovec structures describing the new packet */
299 msg->msg_name = bsd_args->to;
300 msg->msg_namelen = bsd_args->tolen;
303 msg->msg_control = NULL;
304 msg->msg_controllen = 0;
306 iov[0].iov_base = (char *)packet;
307 iov[0].iov_len = linux_ip_copysize;
308 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
309 iov[1].iov_len = bsd_args->len - linux_ip_copysize;
311 sendmsg_args.s = bsd_args->s;
312 sendmsg_args.msg = (caddr_t)msg;
313 sendmsg_args.flags = bsd_args->flags;
314 sendmsg_args.sysmsg_result = 0;
315 error = sendmsg(&sendmsg_args);
316 bsd_args->sysmsg_result = sendmsg_args.sysmsg_result;
320 struct linux_socket_args {
327 linux_socket(struct linux_socket_args *args, int *res)
329 struct linux_socket_args linux_args;
330 struct socket_args bsd_args;
334 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
337 bsd_args.sysmsg_result = 0;
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 /* Copy back the return value from socket() */
346 *res = bsd_args.sysmsg_result;
347 if (bsd_args.type == SOCK_RAW
348 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
349 && bsd_args.domain == AF_INET
350 && retval_socket >= 0) {
351 /* It's a raw IP socket: set the IP_HDRINCL option. */
352 struct setsockopt_args /* {
358 } */ bsd_setsockopt_args;
362 sg = stackgap_init();
363 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
365 bsd_setsockopt_args.s = bsd_args.sysmsg_result;
366 bsd_setsockopt_args.level = IPPROTO_IP;
367 bsd_setsockopt_args.name = IP_HDRINCL;
368 bsd_setsockopt_args.val = (caddr_t)hdrincl;
369 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
370 /* We ignore any error returned by setsockopt() */
371 setsockopt(&bsd_setsockopt_args);
374 return (retval_socket);
377 struct linux_bind_args {
379 struct sockaddr *name;
384 linux_bind(struct linux_bind_args *args, int *res)
386 struct linux_bind_args linux_args;
387 struct bind_args /* {
394 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
397 bsd_args.sysmsg_result = 0;
398 bsd_args.s = linux_args.s;
399 bsd_args.name = (caddr_t)linux_args.name;
400 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
402 error = bind(&bsd_args);
403 *res = bsd_args.sysmsg_result;
407 struct linux_connect_args {
409 struct sockaddr * name;
412 int linux_connect(struct linux_connect_args *, int *res);
413 #endif /* !__alpha__*/
416 linux_connect(struct linux_connect_args *args, int *res)
418 struct thread *td = curthread; /* XXX */
419 struct proc *p = td->td_proc;
420 struct linux_connect_args linux_args;
421 struct connect_args /* {
433 bcopy(args, &linux_args, sizeof(linux_args));
435 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
437 #endif /* __alpha__ */
439 bsd_args.sysmsg_result = 0;
440 bsd_args.s = linux_args.s;
441 bsd_args.name = (caddr_t)linux_args.name;
442 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
444 error = connect(&bsd_args);
445 *res = bsd_args.sysmsg_result;
446 if (error != EISCONN)
450 * Linux doesn't return EISCONN the first time it occurs,
451 * when on a non-blocking socket. Instead it returns the
452 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
454 error = holdsock(p->p_fd, linux_args.s, &fp);
458 if (fp->f_flag & FNONBLOCK) {
459 so = (struct socket *)fp->f_data;
460 if (so->so_emuldata == 0)
461 error = so->so_error;
462 so->so_emuldata = (void *)1;
470 struct linux_listen_args {
476 linux_listen(struct linux_listen_args *args, int *res)
478 struct linux_listen_args linux_args;
479 struct listen_args /* {
485 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
488 bsd_args.sysmsg_result = 0;
489 bsd_args.s = linux_args.s;
490 bsd_args.backlog = linux_args.backlog;
491 error = listen(&bsd_args);
492 *res = bsd_args.sysmsg_result;
496 struct linux_accept_args {
498 struct sockaddr *addr;
503 linux_accept(struct linux_accept_args *args, int *res)
505 struct linux_accept_args linux_args;
506 struct accept_args /* {
511 struct fcntl_args /* {
518 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
521 bsd_args.sysmsg_result = 0;
522 bsd_args.s = linux_args.s;
523 bsd_args.name = (caddr_t)linux_args.addr;
524 bsd_args.anamelen = linux_args.namelen;
525 error = oaccept(&bsd_args);
530 * linux appears not to copy flags from the parent socket to the
531 * accepted one, so we must clear the flags in the new descriptor.
532 * Ignore any errors, because we already have an open fd.
534 f_args.fd = *res = bsd_args.sysmsg_result;
535 f_args.cmd = F_SETFL;
537 (void)fcntl(&f_args);
541 struct linux_getsockname_args {
543 struct sockaddr *addr;
548 linux_getsockname(struct linux_getsockname_args *args, int *res)
550 struct linux_getsockname_args linux_args;
551 struct getsockname_args /* {
558 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
561 bsd_args.sysmsg_result = 0;
562 bsd_args.fdes = linux_args.s;
563 bsd_args.asa = (caddr_t) linux_args.addr;
564 bsd_args.alen = linux_args.namelen;
565 error = ogetsockname(&bsd_args);
566 *res = bsd_args.sysmsg_result;
570 struct linux_getpeername_args {
572 struct sockaddr *addr;
577 linux_getpeername(struct linux_getpeername_args *args, int *res)
579 struct linux_getpeername_args linux_args;
580 struct ogetpeername_args /* {
587 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
590 bsd_args.sysmsg_result = 0;
591 bsd_args.fdes = linux_args.s;
592 bsd_args.asa = (caddr_t) linux_args.addr;
593 bsd_args.alen = linux_args.namelen;
594 error = ogetpeername(&bsd_args);
595 *res = bsd_args.sysmsg_result;
599 struct linux_socketpair_args {
607 linux_socketpair(struct linux_socketpair_args *args, int *res)
609 struct linux_socketpair_args linux_args;
610 struct socketpair_args /* {
618 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
621 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
622 if (bsd_args.domain == -1)
625 bsd_args.sysmsg_result = 0;
626 bsd_args.type = linux_args.type;
627 bsd_args.protocol = linux_args.protocol;
628 bsd_args.rsv = linux_args.rsv;
629 error = socketpair(&bsd_args);
630 *res = bsd_args.sysmsg_result;
634 struct linux_send_args {
642 linux_send(struct linux_send_args *args, int *res)
644 struct linux_send_args linux_args;
645 struct osend_args /* {
653 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
656 bsd_args.sysmsg_result = 0;
657 bsd_args.s = linux_args.s;
658 bsd_args.buf = linux_args.msg;
659 bsd_args.len = linux_args.len;
660 bsd_args.flags = linux_args.flags;
661 error = osend(&bsd_args);
662 *res = bsd_args.sysmsg_result;
666 struct linux_recv_args {
674 linux_recv(struct linux_recv_args *args, int *res)
676 struct linux_recv_args linux_args;
677 struct orecv_args /* {
685 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
688 bsd_args.sysmsg_result = 0;
689 bsd_args.s = linux_args.s;
690 bsd_args.buf = linux_args.msg;
691 bsd_args.len = linux_args.len;
692 bsd_args.flags = linux_args.flags;
693 error = orecv(&bsd_args);
694 *res = bsd_args.sysmsg_result;
698 struct linux_sendto_args {
708 linux_sendto(struct linux_sendto_args *args, int *res)
710 struct linux_sendto_args linux_args;
711 struct sendto_args /* {
721 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
724 bsd_args.sysmsg_result = 0;
725 bsd_args.s = linux_args.s;
726 bsd_args.buf = linux_args.msg;
727 bsd_args.len = linux_args.len;
728 bsd_args.flags = linux_args.flags;
729 bsd_args.to = linux_args.to;
730 bsd_args.tolen = linux_args.tolen;
732 if (linux_check_hdrincl(linux_args.s) == 0)
733 /* IP_HDRINCL set, tweak the packet before sending */
734 return (linux_sendto_hdrincl(&bsd_args));
736 error = sendto(&bsd_args);
737 *res = bsd_args.sysmsg_result;
741 struct linux_recvfrom_args {
751 linux_recvfrom(struct linux_recvfrom_args *args, int *res)
753 struct linux_recvfrom_args linux_args;
754 struct recvfrom_args /* {
764 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
767 bsd_args.sysmsg_result = 0;
768 bsd_args.s = linux_args.s;
769 bsd_args.buf = linux_args.buf;
770 bsd_args.len = linux_args.len;
771 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
772 bsd_args.from = linux_args.from;
773 bsd_args.fromlenaddr = linux_args.fromlen;
774 error = orecvfrom(&bsd_args);
775 *res = bsd_args.sysmsg_result;
779 struct linux_recvmsg_args {
786 linux_recvmsg(struct linux_recvmsg_args *args, int *res)
788 struct linux_recvmsg_args linux_args;
789 struct recvmsg_args /* {
796 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
799 bsd_args.sysmsg_result = 0;
800 bsd_args.s = linux_args.s;
801 bsd_args.msg = linux_args.msg;
802 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
803 error = recvmsg(&bsd_args);
804 *res = bsd_args.sysmsg_result;
808 struct linux_shutdown_args {
814 linux_shutdown(struct linux_shutdown_args *args, int *res)
816 struct linux_shutdown_args linux_args;
817 struct shutdown_args /* {
823 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
826 bsd_args.sysmsg_result = 0;
827 bsd_args.s = linux_args.s;
828 bsd_args.how = linux_args.how;
829 error = shutdown(&bsd_args);
830 *res = bsd_args.sysmsg_result;
834 struct linux_setsockopt_args {
843 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
845 struct linux_setsockopt_args linux_args;
846 struct setsockopt_args /* {
855 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
858 bsd_args.sysmsg_result = 0;
859 bsd_args.s = linux_args.s;
860 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
861 switch (bsd_args.level) {
863 name = linux_to_bsd_so_sockopt(linux_args.optname);
866 name = linux_to_bsd_ip_sockopt(linux_args.optname);
869 /* Linux TCP option values match BSD's */
870 name = linux_args.optname;
879 bsd_args.name = name;
880 bsd_args.val = linux_args.optval;
881 bsd_args.valsize = linux_args.optlen;
882 error = setsockopt(&bsd_args);
883 *res = bsd_args.sysmsg_result;
887 struct linux_getsockopt_args {
896 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
898 struct linux_getsockopt_args linux_args;
899 struct getsockopt_args /* {
908 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
911 bsd_args.sysmsg_result = 0;
912 bsd_args.s = linux_args.s;
913 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
914 switch (bsd_args.level) {
916 name = linux_to_bsd_so_sockopt(linux_args.optname);
919 name = linux_to_bsd_ip_sockopt(linux_args.optname);
922 /* Linux TCP option values match BSD's */
923 name = linux_args.optname;
932 bsd_args.name = name;
933 bsd_args.val = linux_args.optval;
934 bsd_args.avalsize = linux_args.optlen;
935 error = getsockopt(&bsd_args);
936 *res = bsd_args.sysmsg_result;
941 linux_socketcall(struct linux_socketcall_args *args)
943 void *arg = (void *)args->args;
945 switch (args->what) {
947 return (linux_socket(arg, &args->sysmsg_result));
949 return (linux_bind(arg, &args->sysmsg_result));
951 return (linux_connect(arg, &args->sysmsg_result));
953 return (linux_listen(arg, &args->sysmsg_result));
955 return (linux_accept(arg, &args->sysmsg_result));
956 case LINUX_GETSOCKNAME:
957 return (linux_getsockname(arg, &args->sysmsg_result));
958 case LINUX_GETPEERNAME:
959 return (linux_getpeername(arg, &args->sysmsg_result));
960 case LINUX_SOCKETPAIR:
961 return (linux_socketpair(arg, &args->sysmsg_result));
963 return (linux_send(arg, &args->sysmsg_result));
965 return (linux_recv(arg, &args->sysmsg_result));
967 return (linux_sendto(arg, &args->sysmsg_result));
969 return (linux_recvfrom(arg, &args->sysmsg_result));
971 return (linux_shutdown(arg, &args->sysmsg_result));
972 case LINUX_SETSOCKOPT:
973 return (linux_setsockopt(arg, &args->sysmsg_result));
974 case LINUX_GETSOCKOPT:
975 return (linux_getsockopt(arg, &args->sysmsg_result));
981 struct sendmsg_args bsd_args;
983 error = copyin(arg, &bsd_args.s, sizeof(bsd_args) - offsetof(struct sendmsg_args, s));
986 error = copyin(&((struct msghdr *)bsd_args.msg)->msg_control, &control,
994 error = copyin(&((struct cmsghdr*)control)->cmsg_level,
995 &level, sizeof(int));
1001 * Linux thinks that SOL_SOCKET is 1; we know
1002 * that it's really 0xffff, of course.
1005 error = copyout(&level,
1006 &((struct cmsghdr *)control)->cmsg_level,
1012 bsd_args.sysmsg_result = 0;
1013 error = sendmsg(&bsd_args);
1014 args->sysmsg_result = bsd_args.sysmsg_result;
1018 return (linux_recvmsg(arg, &args->sysmsg_result));
1021 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1024 #endif /*!__alpha__*/