add sendmmsg and recvmmsg

This commit is contained in:
christos 2017-02-03 16:57:39 +00:00
parent c16b94cc41
commit 2a4f2d0e56
4 changed files with 227 additions and 11 deletions

View File

@ -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;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_socket.h,v 1.22 2014/01/27 19:19:15 njoly Exp $ */
/* $NetBSD: linux_socket.h,v 1.23 2017/02/03 16:57:39 christos Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -140,6 +140,11 @@ struct linux_msghdr {
unsigned int msg_flags;
};
struct linux_mmsghdr {
struct linux_msghdr msg_hdr;
unsigned int msg_len;
};
/*
* Message flags (for sendmsg/recvmsg)
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_socketcall.c,v 1.46 2017/02/03 13:08:08 christos Exp $ */
/* $NetBSD: linux_socketcall.c,v 1.47 2017/02/03 16:57:39 christos Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_socketcall.c,v 1.46 2017/02/03 13:08:08 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_socketcall.c,v 1.47 2017/02/03 16:57:39 christos Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -219,6 +219,12 @@ linux_sys_socketcall(struct lwp *l, const struct linux_sys_socketcall_args *uap,
case LINUX_SYS_ACCEPT4:
error = linux_sys_accept4(l, (void *)&lda, retval);
break;
case LINUX_SYS_RECVMMSG:
error = linux_sys_recvmmsg(l, (void *)&lda, retval);
break;
case LINUX_SYS_SENDMMSG:
error = linux_sys_sendmmsg(l, (void *)&lda, retval);
break;
default:
error = ENOSYS;
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_socketcall.h,v 1.18 2017/02/03 13:08:08 christos Exp $ */
/* $NetBSD: linux_socketcall.h,v 1.19 2017/02/03 16:57:39 christos Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -95,7 +95,7 @@
#define LINUX_SYS_RECVMMSG 19
#define LINUX_SYS_SENDMMSG 20
#define LINUX_MAX_SOCKETCALL 18 /* no send/recv mmsg yet */
#define LINUX_MAX_SOCKETCALL 20
/*
@ -231,6 +231,21 @@ struct linux_sys_accept4_args {
syscallarg(int) flags;
};
struct linux_sys_recvmmsg_args {
syscallarg(int) s;
syscallarg(struct linux_mmsghdr *) msgvec;
syscallarg(unsigned int) vlen;
syscallarg(unsigned int) flags;
syscallarg(struct linux_timespec *) timeout;
};
struct linux_sys_sendmmsg_args {
syscallarg(int) s;
syscallarg(struct linux_mmsghdr *) msgvec;
syscallarg(unsigned int) vlen;
syscallarg(unsigned int) flags;
};
# ifdef _KERNEL
__BEGIN_DECLS
#define SYS_DEF(foo) int foo(struct lwp *, const struct foo##_args *, register_t *);
@ -250,6 +265,8 @@ SYS_DEF(linux_sys_recv)
SYS_DEF(linux_sys_send)
SYS_DEF(linux_sys_accept)
SYS_DEF(linux_sys_accept4)
SYS_DEF(linux_sys_recvmmsg)
SYS_DEF(linux_sys_sendmmsg)
#undef SYS_DEF
__END_DECLS
# endif /* !_KERNEL */