Subject: Re: handling flags in linux compat recvfrom and recvmsg
To: None <thorpej@zembu.com>
From: Assar Westerlund <assar@netbsd.org>
List: tech-kern
Date: 12/20/2000 05:14:17
--=-=-=

Jason R Thorpe <thorpej@zembu.com> writes:
> On Tue, Dec 19, 2000 at 12:58:29PM +0100, Frank van der Linden wrote:
> 
>  > On Tue, Dec 19, 2000 at 09:05:07AM +0100, assar@netbsd.org wrote:
>  > > Comments?
>  > 
>  > Looks ok to me.
> 
> Shouldn't we return an error for the flags that are not supported?

Yeah, new patch that does that included below (plus adding sendmsg
which I forgot in the last one).  Shouldn't we also check the `flags'
value in the native system calls?  That's done in the second patch
below.

/assar


--=-=-=
Content-Disposition: attachment; filename=nld
Content-Description: patch to add conversion of MSG_* to linux emulation

Index: sys/compat/linux/common/linux_socket.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_socket.c,v
retrieving revision 1.25
diff -u -w -r1.25 linux_socket.c
--- sys/compat/linux/common/linux_socket.c	2000/12/18 14:46:36	1.25
+++ sys/compat/linux/common/linux_socket.c	2000/12/20 04:12:44
@@ -94,6 +94,7 @@
 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_to_bsd_msg_flags __P((int));
 int linux_getifhwaddr __P((struct proc *, register_t *, u_int, void *));
 
 /*
@@ -132,7 +133,40 @@
 	}
 }
 
+/*
+ * convert sendto/recvfrom/sendmsg/recvmsg flags, returning -1 if any
+ * non-supported ones are set
+ */
 int
+linux_to_bsd_msg_flags(flags)
+	int flags;
+{
+	int ret_flags = 0;
+
+	if (flags & LINUX_MSG_OOB)
+		ret_flags |= MSG_OOB;
+	if (flags & LINUX_MSG_PEEK)
+		ret_flags |= MSG_PEEK;
+	if (flags & LINUX_MSG_DONTROUTE)
+		ret_flags |= MSG_DONTROUTE;
+	if (flags & LINUX_MSG_CTRUNC)
+		ret_flags |= MSG_CTRUNC;
+	if (flags & LINUX_MSG_TRUNC)
+		ret_flags |= MSG_TRUNC;
+	if (flags & LINUX_MSG_DONTWAIT)
+		ret_flags |= MSG_DONTWAIT;
+	if (flags & LINUX_MSG_EOR)
+		ret_flags |= MSG_EOR;
+	if (flags & LINUX_MSG_WAITALL)
+		ret_flags |= MSG_WAITALL;
+	if (flags & ~(LINUX_MSG_OOB|LINUX_MSG_PEEK|LINUX_MSG_DONTROUTE|
+		      LINUX_MSG_CTRUNC|LINUX_MSG_TRUNC|LINUX_MSG_DONTWAIT|
+		      LINUX_MSG_EOR|LINUX_MSG_WAITALL))
+		return -1;
+	return ret_flags;
+}
+
+int
 linux_sys_socket(p, v, retval)
 	struct proc *p;
 	void *v;
@@ -196,7 +230,9 @@
 	SCARG(&bsa, s) = SCARG(uap, s);
 	SCARG(&bsa, buf) = SCARG(uap, msg);
 	SCARG(&bsa, len) = SCARG(uap, len);
-	SCARG(&bsa, flags) = SCARG(uap, flags);
+	SCARG(&bsa, flags) = linux_to_bsd_msg_flags(SCARG(uap, flags));
+	if (SCARG(&bsa, flags) == -1)
+		return EINVAL;
 	SCARG(&bsa, to) = (void *) SCARG(uap, to);
 	SCARG(&bsa, tolen) = SCARG(uap, tolen);
 
@@ -222,11 +258,57 @@
 	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, flags) = linux_to_bsd_msg_flags(SCARG(uap, flags));
+	if (SCARG(&bra, flags) == -1)
+		return EINVAL;
 	SCARG(&bra, from) = (caddr_t) SCARG(uap, from);
 	SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen);
 
 	return compat_43_sys_recvfrom(p, &bra, retval);
+}
+
+int
+linux_sys_recvmsg(p, v, retval)
+	struct proc *p;
+	void *v;
+	register_t *retval;
+{
+	struct linux_sys_recvmsg_args /* {
+		syscallarg(int) s;
+		syscallarg(struct msghdr *) msg;
+		syscallarg(u_int) flags;
+	} */ *uap = v;
+	struct sys_recvmsg_args bra;
+
+	SCARG(&bra, s) = SCARG(uap, s);
+	SCARG(&bra, msg) = SCARG(uap, msg);
+	SCARG(&bra, flags) = linux_to_bsd_msg_flags(SCARG(uap, flags));
+	if (SCARG(&bra, flags) == -1)
+		return EINVAL;
+
+	return sys_recvmsg(p, &bra, 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 sys_sendmsg_args bsa;
+
+	SCARG(&bsa, s) = SCARG(uap, s);
+	SCARG(&bsa, msg) = SCARG(uap, msg);
+	SCARG(&bsa, flags) = linux_to_bsd_msg_flags(SCARG(uap, flags));
+	if (SCARG(&bsa, flags) == -1)
+		return EINVAL;
+
+	return sys_sendmsg(p, &bsa, retval);
 }
 
 /*
Index: sys/compat/linux/common/linux_socket.h
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_socket.h,v
retrieving revision 1.7
diff -u -w -r1.7 linux_socket.h
--- sys/compat/linux/common/linux_socket.h	1998/12/15 19:31:40	1.7
+++ sys/compat/linux/common/linux_socket.h	2000/12/20 04:12:45
@@ -123,6 +123,26 @@
 #define	LINUX_TCP_NODELAY	1
 #define	LINUX_TCP_MAXSEG	2
 
+/*
+ * msg flags in recvfrom/recvmsg 
+ */
+
+#define LINUX_MSG_OOB		0x01
+#define LINUX_MSG_PEEK		0x02
+#define LINUX_MSG_DONTROUTE	0x04
+#define LINUX_MSG_CTRUNC	0x08
+#define LINUX_MSG_PROXY		0x10
+#define LINUX_MSG_TRUNC		0x20
+#define LINUX_MSG_DONTWAIT	0x40
+#define LINUX_MSG_EOR		0x80
+#define LINUX_MSG_WAITALL	0x100
+#define LINUX_MSG_FIN		0x200
+#define LINUX_MSG_SYN		0x400
+#define LINUX_MSG_CONFIRM	0x800
+#define LINUX_MSG_RST		0x1000
+#define LINUX_MSG_ERRQUEUE	0x2000
+#define LINUX_MSG_NOSIGNAL	0x4000
+
 #if defined(__i386__)
 #include <compat/linux/arch/i386/linux_socket.h>
 #elif defined(__m68k__)
Index: sys/compat/linux/common/linux_socketcall.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_socketcall.c,v
retrieving revision 1.19
diff -u -w -r1.19 linux_socketcall.c
--- sys/compat/linux/common/linux_socketcall.c	1999/03/25 04:26:45	1.19
+++ sys/compat/linux/common/linux_socketcall.c	2000/12/20 04:12:45
@@ -156,9 +156,9 @@
 	case LINUX_SYS_getsockopt:
 		return linux_sys_getsockopt(p, (void *)&lda, retval);
 	case LINUX_SYS_sendmsg:
-		return sys_sendmsg(p, (void *)&lda, retval);
+		return linux_sys_sendmsg(p, (void *)&lda, retval);
 	case LINUX_SYS_recvmsg:
-		return sys_recvmsg(p, (void *)&lda, retval);
+		return linux_sys_recvmsg(p, (void *)&lda, retval);
 	default:
 		return ENOSYS;
 	}
Index: sys/compat/linux/common/linux_socketcall.h
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_socketcall.h,v
retrieving revision 1.5
diff -u -w -r1.5 linux_socketcall.h
--- sys/compat/linux/common/linux_socketcall.h	1999/03/25 04:26:45	1.5
+++ sys/compat/linux/common/linux_socketcall.h	2000/12/20 04:12:45
@@ -233,6 +233,8 @@
 int linux_sys_socketpair __P((struct proc *, void *, register_t *));
 int linux_sys_sendto __P((struct proc *, void *, register_t *));
 int linux_sys_recvfrom __P((struct proc *, void *, register_t *));
+int linux_sys_recvmsg __P((struct proc *, void *, register_t *));
+int linux_sys_sendmsg __P((struct proc *, void *, register_t *));
 int linux_sys_setsockopt __P((struct proc *, void *, register_t *));
 int linux_sys_getsockopt __P((struct proc *, void *, register_t *));
 int linux_sys_connect __P((struct proc *, void *, register_t *));

--=-=-=



--=-=-=
Content-Disposition: attachment; filename=netbsd-msg-check
Content-Description: patch to test MSG_* in recv*/send*

Index: sys/sys/socket.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/socket.h,v
retrieving revision 1.59
diff -u -w -r1.59 socket.h
--- sys/sys/socket.h	2000/10/04 08:59:16	1.59
+++ sys/sys/socket.h	2000/12/20 03:49:57
@@ -392,6 +392,10 @@
 #define	MSG_BCAST	0x100		/* this message was rcvd using link-level brdcst */
 #define	MSG_MCAST	0x200		/* this message was rcvd using link-level mcast */
 
+/* all flags settable by system calls */
+#define MSG_MASK	(MSG_OOB|MSG_PEEK|MSG_DONTWAIT|MSG_EOR|MSG_TRUNC|\
+			 MSG_CTRUNC|MSG_WAITALL|MSG_DONTWAIT)
+
 /*
  * Header for ancillary data objects in msg_control buffer.
  * Used for additional information with/about a datagram
Index: sys/kern/uipc_syscalls.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/uipc_syscalls.c,v
retrieving revision 1.56
diff -u -w -r1.56 uipc_syscalls.c
--- sys/kern/uipc_syscalls.c	2000/12/10 23:16:28	1.56
+++ sys/kern/uipc_syscalls.c	2000/12/20 03:49:58
@@ -399,6 +399,11 @@
 	} */ *uap = v;
 	struct msghdr msg;
 	struct iovec aiov;
+	int flags;
+
+	flags = SCARG(uap, flags);
+	if (flags & ~MSG_MASK)
+		return (EINVAL);
 
 	msg.msg_name = (caddr_t)SCARG(uap, to);		/* XXX kills const */
 	msg.msg_namelen = SCARG(uap, tolen);
@@ -410,7 +415,7 @@
 #endif
 	aiov.iov_base = (char *)SCARG(uap, buf);	/* XXX kills const */
 	aiov.iov_len = SCARG(uap, len);
-	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
+	return (sendit(p, SCARG(uap, s), &msg, flags, retval));
 }
 
 int
@@ -427,6 +432,12 @@
 	struct msghdr msg;
 	struct iovec aiov[UIO_SMALLIOV], *iov;
 	int error;
+	int flags;
+
+	flags = SCARG(uap, flags);
+	if (flags & ~MSG_MASK)
+		return (EINVAL);
+
 
 	error = copyin(SCARG(uap, msg), (caddr_t)&msg, sizeof(msg));
 	if (error)
@@ -448,7 +459,7 @@
 #ifdef COMPAT_OLDSOCK
 	msg.msg_flags = 0;
 #endif
-	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
+	error = sendit(p, SCARG(uap, s), &msg, flags, retval);
 done:
 	if (iov != aiov)
 		free(iov, M_IOV);
@@ -594,6 +605,11 @@
 	struct msghdr msg;
 	struct iovec aiov;
 	int error;
+	int flags;
+
+	flags = SCARG(uap, flags);
+	if (flags & ~MSG_MASK)
+		return (EINVAL);
 
 	if (SCARG(uap, fromlenaddr)) {
 		error = copyin((caddr_t)SCARG(uap, fromlenaddr),
@@ -609,7 +625,7 @@
 	aiov.iov_base = SCARG(uap, buf);
 	aiov.iov_len = SCARG(uap, len);
 	msg.msg_control = 0;
-	msg.msg_flags = SCARG(uap, flags);
+	msg.msg_flags = flags;
 	return (recvit(p, SCARG(uap, s), &msg,
 		       (caddr_t)SCARG(uap, fromlenaddr), retval));
 }
@@ -628,6 +644,11 @@
 	struct msghdr msg;
 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
 	int error;
+	int flags;
+
+	flags = SCARG(uap, flags);
+	if (flags & ~MSG_MASK)
+		return (EINVAL);
 
 	error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&msg,
 		       sizeof(msg));
@@ -649,9 +670,9 @@
 	uiov = msg.msg_iov;
 	msg.msg_iov = iov;
 #ifdef COMPAT_OLDSOCK
-	msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
+	msg.msg_flags = flags &~ MSG_COMPAT;
 #else
-	msg.msg_flags = SCARG(uap, flags);
+	msg.msg_flags = flags;
 #endif
 	if ((error = recvit(p, SCARG(uap, s), &msg, (caddr_t)0, retval)) == 0) {
 		msg.msg_iov = uiov;
Index: lib/libc/sys/recv.2
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/sys/recv.2,v
retrieving revision 1.16
diff -u -w -r1.16 recv.2
--- lib/libc/sys/recv.2	1999/12/02 21:42:38	1.16
+++ lib/libc/sys/recv.2	2000/12/20 03:49:58
@@ -257,7 +257,8 @@
 address space.
 .It Bq Er EINVAL
 The total length of the I/O is more than can be expressed by the ssize_t
-return value.
+return value, or unsupported bits are set in
+.Fa flags .
 .El
 .Pp
 .Fn recvmsg
Index: lib/libc/sys/send.2
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/sys/send.2,v
retrieving revision 1.15
diff -u -w -r1.15 send.2
--- lib/libc/sys/send.2	1999/12/02 21:42:39	1.15
+++ lib/libc/sys/send.2	2000/12/20 03:49:58
@@ -159,7 +159,8 @@
 The destination for the message is unreachable.
 .It Bq Er EINVAL
 The total length of the I/O is more than can be expressed by the ssize_t
-return value.
+return value, or unsupported bits are set in
+.Fa flags .
 .It Bq Er EAFNOSUPPORT
 Addresses in the specified address family cannot be used with this socket.
 .El

--=-=-=--