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 #include #include +#include #include +#include #include #include @@ -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 #include #include +#include #include #include #include @@ -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. + * 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_ */