Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/compat/linux/common Do address family (AF_*) number tran...



details:   https://anonhg.NetBSD.org/src/rev/4006886b5152
branches:  trunk
changeset: 512047:4006886b5152
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Wed Jul 04 10:09:24 2001 +0000

description:
Do address family (AF_*) number translation for socket system calls which
pass socket address in our or out. This makes Linux programs using IPv6
working under emulation. This addresses kern/13279 by Jun-ichiro itojun Hagino.

Change sendmsg()/recvmsg() to expect the control information
to be passed the standard way (not 4.3BSD one, imlied by compat_43 code
or MSG_COMPAT). Linux uses different (arguably broken) CMSG_ALIGN() on some
architectures unfortunately, that would need to be handled eventually.

Also provide some other trivial stubs (like linux_sys_send()) to avoid
unneeded dependance on uipc_syscalls_43.c.

diffstat:

 sys/compat/linux/common/linux_socket.c     |  534 ++++++++++++++++++++++++++--
 sys/compat/linux/common/linux_socketcall.c |   20 +-
 sys/compat/linux/common/linux_socketcall.h |   88 ++--
 3 files changed, 542 insertions(+), 100 deletions(-)

diffs (truncated from 834 to 300 lines):

diff -r b8042f1ddcb0 -r 4006886b5152 sys/compat/linux/common/linux_socket.c
--- a/sys/compat/linux/common/linux_socket.c    Wed Jul 04 05:57:39 2001 +0000
+++ b/sys/compat/linux/common/linux_socket.c    Wed Jul 04 10:09:24 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_socket.c,v 1.31 2001/06/25 19:55:02 jdolecek Exp $       */
+/*     $NetBSD: linux_socket.c,v 1.32 2001/07/04 10:09:24 jdolecek Exp $       */
 
 /*-
  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@@ -39,8 +39,17 @@
 /*
  * Functions in multiarch:
  *     linux_sys_socketcall            : linux_socketcall.c
+ *
+ * XXX Note: Linux CMSG_ALIGN() uses (sizeof(long)-1). For architectures
+ * where our CMSG_ALIGN() differs (like powerpc, sparc, sparc64), the passed
+ * control structure would need to be adjusted accordingly in sendmsg() and
+ * recvmsg().
  */
 
+#if defined(_KERNEL_OPT)
+#include "opt_inet.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
@@ -63,6 +72,8 @@
 #include <sys/vnode.h>
 #include <sys/device.h>
 #include <sys/protosw.h> 
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
 
 #include <sys/syscallargs.h>
 
@@ -84,48 +95,103 @@
  * than a normal syscall.
  */
 
-int linux_to_bsd_domain __P((int));
+static int linux_to_bsd_domain __P((int));
+static int bsd_to_linux_domain __P((int));
 int linux_to_bsd_sopt_level __P((int));
 int linux_to_bsd_so_sockopt __P((int));
 int linux_to_bsd_ip_sockopt __P((int));
 int linux_to_bsd_tcp_sockopt __P((int));
 int linux_to_bsd_udp_sockopt __P((int));
 int linux_getifhwaddr __P((struct proc *, register_t *, u_int, void *));
+static int linux_sa_get __P((caddr_t *sgp, struct sockaddr **sap,
+               struct osockaddr *osa, int osalen));
+static int linux_sa_put __P((struct osockaddr *osa));
+
+static const int linux_to_bsd_domain_[LINUX_AF_MAX] = {
+       AF_UNSPEC,
+       AF_UNIX,
+       AF_INET,
+       AF_CCITT,       /* LINUX_AF_AX25 */
+       AF_IPX,
+       AF_APPLETALK,
+       -1,             /* LINUX_AF_NETROM */
+       -1,             /* LINUX_AF_BRIDGE */
+       -1,             /* LINUX_AF_ATMPVC */
+       AF_CCITT,       /* LINUX_AF_X25 */
+       AF_INET6,
+       -1,             /* LINUX_AF_ROSE */
+       AF_DECnet,
+       -1,             /* LINUX_AF_NETBEUI */
+       -1,             /* LINUX_AF_SECURITY */
+       pseudo_AF_KEY,
+       AF_ROUTE,       /* LINUX_AF_NETLINK */
+       -1,             /* LINUX_AF_PACKET */
+       -1,             /* LINUX_AF_ASH */
+       -1,             /* LINUX_AF_ECONET */
+       -1,             /* LINUX_AF_ATMSVC */
+       AF_SNA,
+       /* rest up to LINUX_AF_MAX-1 is not allocated */
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+       
+static const int bsd_to_linux_domain_[AF_MAX] = {
+       LINUX_AF_UNSPEC,
+       LINUX_AF_UNIX,
+       LINUX_AF_INET,
+       -1,             /* AF_IMPLINK */
+       -1,             /* AF_PUP */
+       -1,             /* AF_CHAOS */
+       -1,             /* AF_NS */
+       -1,             /* AF_ISO */
+       -1,             /* AF_ECMA */
+       -1,             /* AF_DATAKIT */
+       LINUX_AF_AX25,  /* AF_CCITT */
+       LINUX_AF_SNA,
+       LINUX_AF_DECnet,
+       -1,             /* AF_DLI */
+       -1,             /* AF_LAT */
+       -1,             /* AF_HYLINK */
+       LINUX_AF_APPLETALK,
+       LINUX_AF_NETLINK,
+       -1,             /* AF_LINK */
+       -1,             /* AF_XTP */
+       -1,             /* AF_COIP */
+       -1,             /* AF_CNT */
+       -1,             /* pseudo_AF_RTIP */
+       LINUX_AF_IPX,
+       LINUX_AF_INET6,
+       -1,             /* pseudo_AF_PIP */
+       -1,             /* AF_ISDN */
+       -1,             /* AF_NATM */
+       -1,             /* AF_ARP */
+       LINUX_pseudo_AF_KEY,
+       -1,             /* pseudo_AF_HDRCMPLT */
+};
 
 /*
  * Convert between Linux and BSD socket domain values
  */
-int
+static int
 linux_to_bsd_domain(ldom)
        int ldom;
 {
+       if (ldom < 0 || ldom >= LINUX_AF_MAX)
+               return (-1);
 
-       switch (ldom) {
-       case LINUX_AF_UNSPEC:
-               return AF_UNSPEC;
-       case LINUX_AF_UNIX:
-               return AF_LOCAL;
-       case LINUX_AF_INET:
-               return AF_INET;
-       case LINUX_AF_AX25:
-               return AF_CCITT;
-       case LINUX_AF_IPX:
-               return AF_IPX;
-       case LINUX_AF_APPLETALK:
-               return AF_APPLETALK;
-       case LINUX_AF_X25:
-               return AF_CCITT;
-       case LINUX_AF_INET6:
-               return AF_INET6;
-       case LINUX_AF_DECnet:
-               return AF_DECnet;
-       case LINUX_AF_NETLINK:
-               return AF_ROUTE;
-       /* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */
-       /* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */
-       default:
-               return -1;
-       }
+       return linux_to_bsd_domain_[ldom];
+}
+
+/*
+ * Convert between BSD and Linux socket domain values
+ */
+static int
+bsd_to_linux_domain(bdom)
+       int bdom;
+{
+       if (bdom < 0 || bdom >= AF_MAX)
+               return (-1);
+
+       return bsd_to_linux_domain_[bdom];
 }
 
 int
@@ -180,26 +246,92 @@
        register_t *retval;
 {
        struct linux_sys_sendto_args /* {
-               syscallarg(int) s;
-               syscallarg(void *) msg;
-               syscallarg(int) len;
-               syscallarg(int) flags;
-               syscallarg(sockaddr *) to;
-               syscallarg(int) tolen;
+               syscallarg(int)                         s;
+               syscallarg(void *)                      msg;
+               syscallarg(int)                         len;
+               syscallarg(int)                         flags;
+               syscallarg(struct osockaddr *)          to;
+               syscallarg(int)                         tolen;
        } */ *uap = v;
        struct sys_sendto_args bsa;
 
        SCARG(&bsa, s) = SCARG(uap, s);
        SCARG(&bsa, buf) = SCARG(uap, msg);
-       SCARG(&bsa, len) = SCARG(uap, len);
+       SCARG(&bsa, len) = (size_t) SCARG(uap, len);
        SCARG(&bsa, flags) = SCARG(uap, flags);
-       SCARG(&bsa, to) = (void *) SCARG(uap, to);
+       if (SCARG(uap, to)) {
+               struct sockaddr *sa;
+               int error;
+               caddr_t sg = stackgap_init(p->p_emul);
+
+               if ((error = linux_sa_get(&sg, &sa, SCARG(uap, to),
+                   SCARG(uap, tolen))))
+                       return (error);
+
+               SCARG(&bsa, to) = sa;
+       } else
+               SCARG(&bsa, to) = NULL;
        SCARG(&bsa, tolen) = SCARG(uap, tolen);
 
-       return sys_sendto(p, &bsa, retval);
+       return (sys_sendto(p, &bsa, retval));
 }
 
 int
+linux_sys_sendmsg(p, v, retval)
+       struct proc *p;
+       void *v;
+       register_t *retval;
+{
+       struct linux_sys_sendmsg_args /* {
+               syscallarg(int) s;
+               syscallarg(struct msghdr *) msg;
+               syscallarg(u_int) flags;
+       } */ *uap = v;
+       struct msghdr   msg;
+       int             error;
+       struct sys_sendmsg_args bsa;
+       struct msghdr *nmsg = NULL;
+
+       error = copyin(SCARG(uap, msg), (caddr_t)&msg, sizeof(msg));
+       if (error)
+               return (error);
+
+       if (msg.msg_name) {
+               struct sockaddr *sa;
+               caddr_t sg = stackgap_init(p->p_emul);
+
+               nmsg = (struct msghdr *) stackgap_alloc(&sg,
+                   sizeof(struct msghdr));
+               if (!nmsg)
+                       return (ENOMEM);
+
+               error = linux_sa_get(&sg, &sa,
+                   (struct osockaddr *) msg.msg_name, msg.msg_namelen);
+               if (error)
+                       return (error);
+
+               msg.msg_name = (struct sockaddr *) sa;
+               if ((error = copyout(&msg, nmsg, sizeof(struct msghdr))))
+                       return (error);
+       }
+
+       /*
+        * XXX handle different alignment of cmsg data on architectures where
+        * the Linux alignment is different (powerpc, sparc, sparc64).
+        */
+
+       SCARG(&bsa, s) = SCARG(uap, s);
+       SCARG(&bsa, msg) = nmsg;
+       SCARG(&bsa, flags) = SCARG(uap, flags);
+
+       if ((error = sys_sendmsg(p, &bsa, retval)))
+               return (error);
+
+       return (0);
+}
+
+
+int
 linux_sys_recvfrom(p, v, retval)
        struct proc *p;
        void *v;
@@ -210,19 +342,57 @@
                syscallarg(void *) buf;
                syscallarg(int) len;
                syscallarg(int) flags;
-               syscallarg(struct sockaddr *) from;
-               syscallarg(int *) fromlen;
+               syscallarg(struct osockaddr *) from;
+               syscallarg(int *) fromlenaddr;
        } */ *uap = v;
-       struct compat_43_sys_recvfrom_args bra;
+       int             error;
+       struct sys_recvfrom_args bra;
 
        SCARG(&bra, s) = SCARG(uap, s);
        SCARG(&bra, buf) = SCARG(uap, buf);
        SCARG(&bra, len) = SCARG(uap, len);
        SCARG(&bra, flags) = SCARG(uap, flags);
-       SCARG(&bra, from) = (caddr_t) SCARG(uap, from);
-       SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen);
+       SCARG(&bra, from) = (struct sockaddr *) SCARG(uap, from);
+       SCARG(&bra, fromlenaddr) = SCARG(uap, fromlenaddr);
+
+       if ((error = sys_recvfrom(p, &bra, retval)))
+               return (error);
+
+       if (SCARG(uap, from) && (error = linux_sa_put(SCARG(uap, from))))
+               return (error);
+
+       return (0);
+}



Home | Main Index | Thread Index | Old Index