summaryrefslogtreecommitdiff
path: root/sys/compat/linux/common/linux_socket.c
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2017-02-03 16:57:39 +0000
committerchristos <christos@NetBSD.org>2017-02-03 16:57:39 +0000
commiteab9789e2e6f17f4c6c8c5f6216486ebe18148b3 (patch)
tree0024662d4cdf014485ff00f73129a9240ff0ce40 /sys/compat/linux/common/linux_socket.c
parent0e109bbbff24f787abe7e278e151c3ef78c7620e (diff)
add sendmmsg and recvmmsg
Diffstat (limited to 'sys/compat/linux/common/linux_socket.c')
-rw-r--r--sys/compat/linux/common/linux_socket.c200
1 files changed, 194 insertions, 6 deletions
diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c
index 3a23afd6d72..4d01796de2c 100644
--- a/sys/compat/linux/common/linux_socket.c
+++ b/sys/compat/linux/common/linux_socket.c
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_socket.c,v 1.136 2017/02/03 13:08:08 christos Exp $ */
+/* $NetBSD: linux_socket.c,v 1.137 2017/02/03 16:57:39 christos Exp $ */
/*-
* Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.136 2017/02/03 13:08:08 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.137 2017/02/03 16:57:39 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.136 2017/02/03 13:08:08 christos
#include <compat/linux/common/linux_util.h>
#include <compat/linux/common/linux_signal.h>
#include <compat/linux/common/linux_ioctl.h>
+#include <compat/linux/common/linux_sched.h>
#include <compat/linux/common/linux_socket.h>
#include <compat/linux/common/linux_fcntl.h>
#if !defined(__alpha__) && !defined(__amd64__)
@@ -124,8 +125,8 @@ static int linux_get_sa(struct lwp *, int, struct sockaddr_big *,
static int linux_sa_put(struct osockaddr *osa);
static int linux_to_bsd_msg_flags(int);
static int bsd_to_linux_msg_flags(int);
-static void linux_to_bsd_msghdr(struct linux_msghdr *, struct msghdr *);
-static void bsd_to_linux_msghdr(struct msghdr *, struct linux_msghdr *);
+static void linux_to_bsd_msghdr(const struct linux_msghdr *, struct msghdr *);
+static void bsd_to_linux_msghdr(const struct msghdr *, struct linux_msghdr *);
static const int linux_to_bsd_domain_[LINUX_AF_MAX] = {
AF_UNSPEC,
@@ -433,7 +434,7 @@ linux_sys_sendto(struct lwp *l, const struct linux_sys_sendto_args *uap, registe
}
static void
-linux_to_bsd_msghdr(struct linux_msghdr *lmsg, struct msghdr *bmsg)
+linux_to_bsd_msghdr(const struct linux_msghdr *lmsg, struct msghdr *bmsg)
{
bmsg->msg_name = lmsg->msg_name;
bmsg->msg_namelen = lmsg->msg_namelen;
@@ -445,7 +446,7 @@ linux_to_bsd_msghdr(struct linux_msghdr *lmsg, struct msghdr *bmsg)
}
static void
-bsd_to_linux_msghdr(struct msghdr *bmsg, struct linux_msghdr *lmsg)
+bsd_to_linux_msghdr(const struct msghdr *bmsg, struct linux_msghdr *lmsg)
{
lmsg->msg_name = bmsg->msg_name;
lmsg->msg_namelen = bmsg->msg_namelen;
@@ -1742,3 +1743,190 @@ linux_sys_accept4(struct lwp *l, const struct linux_sys_accept4_args *uap, regis
return 0;
}
+
+int
+linux_sys_sendmmsg(struct lwp *l, const struct linux_sys_sendmmsg_args *uap,
+ register_t *retval)
+{
+ /* {
+ syscallarg(int) s;
+ syscallarg(struct linux_mmsghdr *) msgvec;
+ syscallarg(unsigned int) vlen;
+ syscallarg(unsigned int) flags;
+ } */
+ struct linux_mmsghdr lmsg;
+ struct mmsghdr bmsg;
+ struct socket *so;
+ file_t *fp;
+ struct msghdr *msg = &bmsg.msg_hdr;
+ int error, s;
+ unsigned int vlen, flags, dg;
+
+ if ((flags = linux_to_bsd_msg_flags(SCARG(uap, flags))) == -1)
+ return EINVAL;
+
+ flags = (flags & MSG_USERFLAGS) | MSG_IOVUSRSPACE;
+
+ s = SCARG(uap, s);
+ if ((error = fd_getsock1(s, &so, &fp)) != 0)
+ return error;
+
+ vlen = SCARG(uap, vlen);
+ if (vlen > 1024)
+ vlen = 1024;
+
+ for (dg = 0; dg < vlen;) {
+ error = copyin(SCARG(uap, msgvec) + dg, &lmsg, sizeof(lmsg));
+ if (error)
+ break;
+ linux_to_bsd_msghdr(&lmsg.msg_hdr, &bmsg.msg_hdr);
+
+ msg->msg_flags = flags;
+
+ error = do_sys_sendmsg_so(l, s, so, fp, msg, flags,
+ &msg, sizeof(msg), retval);
+ if (error)
+ break;
+
+ ktrkuser("msghdr", msg, sizeof *msg);
+ lmsg.msg_len = *retval;
+ error = copyout(&lmsg, SCARG(uap, msgvec) + dg, sizeof(lmsg));
+ if (error)
+ break;
+ dg++;
+
+ }
+
+ *retval = dg;
+ if (error)
+ so->so_error = error;
+
+ fd_putfile(s);
+
+ /*
+ * If we succeeded at least once, return 0, hopefully so->so_error
+ * will catch it next time.
+ */
+ if (dg)
+ return 0;
+ return error;
+}
+
+int
+linux_sys_recvmmsg(struct lwp *l, const struct linux_sys_recvmmsg_args *uap,
+ register_t *retval)
+{
+ /* {
+ syscallarg(int) s;
+ syscallarg(struct linux_mmsghdr *) msgvec;
+ syscallarg(unsigned int) vlen;
+ syscallarg(unsigned int) flags;
+ syscallarg(struct linux_timespec *) timeout;
+ } */
+ struct linux_mmsghdr lmsg;
+ struct mmsghdr bmsg;
+ struct socket *so;
+ struct msghdr *msg = &bmsg.msg_hdr;
+ int error, s;
+ struct mbuf *from, *control;
+ struct timespec ts, now;
+ struct linux_timespec lts;
+ unsigned int vlen, flags, dg;
+
+ if (SCARG(uap, timeout)) {
+ error = copyin(SCARG(uap, timeout), &lts, sizeof(lts));
+ return error;
+ ts.tv_sec = lts.tv_sec;
+ ts.tv_nsec = lts.tv_nsec;
+ getnanotime(&now);
+ timespecadd(&now, &ts, &ts);
+ }
+
+ s = SCARG(uap, s);
+ if ((error = fd_getsock(s, &so)) != 0)
+ return error;
+
+ vlen = SCARG(uap, vlen);
+ if (vlen > 1024)
+ vlen = 1024;
+
+ from = NULL;
+ flags = (SCARG(uap, flags) & MSG_USERFLAGS) | MSG_IOVUSRSPACE;
+
+ for (dg = 0; dg < vlen;) {
+ error = copyin(SCARG(uap, msgvec) + dg, &lmsg, sizeof(lmsg));
+ if (error)
+ break;
+ linux_to_bsd_msghdr(&lmsg.msg_hdr, &bmsg.msg_hdr);
+ msg->msg_flags = flags & ~MSG_WAITFORONE;
+
+ if (from != NULL) {
+ m_free(from);
+ from = NULL;
+ }
+
+ error = do_sys_recvmsg_so(l, s, so, msg, NULL, 0, &from,
+ msg->msg_control != NULL ? &control : NULL, retval);
+ if (error) {
+ if (error == EAGAIN && dg > 0)
+ error = 0;
+ break;
+ }
+
+ if (msg->msg_control != NULL)
+ error = linux_copyout_msg_control(l, msg, control);
+ if (error)
+ break;
+
+ if (from != NULL) {
+ mtod(from, struct osockaddr *)->sa_family =
+ bsd_to_linux_domain(mtod(from,
+ struct sockaddr *)->sa_family);
+ error = copyout_sockname(msg->msg_name,
+ &msg->msg_namelen, 0, from);
+ if (error)
+ break;
+ }
+
+
+ lmsg.msg_len = *retval;
+ ktrkuser("msghdr", msg, sizeof(*msg));
+ bsd_to_linux_msghdr(msg, &lmsg.msg_hdr);
+ error = copyout(&lmsg, SCARG(uap, msgvec) + dg, sizeof(lmsg));
+ if (error)
+ break;
+
+ dg++;
+ if (msg->msg_flags & MSG_OOB)
+ break;
+
+ if (SCARG(uap, timeout)) {
+ getnanotime(&now);
+ timespecsub(&now, &ts, &now);
+ if (now.tv_sec > 0)
+ break;
+ }
+
+ if (flags & MSG_WAITFORONE)
+ flags |= MSG_DONTWAIT;
+
+ }
+
+ if (from != NULL)
+ m_free(from);
+
+ *retval = dg;
+ if (error)
+ so->so_error = error;
+
+ fd_putfile(s);
+
+ /*
+ * If we succeeded at least once, return 0, hopefully so->so_error
+ * will catch it next time.
+ */
+ if (dg)
+ return 0;
+
+ return error;
+}