Module Name:    src
Committed By:   joerg
Date:           Fri Jan 13 21:02:03 UTC 2012

Modified Files:
        src/sys/compat/netbsd32: netbsd32_socket.c

Log Message:
Reduce difference between recvfrom/recvmsg for netbsd32 and the native
version. This fixes the bug of lost file descriptors when the control
space is not large enough.


To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 src/sys/compat/netbsd32/netbsd32_socket.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/compat/netbsd32/netbsd32_socket.c
diff -u src/sys/compat/netbsd32/netbsd32_socket.c:1.37 src/sys/compat/netbsd32/netbsd32_socket.c:1.38
--- src/sys/compat/netbsd32/netbsd32_socket.c:1.37	Fri Apr 23 15:19:20 2010
+++ src/sys/compat/netbsd32/netbsd32_socket.c	Fri Jan 13 21:02:03 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_socket.c,v 1.37 2010/04/23 15:19:20 rmind Exp $	*/
+/*	$NetBSD: netbsd32_socket.c,v 1.38 2012/01/13 21:02:03 joerg Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.37 2010/04/23 15:19:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.38 2012/01/13 21:02:03 joerg Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -49,12 +49,9 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_soc
 #include <compat/netbsd32/netbsd32_conv.h>
 
 /*
- * Note that the netbsd32_msghdr's iov really points to a struct iovec,
- * not a netbsd32_iovec.
+ * XXX Assumes that sockaddr is compatible.
+ * XXX Assumes that copyout_msg_control uses identical alignment.
  */
-static int recvit32(struct lwp *, int, struct netbsd32_msghdr *,
-    struct iovec *, void *, register_t *);
-
 int
 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
 {
@@ -63,147 +60,61 @@ netbsd32_recvmsg(struct lwp *l, const st
 		syscallarg(netbsd32_msghdrp_t) msg;
 		syscallarg(int) flags;
 	} */
-	struct netbsd32_msghdr msg;
+	struct netbsd32_msghdr	msg32;
 	struct iovec aiov[UIO_SMALLIOV], *iov;
-	struct netbsd32_iovec *iov32;
+	struct msghdr	msg;
+	int		error;
+	struct mbuf	*from, *control;
 	size_t iovsz;
-	int error;
 
-	error = copyin(SCARG_P32(uap, msg), &msg, sizeof(msg));
-		/* netbsd32_msghdr needs the iov pre-allocated */
+	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
 	if (error)
 		return (error);
-	iovsz = msg.msg_iovlen * sizeof(struct iovec);
-	if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
-		if ((u_int)msg.msg_iovlen > IOV_MAX)
+
+	iovsz = msg32.msg_iovlen * sizeof(struct iovec);
+	if (msg32.msg_iovlen > UIO_SMALLIOV) {
+		if (msg32.msg_iovlen > IOV_MAX)
 			return (EMSGSIZE);
 		iov = kmem_alloc(iovsz, KM_SLEEP);
 	} else 
 		iov = aiov;
-	msg.msg_flags = SCARG(uap, flags);
-	iov32 = NETBSD32PTR64(msg.msg_iov);
-	error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
+	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
+	    msg32.msg_iovlen);
 	if (error)
 		goto done;
-	if ((error = recvit32(l, SCARG(uap, s), &msg, iov, (void *)0,
-	    retval)) == 0) {
-		error = copyout(&msg, SCARG_P32(uap, msg), sizeof(msg));
-	}
-done:
-	if (iov != aiov)
-		kmem_free(iov, iovsz);
-	return (error);
-}
-
-int
-recvit32(struct lwp *l, int s, struct netbsd32_msghdr *mp, struct iovec *iov, void *namelenp, register_t *retsize)
-{
-	struct uio auio;
-	struct mbuf *from = 0, *control = 0;
-	struct socket *so;
-	struct iovec *ktriov = NULL;
-	size_t len, iovsz;
-	int i, error;
 
-	/* fd_getsock() will use the descriptor for us */
-	if ((error = fd_getsock(s, &so)) != 0)
-		return (error);
-	auio.uio_iov = iov;
-	auio.uio_iovcnt = mp->msg_iovlen;
-	auio.uio_rw = UIO_READ;
-	auio.uio_vmspace = l->l_proc->p_vmspace;
-	auio.uio_offset = 0;			/* XXX */
-	auio.uio_resid = 0;
-	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
-		/*
-		 * Reads return ssize_t because -1 is returned on error.
-		 * Therefore we must restrict the length to SSIZE_MAX to
-		 * avoid garbage return values.
-		 */
-		auio.uio_resid += iov->iov_len;
-		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
-			error = EINVAL;
-			goto out1;
-		}
-	}
+	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
+	msg.msg_name = NETBSD32PTR64(msg32.msg_name);
+	msg.msg_namelen = msg32.msg_namelen;
+	msg.msg_control = NETBSD32PTR64(msg32.msg_control);
+	msg.msg_controllen = msg32.msg_controllen;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = msg32.msg_iovlen;
 
-	iovsz = mp->msg_iovlen * sizeof(struct iovec);
-	if (ktrpoint(KTR_GENIO)) {
-		ktriov = kmem_alloc(iovsz, KM_SLEEP);
-		memcpy(ktriov, auio.uio_iov, iovsz);
-	}
+	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from,
+	    msg.msg_control != NULL ? &control : NULL, retval);
+	if (error != 0)
+		goto done;
 
-	len = auio.uio_resid;
-	error = (*so->so_receive)(so, &from, &auio, NULL,
-			  NETBSD32PTR64(mp->msg_control) ? &control : NULL,
-			  &mp->msg_flags);
-	if (error) {
-		if (auio.uio_resid != len && (error == ERESTART ||
-		    error == EINTR || error == EWOULDBLOCK))
-			error = 0;
-	}
+	if (msg.msg_control != NULL)
+		error = copyout_msg_control(l, &msg, control);
 
-	if (ktriov != NULL) {
-		ktrgeniov(s, UIO_READ, ktriov, len - auio.uio_resid, error);
-		kmem_free(ktriov, iovsz);
+	if (error == 0)
+		error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
+			from);
+	if (from != NULL)
+		m_free(from);
+	if (error == 0) {
+		ktrkuser("msghdr", &msg, sizeof msg);
+		msg32.msg_namelen = msg.msg_namelen;
+		msg32.msg_controllen = msg.msg_controllen;
+		msg32.msg_flags = msg.msg_flags;
+		error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
 	}
 
-	if (error)
-		goto out;
-	*retsize = len - auio.uio_resid;
-	if (NETBSD32PTR64(mp->msg_name)) {
-		len = mp->msg_namelen;
-		if (len <= 0 || from == 0)
-			len = 0;
-		else {
-			if (len > from->m_len)
-				len = from->m_len;
-			/* else if len < from->m_len ??? */
-			error = copyout(mtod(from, void *),
-			    (void *)NETBSD32PTR64(mp->msg_name),
-			    (unsigned)len);
-			if (error)
-				goto out;
-		}
-		mp->msg_namelen = len;
-		if (namelenp &&
-		    (error = copyout((void *)&len, namelenp, sizeof(int))))
-			goto out;
-	}
-	if (NETBSD32PTR64(mp->msg_control)) {
-		len = mp->msg_controllen;
-		if (len <= 0 || control == 0)
-			len = 0;
-		else {
-			struct mbuf *m = control;
-			void *cp = (void *)NETBSD32PTR64(mp->msg_control);
-
-			do {
-				i = m->m_len;
-				if (len < i) {
-					mp->msg_flags |= MSG_CTRUNC;
-					i = len;
-				}
-				error = copyout(mtod(m, void *), cp,
-				    (unsigned)i);
-				if (m->m_next)
-					i = ALIGN(i);
-				cp = (char *)cp + i;
-				len -= i;
-				if (error != 0 || len <= 0)
-					break;
-			} while ((m = m->m_next) != NULL);
-			len = (char *)cp - (char *)NETBSD32PTR64(mp->msg_control);
-		}
-		mp->msg_controllen = len;
-	}
- out:
-	if (from)
-		m_freem(from);
-	if (control)
-		m_freem(control);
- out1:
-	fd_putfile(s);
+ done:
+	if (iov != aiov)
+		kmem_free(iov, iovsz);
 	return (error);
 }
 
@@ -262,26 +173,28 @@ netbsd32_recvfrom(struct lwp *l, const s
 		syscallarg(netbsd32_sockaddrp_t) from;
 		syscallarg(netbsd32_intp) fromlenaddr;
 	} */
-	struct netbsd32_msghdr msg;
-	struct iovec aiov;
-	int error;
+	struct msghdr	msg;
+	struct iovec	aiov;
+	int		error;
+	struct mbuf	*from;
 
-	if (SCARG_P32(uap, fromlenaddr)) {
-		error = copyin(SCARG_P32(uap, fromlenaddr),
-		    &msg.msg_namelen, sizeof(msg.msg_namelen));
-		if (error)
-			return (error);
-	} else
-		msg.msg_namelen = 0;
-	msg.msg_name = SCARG(uap, from);
-	NETBSD32PTR32(msg.msg_iov, 0); /* ignored in recvit32(), uses iov */
+	msg.msg_name = NULL;
+	msg.msg_iov = &aiov;
 	msg.msg_iovlen = 1;
 	aiov.iov_base = SCARG_P32(uap, buf);
-	aiov.iov_len = (u_long)SCARG(uap, len);
-	NETBSD32PTR32(msg.msg_control, 0);
-	msg.msg_flags = SCARG(uap, flags);
-	return (recvit32(l, SCARG(uap, s), &msg, &aiov,
-	    SCARG_P32(uap, fromlenaddr), retval));
+	aiov.iov_len = SCARG(uap, len);
+	msg.msg_control = NULL;
+	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
+
+	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
+	if (error != 0)
+		return error;
+
+	error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr),
+	    MSG_LENUSRSPACE, from);
+	if (from != NULL)
+		m_free(from);
+	return error;
 }
 
 int

Reply via email to