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.2 2003/06/17 04:28:19 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(struct proc *p, 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(p, &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 proc *p, 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(p, &sendmsg_args));
316 struct linux_socket_args {
323 linux_socket(struct proc *p, struct linux_socket_args *args)
325 struct linux_socket_args linux_args;
326 struct socket_args /* {
334 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
337 bsd_args.protocol = linux_args.protocol;
338 bsd_args.type = linux_args.type;
339 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
340 if (bsd_args.domain == -1)
343 retval_socket = socket(p, &bsd_args);
344 if (bsd_args.type == SOCK_RAW
345 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
346 && bsd_args.domain == AF_INET
347 && retval_socket >= 0) {
348 /* It's a raw IP socket: set the IP_HDRINCL option. */
349 struct setsockopt_args /* {
355 } */ bsd_setsockopt_args;
359 sg = stackgap_init();
360 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
362 bsd_setsockopt_args.s = p->p_retval[0];
363 bsd_setsockopt_args.level = IPPROTO_IP;
364 bsd_setsockopt_args.name = IP_HDRINCL;
365 bsd_setsockopt_args.val = (caddr_t)hdrincl;
366 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
367 /* We ignore any error returned by setsockopt() */
368 setsockopt(p, &bsd_setsockopt_args);
369 /* Copy back the return value from socket() */
370 p->p_retval[0] = bsd_setsockopt_args.s;
373 return (retval_socket);
376 struct linux_bind_args {
378 struct sockaddr *name;
383 linux_bind(struct proc *p, struct linux_bind_args *args)
385 struct linux_bind_args linux_args;
386 struct bind_args /* {
393 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
396 bsd_args.s = linux_args.s;
397 bsd_args.name = (caddr_t)linux_args.name;
398 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
400 return (bind(p, &bsd_args));
403 struct linux_connect_args {
405 struct sockaddr * name;
408 int linux_connect(struct proc *, struct linux_connect_args *);
409 #endif /* !__alpha__*/
412 linux_connect(struct proc *p, struct linux_connect_args *args)
414 struct linux_connect_args linux_args;
415 struct connect_args /* {
425 bcopy(args, &linux_args, sizeof(linux_args));
427 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
429 #endif /* __alpha__ */
431 bsd_args.s = linux_args.s;
432 bsd_args.name = (caddr_t)linux_args.name;
433 bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
435 error = connect(p, &bsd_args);
436 if (error != EISCONN)
440 * Linux doesn't return EISCONN the first time it occurs,
441 * when on a non-blocking socket. Instead it returns the
442 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
444 error = holdsock(p->p_fd, linux_args.s, &fp);
448 if (fp->f_flag & FNONBLOCK) {
449 so = (struct socket *)fp->f_data;
450 if (so->so_emuldata == 0)
451 error = so->so_error;
452 so->so_emuldata = (void *)1;
460 struct linux_listen_args {
466 linux_listen(struct proc *p, struct linux_listen_args *args)
468 struct linux_listen_args linux_args;
469 struct listen_args /* {
475 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
478 bsd_args.s = linux_args.s;
479 bsd_args.backlog = linux_args.backlog;
480 return (listen(p, &bsd_args));
483 struct linux_accept_args {
485 struct sockaddr *addr;
490 linux_accept(struct proc *p, struct linux_accept_args *args)
492 struct linux_accept_args linux_args;
493 struct accept_args /* {
498 struct fcntl_args /* {
505 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
508 bsd_args.s = linux_args.s;
509 bsd_args.name = (caddr_t)linux_args.addr;
510 bsd_args.anamelen = linux_args.namelen;
511 error = oaccept(p, &bsd_args);
516 * linux appears not to copy flags from the parent socket to the
517 * accepted one, so we must clear the flags in the new descriptor.
518 * Ignore any errors, because we already have an open fd.
520 f_args.fd = p->p_retval[0];
521 f_args.cmd = F_SETFL;
523 (void)fcntl(p, &f_args);
524 p->p_retval[0] = f_args.fd;
528 struct linux_getsockname_args {
530 struct sockaddr *addr;
535 linux_getsockname(struct proc *p, struct linux_getsockname_args *args)
537 struct linux_getsockname_args linux_args;
538 struct getsockname_args /* {
545 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
548 bsd_args.fdes = linux_args.s;
549 bsd_args.asa = (caddr_t) linux_args.addr;
550 bsd_args.alen = linux_args.namelen;
551 return (ogetsockname(p, &bsd_args));
554 struct linux_getpeername_args {
556 struct sockaddr *addr;
561 linux_getpeername(struct proc *p, struct linux_getpeername_args *args)
563 struct linux_getpeername_args linux_args;
564 struct ogetpeername_args /* {
571 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
574 bsd_args.fdes = linux_args.s;
575 bsd_args.asa = (caddr_t) linux_args.addr;
576 bsd_args.alen = linux_args.namelen;
577 return (ogetpeername(p, &bsd_args));
580 struct linux_socketpair_args {
588 linux_socketpair(struct proc *p, struct linux_socketpair_args *args)
590 struct linux_socketpair_args linux_args;
591 struct socketpair_args /* {
599 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
602 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
603 if (bsd_args.domain == -1)
606 bsd_args.type = linux_args.type;
607 bsd_args.protocol = linux_args.protocol;
608 bsd_args.rsv = linux_args.rsv;
609 return (socketpair(p, &bsd_args));
612 struct linux_send_args {
620 linux_send(struct proc *p, struct linux_send_args *args)
622 struct linux_send_args linux_args;
623 struct osend_args /* {
631 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
634 bsd_args.s = linux_args.s;
635 bsd_args.buf = linux_args.msg;
636 bsd_args.len = linux_args.len;
637 bsd_args.flags = linux_args.flags;
638 return (osend(p, &bsd_args));
641 struct linux_recv_args {
649 linux_recv(struct proc *p, struct linux_recv_args *args)
651 struct linux_recv_args linux_args;
652 struct orecv_args /* {
660 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
663 bsd_args.s = linux_args.s;
664 bsd_args.buf = linux_args.msg;
665 bsd_args.len = linux_args.len;
666 bsd_args.flags = linux_args.flags;
667 return (orecv(p, &bsd_args));
670 struct linux_sendto_args {
680 linux_sendto(struct proc *p, struct linux_sendto_args *args)
682 struct linux_sendto_args linux_args;
683 struct sendto_args /* {
693 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
696 bsd_args.s = linux_args.s;
697 bsd_args.buf = linux_args.msg;
698 bsd_args.len = linux_args.len;
699 bsd_args.flags = linux_args.flags;
700 bsd_args.to = linux_args.to;
701 bsd_args.tolen = linux_args.tolen;
703 if (linux_check_hdrincl(p, linux_args.s) == 0)
704 /* IP_HDRINCL set, tweak the packet before sending */
705 return (linux_sendto_hdrincl(p, &bsd_args));
707 return (sendto(p, &bsd_args));
710 struct linux_recvfrom_args {
720 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args)
722 struct linux_recvfrom_args linux_args;
723 struct recvfrom_args /* {
733 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
736 bsd_args.s = linux_args.s;
737 bsd_args.buf = linux_args.buf;
738 bsd_args.len = linux_args.len;
739 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
740 bsd_args.from = linux_args.from;
741 bsd_args.fromlenaddr = linux_args.fromlen;
742 return (orecvfrom(p, &bsd_args));
745 struct linux_recvmsg_args {
752 linux_recvmsg(struct proc *p, struct linux_recvmsg_args *args)
754 struct linux_recvmsg_args linux_args;
755 struct recvmsg_args /* {
762 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
765 bsd_args.s = linux_args.s;
766 bsd_args.msg = linux_args.msg;
767 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
768 return (recvmsg(p, &bsd_args));
771 struct linux_shutdown_args {
777 linux_shutdown(struct proc *p, struct linux_shutdown_args *args)
779 struct linux_shutdown_args linux_args;
780 struct shutdown_args /* {
786 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
789 bsd_args.s = linux_args.s;
790 bsd_args.how = linux_args.how;
791 return (shutdown(p, &bsd_args));
794 struct linux_setsockopt_args {
803 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args)
805 struct linux_setsockopt_args linux_args;
806 struct setsockopt_args /* {
815 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
818 bsd_args.s = linux_args.s;
819 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
820 switch (bsd_args.level) {
822 name = linux_to_bsd_so_sockopt(linux_args.optname);
825 name = linux_to_bsd_ip_sockopt(linux_args.optname);
828 /* Linux TCP option values match BSD's */
829 name = linux_args.optname;
838 bsd_args.name = name;
839 bsd_args.val = linux_args.optval;
840 bsd_args.valsize = linux_args.optlen;
841 return (setsockopt(p, &bsd_args));
844 struct linux_getsockopt_args {
853 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args)
855 struct linux_getsockopt_args linux_args;
856 struct getsockopt_args /* {
865 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
868 bsd_args.s = linux_args.s;
869 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
870 switch (bsd_args.level) {
872 name = linux_to_bsd_so_sockopt(linux_args.optname);
875 name = linux_to_bsd_ip_sockopt(linux_args.optname);
878 /* Linux TCP option values match BSD's */
879 name = linux_args.optname;
888 bsd_args.name = name;
889 bsd_args.val = linux_args.optval;
890 bsd_args.avalsize = linux_args.optlen;
891 return (getsockopt(p, &bsd_args));
895 linux_socketcall(struct proc *p, struct linux_socketcall_args *args)
897 void *arg = (void *)args->args;
899 switch (args->what) {
901 return (linux_socket(p, arg));
903 return (linux_bind(p, arg));
905 return (linux_connect(p, arg));
907 return (linux_listen(p, arg));
909 return (linux_accept(p, arg));
910 case LINUX_GETSOCKNAME:
911 return (linux_getsockname(p, arg));
912 case LINUX_GETPEERNAME:
913 return (linux_getpeername(p, arg));
914 case LINUX_SOCKETPAIR:
915 return (linux_socketpair(p, arg));
917 return (linux_send(p, arg));
919 return (linux_recv(p, arg));
921 return (linux_sendto(p, arg));
923 return (linux_recvfrom(p, arg));
925 return (linux_shutdown(p, arg));
926 case LINUX_SETSOCKOPT:
927 return (linux_setsockopt(p, arg));
928 case LINUX_GETSOCKOPT:
929 return (linux_getsockopt(p, arg));
937 const struct msghdr *msg;
941 error = copyin(&uap->msg->msg_control, &control,
949 error = copyin(&((struct cmsghdr*)control)->cmsg_level,
950 &level, sizeof(int));
956 * Linux thinks that SOL_SOCKET is 1; we know
957 * that it's really 0xffff, of course.
960 error = copyout(&level,
961 &((struct cmsghdr *)control)->cmsg_level,
967 return (sendmsg(p, arg));
970 return (linux_recvmsg(p, arg));
973 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
976 #endif /*!__alpha__*/