diff options
| author | christos <christos@NetBSD.org> | 2017-02-03 16:57:39 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2017-02-03 16:57:39 +0000 |
| commit | eab9789e2e6f17f4c6c8c5f6216486ebe18148b3 (patch) | |
| tree | 0024662d4cdf014485ff00f73129a9240ff0ce40 /sys/compat/linux/common/linux_socket.c | |
| parent | 0e109bbbff24f787abe7e278e151c3ef78c7620e (diff) | |
add sendmmsg and recvmmsg
Diffstat (limited to 'sys/compat/linux/common/linux_socket.c')
| -rw-r--r-- | sys/compat/linux/common/linux_socket.c | 200 |
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), <s, 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; +} |
