Index: emulation/linux/linux_socket.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/linux/linux_socket.c,v
retrieving revision 1.8
diff -u -r1.8 linux_socket.c
--- emulation/linux/linux_socket.c	15 Aug 2003 06:32:51 -0000	1.8
+++ emulation/linux/linux_socket.c	6 Sep 2003 02:56:29 -0000
@@ -44,7 +44,9 @@
 #include <sys/file.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
+#include <sys/syscall1.h>
 #include <sys/uio.h>
+#include <sys/malloc.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -56,26 +58,64 @@
 #include "linux_util.h"
 
 /*
- * FreeBSD's socket calls require the sockaddr struct length to agree
+ * Copyin a sockaddr structure provided by a Linux binary.  Linux uses
+ * the 4.3BSD sockaddr structure which has no sa_len field.  We must
+ * pass 4.4BSD sockaddr structures when we call native functions in the
+ * BSD kernel.  his function does the conversion for us.
+ *
+ * Also, our socket calls require the sockaddr structure length to agree
  * with the address family.  Linux does not, so we must force it.
+ *
+ * This function should only need to be called from linux_connect()
+ * and linux_bind().
  */
 static int
-linux_to_bsd_namelen(caddr_t name, int namelen)
+linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
 {
-	uint16_t	family;	/* XXX must match Linux sockaddr */
-
-	if (copyin(name, &family, sizeof(family)))
-		return namelen;
+	struct sockaddr *sa;
+	uint16_t family;	/* XXX: must match Linux sockaddr */
+	int error, sa_len = 0;
+
+	if (len > SOCK_MAXADDRLEN)
+		return ENAMETOOLONG;
+	error = copyin(uaddr, &family, sizeof(family));
+	if (error)
+		return (error);
 
+	/*
+	 * Force the sa_len field to match the address family.
+	 */
 	switch (family) {
-		case AF_INET:
-			return sizeof(struct sockaddr_in);
-		case AF_INET6:
-			return sizeof(struct sockaddr_in6);
+	case AF_INET:
+		sa_len = sizeof(struct sockaddr_in);
+		break;
+	case AF_INET6:
+		sa_len = sizeof(struct sockaddr_in6);
+		break;
+	default:
+		/*
+		 * This is the default behavior of the old
+		 * linux_to_bsd_namelen() function.
+		 */
+		sa_len = len;
 	}
-	return namelen;
-}
 
+	MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
+	error = copyin(uaddr, sa, sa_len);
+	if (error) {
+		FREE(sa, M_SONAME);
+	} else {
+		/*
+		 * Convert to the 4.4BSD sockaddr structure.
+		 */
+		sa->sa_family = *(sa_family_t *)sa;
+		sa->sa_len = sa_len;
+		*namp = sa;
+	}
+
+	return (error);
+}
+ 
 #ifndef __alpha__
 static int
 linux_to_bsd_domain(int domain)
@@ -384,24 +424,20 @@
 linux_bind(struct linux_bind_args *args, int *res)
 {
 	struct linux_bind_args linux_args;
-	struct bind_args /* {
-		int s;
-		caddr_t name;
-		int namelen;
-	} */ bsd_args;
+	struct sockaddr *sa;
 	int error;
 
-	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
+	error = copyin(args, &linux_args, sizeof(linux_args));
+	if (error)
+		return (error);
+	error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
+	if (error)
 		return (error);
 
-	bsd_args.sysmsg_result = 0;
-	bsd_args.s = linux_args.s;
-	bsd_args.name = (caddr_t)linux_args.name;
-	bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
-	    linux_args.namelen);
-	error = bind(&bsd_args);
-	*res = bsd_args.sysmsg_result;
-	return(error);
+	error = bind1(linux_args.s, sa);
+	FREE(sa, M_SONAME);
+
+	return (error);
 }
 
 struct linux_connect_args {
@@ -418,31 +454,23 @@
 	struct thread *td = curthread;	/* XXX */
 	struct proc *p = td->td_proc;
 	struct linux_connect_args linux_args;
-	struct connect_args /* {
-		int s;
-		caddr_t name;
-		int namelen;
-	} */ bsd_args;
+	struct sockaddr *sa;
 	struct socket *so;
 	struct file *fp;
 	int error;
 
 	KKASSERT(p);
 
-#ifdef __alpha__
-	bcopy(args, &linux_args, sizeof(linux_args));
-#else
-	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
+	error = copyin(args, &linux_args, sizeof(linux_args));
+	if (error)
+		return (error);
+	error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
+	if (error)
 		return (error);
-#endif /* __alpha__ */
 
-	bsd_args.sysmsg_result = 0;
-	bsd_args.s = linux_args.s;
-	bsd_args.name = (caddr_t)linux_args.name;
-	bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name,
-	    linux_args.namelen);
-	error = connect(&bsd_args);
-	*res = bsd_args.sysmsg_result;
+	error = connect1(linux_args.s, sa);
+	FREE(sa, M_SONAME);
+
 	if (error != EISCONN)
 		return (error);
 
@@ -503,26 +531,50 @@
 linux_accept(struct linux_accept_args *args, int *res)
 {
 	struct linux_accept_args linux_args;
-	struct accept_args /* {
-		int s;
-		caddr_t name;
-		int *anamelen;
-	} */ bsd_args;
 	struct fcntl_args /* {
 		int fd;
 		int cmd;
 		long arg;
 	} */ f_args;
-	int error;
+	struct sockaddr *sa = NULL;
+	int error, sa_len;
 
-	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
+	error = copyin(args, &linux_args, sizeof(linux_args));
+	if (error)
 		return (error);
 
-	bsd_args.sysmsg_result = 0;
-	bsd_args.s = linux_args.s;
-	bsd_args.name = (caddr_t)linux_args.addr;
-	bsd_args.anamelen = linux_args.namelen;
-	error = oaccept(&bsd_args);
+	if (linux_args.addr) {
+		error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
+		if (error)
+			return (error);
+
+		error = accept1(linux_args.s, &sa, &sa_len, res);
+
+		if (error) {
+			/*
+			 * Return a namelen of zero for older code which
+			 * might ignore the return value from accept().
+			 */
+			sa_len = 0;
+			copyout(&sa_len, linux_args.namelen,
+			    sizeof(*linux_args.namelen));
+		} else {
+			/*
+			 * Convert to the Linux sockaddr strucuture.
+			 */
+			*(u_short *)sa = sa->sa_family;
+			error = copyout(sa, linux_args.addr, sa_len);
+			if (error == 0) {
+				error = copyout(&sa_len, linux_args.namelen,
+				    sizeof(*linux_args.namelen));
+			}
+		}
+		if (sa)
+			FREE(sa, M_SONAME);
+	} else {
+		error = accept1(linux_args.s, NULL, 0, res);
+	}
+
 	if (error)
 		return (error);
 
@@ -531,7 +583,7 @@
 	 * accepted one, so we must clear the flags in the new descriptor.
 	 * Ignore any errors, because we already have an open fd.
 	 */
-	f_args.fd = *res = bsd_args.sysmsg_result;
+	f_args.fd = *res;
 	f_args.cmd = F_SETFL;
 	f_args.arg = 0;
 	(void)fcntl(&f_args);
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.11
diff -u -r1.11 uipc_syscalls.c
--- kern/uipc_syscalls.c	30 Aug 2003 18:29:23 -0000	1.11
+++ kern/uipc_syscalls.c	5 Sep 2003 08:38:29 -0000
@@ -57,6 +57,7 @@
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/signalvar.h>
+#include <sys/syscall1.h>
 #include <sys/uio.h>
 #include <sys/vnode.h>
 #include <sys/lock.h>
@@ -133,7 +134,7 @@
 	return (error);
 }
 
-static int
+int
 bind1(int s, struct sockaddr *sa)
 {
 	struct thread *td = curthread;
@@ -195,7 +196,7 @@
  * sockaddr which must be freed later with FREE().  The caller must
  * initialize *name to NULL.
  */
-static int
+int
 accept1(int s, struct sockaddr **name, int *namelen, int *res)
 {
 	struct thread *td = curthread;
@@ -409,7 +410,7 @@
 }
 #endif /* COMPAT_OLDSOCK */
 
-static int
+int
 connect1(int s, struct sockaddr *sa)
 {
 	struct thread *td = curthread;
Index: sys/syscall1.h
===================================================================
RCS file: sys/syscall1.h
diff -N sys/syscall1.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/syscall1.h	6 Sep 2003 03:27:42 -0000
@@ -0,0 +1,40 @@
+/*
+ * SYSCALL1.H	- Split syscall prototypes
+ *
+ * Copyright (c) 2003 David P. Reese, Jr. <daver@gomerbud.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly$
+ */
+
+#ifndef _SYS_SYSCALL1_H_
+#define _SYS_SYSCALL1_H_
+
+struct sockaddr;
+
+int accept1(int s, struct sockaddr **name, int *namelen, int *res);
+int bind1(int s, struct sockaddr *sa);
+int connect1(int s, struct sockaddr *sa);
+
+#endif /* !_SYS_SYSCALL1_H_ */

