From 5f1fe808bd588b02170e671c6f9f1daf16744ccf Mon Sep 17 00:00:00 2001 In-Reply-To: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> References: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> From: Stacey Son Date: Mon, 7 Oct 2013 14:00:40 -0500 Subject: [PATCH v3 13/19] bsd-user: add support for socket related system calls This change adds support or stubs for socket related system calls including accept(2), bind(2), connect(2), getpeername(2), getsockname(2), getsockopt(2), setsockopt(2), listen(2), recvfrom(2), recvmsg(2), sendmsg(2), sendto(2), socket(2), socketpair(2), shutdown(2), setfib(2), sctp_peeloff(2), sctp_generic_sendmsg(2), sctp_generic_recvmsg(2), sendfile(2), and freebsd4_sendfile(2). --- bsd-user/Makefile.objs | 4 +- bsd-user/bsd-socket.c | 108 +++++++++ bsd-user/bsd-socket.h | 266 ++++++++++++++++++++ bsd-user/freebsd/os-socket.c | 149 ++++++++++++ bsd-user/freebsd/os-socket.h | 548 ++++++++++++++++++++++++++++++++++++++++++ bsd-user/freebsd/qemu-os.h | 6 + bsd-user/netbsd/os-socket.c | 1 + bsd-user/netbsd/os-socket.h | 98 ++++++++ bsd-user/openbsd/os-socket.c | 1 + bsd-user/openbsd/os-socket.h | 98 ++++++++ bsd-user/qemu-bsd.h | 8 + bsd-user/syscall.c | 93 +++++++ 12 files changed, 1378 insertions(+), 2 deletions(-) create mode 100644 bsd-user/bsd-socket.c create mode 100644 bsd-user/bsd-socket.h create mode 100644 bsd-user/freebsd/os-socket.c create mode 100644 bsd-user/freebsd/os-socket.h create mode 100644 bsd-user/netbsd/os-socket.c create mode 100644 bsd-user/netbsd/os-socket.h create mode 100644 bsd-user/openbsd/os-socket.c create mode 100644 bsd-user/openbsd/os-socket.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index 77709cd..635d879 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,6 +1,6 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ - uaccess.o bsd-mem.o bsd-proc.o \ + uaccess.o bsd-mem.o bsd-proc.o bsd-socket.o \ $(HOST_VARIANT_DIR)/os-proc.o \ - $(HOST_VARIANT_DIR)/os-stat.o \ + $(HOST_VARIANT_DIR)/os-socket.o $(HOST_VARIANT_DIR)/os-stat.o \ $(HOST_VARIANT_DIR)/os-sys.o \ $(HOST_VARIANT_DIR)/os-time.o $(TARGET_ABI_DIR)/target_arch_cpu.o diff --git a/bsd-user/bsd-socket.c b/bsd-user/bsd-socket.c new file mode 100644 index 0000000..c1a3b49 --- /dev/null +++ b/bsd-user/bsd-socket.c @@ -0,0 +1,108 @@ +/* + * BSD socket system call related helpers + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include + +#include "qemu.h" +#include "qemu-bsd.h" + +/* + * socket conversion + */ +abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, + socklen_t len) +{ + const socklen_t unix_maxlen = sizeof(struct sockaddr_un); + sa_family_t sa_family; + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); + if (target_saddr == 0) { + return -TARGET_EFAULT; + } + + sa_family = target_saddr->sa_family; + + /* + * Oops. The caller might send a incomplete sun_path; sun_path + * must be terminated by \0 (see the manual page), but unfortunately + * it is quite common to specify sockaddr_un length as + * "strlen(x->sun_path)" while it should be "strlen(...) + 1". We will + * fix that here if needed. + */ + if (target_saddr->sa_family == AF_UNIX) { + if (len < unix_maxlen && len > 0) { + char *cp = (char *)target_saddr; + + if (cp[len-1] && !cp[len]) { + len++; + } + } + if (len > unix_maxlen) { + len = unix_maxlen; + } + } + + memcpy(addr, target_saddr, len); + addr->sa_family = sa_family; /* type uint8_t */ + addr->sa_len = target_saddr->sa_len; /* type uint8_t */ + unlock_user(target_saddr, target_addr, 0); + + return 0; +} + +abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr, + socklen_t len) +{ + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); + if (target_saddr == 0) { + return -TARGET_EFAULT; + } + memcpy(target_saddr, addr, len); + target_saddr->sa_family = addr->sa_family; /* type uint8_t */ + target_saddr->sa_len = addr->sa_len; /* type uint8_t */ + unlock_user(target_saddr, target_addr, len); + + return 0; +} + +abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr, + socklen_t len) +{ + struct target_ip_mreqn *target_smreqn; + + target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); + if (target_smreqn == 0) { + return -TARGET_EFAULT; + } + mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; + mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; + if (len == sizeof(struct target_ip_mreqn)) { + mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex); + } + unlock_user(target_smreqn, target_addr, 0); + + return 0; +} + diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h new file mode 100644 index 0000000..f5d1ac8 --- /dev/null +++ b/bsd-user/bsd-socket.h @@ -0,0 +1,266 @@ +/* + * socket related system call shims + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef __BSD_SOCKET_H_ +#define __BSD_SOCKET_H_ + +#include +#include +#include +#include + +#include "qemu-bsd.h" + +/* bind(2) */ +static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr, + socklen_t addrlen) +{ + abi_long ret; + void *addr; + + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + + addr = alloca(addrlen + 1); + ret = target_to_host_sockaddr(addr, target_addr, addrlen); + if (is_error(ret)) { + return ret; + } + + return get_errno(bind(sockfd, addr, addrlen)); +} + +/* connect(2) */ +static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr, + socklen_t addrlen) +{ + abi_long ret; + void *addr; + + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + addr = alloca(addrlen); + + ret = target_to_host_sockaddr(addr, target_addr, addrlen); + + if (is_error(ret)) { + return ret; + } + + return get_errno(connect(sockfd, addr, addrlen)); +} + +/* accept(2) */ +static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr, + abi_ulong target_addrlen_addr) +{ + socklen_t addrlen; + void *addr; + abi_long ret; + + if (target_addr == 0) { + return get_errno(accept(fd, NULL, NULL)); + } + /* return EINVAL if addrlen pointer is invalid */ + if (get_user_u32(addrlen, target_addrlen_addr)) { + return -TARGET_EINVAL; + } + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) { + return -TARGET_EINVAL; + } + addr = alloca(addrlen); + + ret = get_errno(accept(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) { + ret = -TARGET_EFAULT; + } + } + return ret; +} + +/* getpeername(2) */ +static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr, + abi_ulong target_addrlen_addr) +{ + socklen_t addrlen; + void *addr; + abi_long ret; + + if (get_user_u32(addrlen, target_addrlen_addr)) { + return -TARGET_EFAULT; + } + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) { + return -TARGET_EFAULT; + } + addr = alloca(addrlen); + ret = get_errno(getpeername(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) { + ret = -TARGET_EFAULT; + } + } + return ret; +} + +/* getsockname(2) */ +static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr, + abi_ulong target_addrlen_addr) +{ + socklen_t addrlen; + void *addr; + abi_long ret; + + if (get_user_u32(addrlen, target_addrlen_addr)) { + return -TARGET_EFAULT; + } + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) { + return -TARGET_EFAULT; + } + addr = alloca(addrlen); + + ret = get_errno(getsockname(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) { + ret = -TARGET_EFAULT; + } + } + return ret; +} + +/* socketpair(2) */ +static inline abi_long do_bsd_socketpair(int domain, int type, int protocol, + abi_ulong target_tab_addr) +{ + int tab[2]; + abi_long ret; + + ret = get_errno(socketpair(domain, type, protocol, tab)); + if (!is_error(ret)) { + if (put_user_s32(tab[0], target_tab_addr) || + put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) { + ret = -TARGET_EFAULT; + } + } + return ret; +} + +/* sendto(2) */ +static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len, + int flags, abi_ulong target_addr, socklen_t addrlen) +{ + struct sockaddr *saddr; + void *host_msg; + abi_long ret; + + if ((int)addrlen < 0) { + return -TARGET_EINVAL; + } + host_msg = lock_user(VERIFY_READ, msg, len, 1); + if (!host_msg) { + return -TARGET_EFAULT; + } + if (target_addr) { + saddr = alloca(addrlen); + ret = target_to_host_sockaddr(saddr, target_addr, addrlen); + if (is_error(ret)) { + unlock_user(host_msg, msg, 0); + return ret; + } + ret = get_errno(sendto(fd, host_msg, len, flags, saddr, addrlen)); + } else { + ret = get_errno(send(fd, host_msg, len, flags)); + } + unlock_user(host_msg, msg, 0); + return ret; +} + +/* recvfrom(2) */ +static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len, + int flags, abi_ulong target_addr, abi_ulong target_addrlen) +{ + socklen_t addrlen; + struct sockaddr *saddr; + void *host_msg; + abi_long ret; + + host_msg = lock_user(VERIFY_WRITE, msg, len, 0); + if (!host_msg) { + return -TARGET_EFAULT; + } + if (target_addr) { + if (get_user_u32(addrlen, target_addrlen)) { + ret = -TARGET_EFAULT; + goto fail; + } + if ((int)addrlen < 0) { + ret = -TARGET_EINVAL; + goto fail; + } + saddr = alloca(addrlen); + ret = get_errno(recvfrom(fd, host_msg, len, flags, saddr, &addrlen)); + } else { + saddr = NULL; /* To keep compiler quiet. */ + ret = get_errno(qemu_recv(fd, host_msg, len, flags)); + } + if (!is_error(ret)) { + if (target_addr) { + host_to_target_sockaddr(target_addr, saddr, addrlen); + if (put_user_u32(addrlen, target_addrlen)) { + ret = -TARGET_EFAULT; + goto fail; + } + } + unlock_user(host_msg, msg, len); + } else { +fail: + unlock_user(host_msg, msg, 0); + } + return ret; +} + +/* socket(2) */ +static inline abi_long do_bsd_socket(abi_long domain, abi_long type, + abi_long protocol) +{ + + return get_errno(socket(domain, type, protocol)); +} + +/* shutdown(2) */ +static inline abi_long do_bsd_shutdown(abi_long s, abi_long how) +{ + + return get_errno(shutdown(s, how)); +} + +#endif /* !__BSD_SOCKET_H_ */ diff --git a/bsd-user/freebsd/os-socket.c b/bsd-user/freebsd/os-socket.c new file mode 100644 index 0000000..949af28 --- /dev/null +++ b/bsd-user/freebsd/os-socket.c @@ -0,0 +1,149 @@ +/* + * FreeBSD socket related system call helpers + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "qemu.h" +#include "qemu-os.h" + +abi_long t2h_freebsd_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + abi_long msg_controllen; + abi_ulong target_cmsg_addr; + struct target_cmsghdr *target_cmsg; + socklen_t space = 0; + + + msg_controllen = tswapal(target_msgh->msg_controllen); + if (msg_controllen < sizeof(struct target_cmsghdr)) { + goto the_end; + } + target_cmsg_addr = tswapal(target_msgh->msg_control); + target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); + if (target_cmsg == 0) { + return -TARGET_EFAULT; + } + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + int len = tswapal(target_cmsg->cmsg_len) - + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)); + space += CMSG_SPACE(len); + if (space > msgh->msg_controllen) { + space -= CMSG_SPACE(len); + gemu_log("Host cmsg overflow\n"); + break; + } + cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); + cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); + cmsg->cmsg_len = CMSG_LEN(len); + + if (cmsg->cmsg_level != TARGET_SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", + cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(data, target_data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) { + fd[i] = tswap32(target_fd[i]); + } + } + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + unlock_user(target_cmsg, target_cmsg_addr, 0); + +the_end: + msgh->msg_controllen = space; + return 0; +} + +abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + abi_long msg_controllen; + abi_ulong target_cmsg_addr; + struct target_cmsghdr *target_cmsg; + socklen_t space = 0; + + msg_controllen = tswapal(target_msgh->msg_controllen); + if (msg_controllen < sizeof(struct target_cmsghdr)) { + goto the_end; + } + target_cmsg_addr = tswapal(target_msgh->msg_control); + target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, + msg_controllen, 0); + if (target_cmsg == 0) { + return -TARGET_EFAULT; + } + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); + + space += TARGET_CMSG_SPACE(len); + if (space > msg_controllen) { + space -= TARGET_CMSG_SPACE(len); + gemu_log("Target cmsg overflow\n"); + break; + } + target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); + target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); + target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); + if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && + (cmsg->cmsg_type == SCM_RIGHTS)) { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + for (i = 0; i < numfds; i++) { + target_fd[i] = tswap32(fd[i]); + } + } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && + (cmsg->cmsg_type == SO_TIMESTAMP) && + (len == sizeof(struct timeval))) { + /* copy struct timeval to target */ + struct timeval *tv = (struct timeval *)data; + struct target_freebsd_timeval *target_tv = + (struct target_freebsd_timeval *)target_data; + __put_user(tv->tv_sec, &target_tv->tv_sec); + __put_user(tv->tv_usec, &target_tv->tv_usec); + } else { + gemu_log("Unsupported ancillary data: %d/%d\n", + cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(target_data, data, len); + } + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + unlock_user(target_cmsg, target_cmsg_addr, space); + +the_end: + target_msgh->msg_controllen = tswapal(space); + return 0; +} + diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h new file mode 100644 index 0000000..9339ffb --- /dev/null +++ b/bsd-user/freebsd/os-socket.h @@ -0,0 +1,548 @@ +/* + * FreeBSD socket related system call shims + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef __FREEBSD_SOCKET_H_ +#define __FREEBSD_SOCKET_H_ + +#include +#include +#include +#include + +#include "qemu-os.h" + +/* sendmsg(2) */ +static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg, + int flags) +{ + abi_long ret; + struct target_msghdr *msgp; + struct msghdr msg; + int count; + struct iovec *vec; + abi_ulong target_vec; + + if (!lock_user_struct(VERIFY_READ, msgp, target_msg, 1)) { + return -TARGET_EFAULT; + } + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + ret = target_to_host_sockaddr(msg.msg_name, + tswapal(msgp->msg_name), msg.msg_namelen); + + if (is_error(ret)) { + unlock_user_struct(msgp, target_msg, 0); + return ret; + } + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + msg.msg_controllen = 2 * tswapal(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); + msg.msg_flags = tswap32(msgp->msg_flags); + + count = tswapal(msgp->msg_iovlen); + vec = alloca(count * sizeof(struct iovec)); + target_vec = tswapal(msgp->msg_iov); + lock_iovec(VERIFY_READ, vec, target_vec, count, 1); + msg.msg_iovlen = count; + msg.msg_iov = vec; + + ret = t2h_freebsd_cmsg(&msg, msgp); + if (!is_error(ret)) { + ret = get_errno(sendmsg(fd, &msg, flags)); + } + unlock_iovec(vec, target_vec, count, 0); + unlock_user_struct(msgp, target_msg, 0); + return ret; +} + +/* recvmsg(2) */ +static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg, + int flags) +{ + abi_long ret, len; + struct target_msghdr *msgp; + struct msghdr msg; + int count; + struct iovec *vec; + abi_ulong target_vec; + + if (!lock_user_struct(VERIFY_WRITE, msgp, target_msg, 0)) { + return -TARGET_EFAULT; + } + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + ret = target_to_host_sockaddr(msg.msg_name, + tswapal(msgp->msg_name), msg.msg_namelen); + + if (is_error(ret)) { + unlock_user_struct(msgp, target_msg, 1); + return ret; + } + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + msg.msg_controllen = 2 * tswapal(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); + msg.msg_flags = tswap32(msgp->msg_flags); + + count = tswapal(msgp->msg_iovlen); + vec = alloca(count * sizeof(struct iovec)); + target_vec = tswapal(msgp->msg_iov); + lock_iovec(VERIFY_WRITE, vec, target_vec, count, 0); + msg.msg_iovlen = count; + msg.msg_iov = vec; + + ret = get_errno(recvmsg(fd, &msg, flags)); + if (!is_error(ret)) { + len = ret; + ret = h2t_freebsd_cmsg(msgp, &msg); + if (!is_error(ret)) { + msgp->msg_namelen = tswap32(msg.msg_namelen); + if (msg.msg_name != NULL) { + ret = host_to_target_sockaddr(tswapal(msgp->msg_name), + msg.msg_name, msg.msg_namelen); + if (is_error(ret)) { + goto out; + } + } + } + ret = len; + } +out: + unlock_iovec(vec, target_vec, count, 1); + unlock_user_struct(msgp, target_msg, 1); + return ret; +} + +/* setsockopt(2) */ +static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, socklen_t optlen) +{ + abi_long ret; + int val; + struct ip_mreqn *ip_mreq; + + switch (level) { + case IPPROTO_TCP: + /* TCP options all take an 'int' value. */ + if (optlen < sizeof(uint32_t)) { + return -TARGET_EINVAL; + } + if (get_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + + case IPPROTO_IP: + switch (optname) { + case IP_HDRINCL:/* int; header is included with data */ + case IP_TOS: /* int; IP type of service and preced. */ + case IP_TTL: /* int; IP time to live */ + case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */ + case IP_RECVRETOPTS: /* bool; receive IP opts for response */ + case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */ + case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f */ + case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */ + case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */ + case IP_PORTRANGE: /* int; range to choose for unspec port */ + case IP_RECVIF: /* bool; receive reception if w/dgram */ + case IP_IPSEC_POLICY: /* int; set/get security policy */ + case IP_FAITH: /* bool; accept FAITH'ed connections */ + case IP_RECVTTL: /* bool; receive reception TTL w/dgram */ + val = 0; + if (optlen >= sizeof(uint32_t)) { + if (get_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } else if (optlen >= 1) { + if (get_user_u8(val, optval_addr)) { + return -TARGET_EFAULT; + } + } + ret = get_errno(setsockopt(sockfd, level, optname, &val, + sizeof(val))); + break; + + case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */ + case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group membership*/ + if (optlen < sizeof(struct target_ip_mreq) || + optlen > sizeof(struct target_ip_mreqn)) { + return -TARGET_EINVAL; + } + ip_mreq = (struct ip_mreqn *) alloca(optlen); + target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); + ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, + optlen)); + break; + + default: + goto unimplemented; + } + break; + + case TARGET_SOL_SOCKET: + switch (optname) { + /* Options with 'int' argument. */ + case TARGET_SO_DEBUG: + optname = SO_DEBUG; + break; + + case TARGET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + + case TARGET_SO_REUSEPORT: + optname = SO_REUSEADDR; + break; + + case TARGET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + + case TARGET_SO_DONTROUTE: + optname = SO_DONTROUTE; + break; + + case TARGET_SO_LINGER: + optname = SO_LINGER; + break; + + case TARGET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + + case TARGET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + + case TARGET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + + case TARGET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + + case TARGET_SO_SNDLOWAT: + optname = SO_RCVLOWAT; + break; + + case TARGET_SO_RCVLOWAT: + optname = SO_RCVLOWAT; + break; + + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + break; + + case TARGET_SO_RCVTIMEO: + optname = SO_RCVTIMEO; + break; + + case TARGET_SO_ACCEPTFILTER: + goto unimplemented; + + case TARGET_SO_NOSIGPIPE: + optname = SO_NOSIGPIPE; + break; + + case TARGET_SO_TIMESTAMP: + optname = SO_TIMESTAMP; + break; + + case TARGET_SO_BINTIME: + optname = SO_BINTIME; + break; + + case TARGET_SO_ERROR: + optname = SO_ERROR; + break; + + case TARGET_SO_SETFIB: + optname = SO_ERROR; + break; + +#ifdef SO_USER_COOKIE + case TARGET_SO_USER_COOKIE: + optname = SO_USER_COOKIE; + break; +#endif + default: + goto unimplemented; + } + if (optlen < sizeof(uint32_t)) { + return -TARGET_EINVAL; + } + if (get_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, + sizeof(val))); + break; + default: +unimplemented: + gemu_log("Unsupported setsockopt level=%d optname=%d\n", + level, optname); + ret = -TARGET_ENOPROTOOPT; + } + + return ret; +} + +/* getsockopt(2) */ +static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, abi_ulong optlen) +{ + abi_long ret; + int len, val; + socklen_t lv; + + switch (level) { + case TARGET_SOL_SOCKET: + level = SOL_SOCKET; + switch (optname) { + + /* These don't just return a single integer */ + case TARGET_SO_LINGER: + case TARGET_SO_RCVTIMEO: + case TARGET_SO_SNDTIMEO: + case TARGET_SO_ACCEPTFILTER: + goto unimplemented; + + /* Options with 'int' argument. */ + case TARGET_SO_DEBUG: + optname = SO_DEBUG; + goto int_case; + + case TARGET_SO_REUSEADDR: + optname = SO_REUSEADDR; + goto int_case; + + case TARGET_SO_REUSEPORT: + optname = SO_REUSEPORT; + goto int_case; + + case TARGET_SO_TYPE: + optname = SO_TYPE; + goto int_case; + + case TARGET_SO_ERROR: + optname = SO_ERROR; + goto int_case; + + case TARGET_SO_DONTROUTE: + optname = SO_DONTROUTE; + goto int_case; + + case TARGET_SO_BROADCAST: + optname = SO_BROADCAST; + goto int_case; + + case TARGET_SO_SNDBUF: + optname = SO_SNDBUF; + goto int_case; + + case TARGET_SO_RCVBUF: + optname = SO_RCVBUF; + goto int_case; + + case TARGET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + goto int_case; + + case TARGET_SO_OOBINLINE: + optname = SO_OOBINLINE; + goto int_case; + + case TARGET_SO_TIMESTAMP: + optname = SO_TIMESTAMP; + goto int_case; + + case TARGET_SO_RCVLOWAT: + optname = SO_RCVLOWAT; + goto int_case; + + case TARGET_SO_LISTENINCQLEN: + optname = SO_LISTENINCQLEN; + goto int_case; + + default: +int_case: + if (get_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + if (len < 0) { + return -TARGET_EINVAL; + } + lv = sizeof(lv); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) { + return ret; + } + if (len > lv) { + len = lv; + } + if (len == 4) { + if (put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } else { + if (put_user_u8(val, optval_addr)) { + return -TARGET_EFAULT; + } + } + if (put_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + break; + + } + break; + + case IPPROTO_TCP: + /* TCP options all take an 'int' value. */ + goto int_case; + + case IPPROTO_IP: + switch (optname) { + case IP_HDRINCL: + case IP_TOS: + case IP_TTL: + case IP_RECVOPTS: + case IP_RECVRETOPTS: + case IP_RECVDSTADDR: + + case IP_RETOPTS: +#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 && defined(IP_RECVTOS) + case IP_RECVTOS: +#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_PORTRANGE: + case IP_IPSEC_POLICY: + case IP_FAITH: + case IP_ONESBCAST: + case IP_BINDANY: + if (get_user_u32(len, optlen)) { + return -TARGET_EFAULT; + } + if (len < 0) { + return -TARGET_EINVAL; + } + lv = sizeof(lv); + ret = get_errno(getsockopt(sockfd, level, optname, + &val, &lv)); + if (ret < 0) { + return ret; + } + if (len < sizeof(int) && len > 0 && val >= 0 && + val < 255) { + len = 1; + if (put_user_u32(len, optlen) || + put_user_u8(val, optval_addr)) { + return -TARGET_EFAULT; + } + } else { + if (len > sizeof(int)) { + len = sizeof(int); + } + if (put_user_u32(len, optlen) || + put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } + break; + + default: + goto unimplemented; + } + break; + + default: +unimplemented: + gemu_log("getsockopt level=%d optname=%d not yet supported\n", + level, optname); + ret = -TARGET_EOPNOTSUPP; + break; + } + return ret; +} + +/* setfib(2) */ +static inline abi_long do_freebsd_setfib(abi_long fib) +{ + + return get_errno(setfib(fib)); +} + +/* sctp_peeloff(2) */ +static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id) +{ + + qemu_log("qemu: Unsupported syscall sctp_peeloff()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_sendmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s, + abi_ulong target_msg, abi_long msglen, abi_ulong target_to, + abi_ulong len, abi_ulong target_sinfo, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_recvmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s, + abi_ulong target_iov, abi_long iovlen, abi_ulong target_from, + abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n"); + return -TARGET_ENOSYS; +} + +/* freebsd4_sendfile(2) */ +static inline abi_long do_freebsd_freebsd4_sendfile(abi_long fd, abi_long s, + abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr, + abi_ulong target_sbytes, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall freebsd4_sendfile()\n"); + return -TARGET_ENOSYS; +} + +/* sendfile(2) */ +static inline abi_long do_freebsd_sendfile(abi_long fd, abi_long s, + abi_ulong arg3, abi_ulong arg4, abi_ulong nbytes, abi_ulong target_hdtr, + abi_ulong target_sbytes, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall sendfile()\n"); + return -TARGET_ENOSYS; +} + +#endif /* !__FREEBSD_SOCKET_H_ */ diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h index e915246..90d8eb4 100644 --- a/bsd-user/freebsd/qemu-os.h +++ b/bsd-user/freebsd/qemu-os.h @@ -50,6 +50,12 @@ abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n); +/* os-socket.c */ +abi_long t2h_freebsd_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh); +abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh); + /* os-stat.c */ abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st); abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st); diff --git a/bsd-user/netbsd/os-socket.c b/bsd-user/netbsd/os-socket.c new file mode 100644 index 0000000..d983c34 --- /dev/null +++ b/bsd-user/netbsd/os-socket.c @@ -0,0 +1 @@ +/* XXX NetBSD socket related helpers */ diff --git a/bsd-user/netbsd/os-socket.h b/bsd-user/netbsd/os-socket.h new file mode 100644 index 0000000..a49c41d --- /dev/null +++ b/bsd-user/netbsd/os-socket.h @@ -0,0 +1,98 @@ +/* + * NetBSD socket related system call shims + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef __NETBSD_SOCKET_H_ +#define __NETBSD_SOCKET_H_ + +/* + * XXX To support FreeBSD binaries on NetBSD these syscalls will need + * to be emulated. + */ + +/* sendmsg(2) */ +static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg, + int flags) +{ + + qemu_log("qemu: Unsupported syscall sendmsg()\n"); + return -TARGET_ENOSYS; +} + +/* recvmsg(2) */ +static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg, + int flags) +{ + + qemu_log("qemu: Unsupported syscall recvmsg()\n"); + return -TARGET_ENOSYS; +} + +/* setsockopt(2) */ +static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, socklen_t optlen) +{ + + qemu_log("qemu: Unsupported syscall setsockopt()\n"); + return -TARGET_ENOSYS; +} + +/* getsockopt(2) */ +static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, abi_ulong optlen) +{ + + qemu_log("qemu: Unsupported syscall getsockopt()\n"); + return -TARGET_ENOSYS; +} + +/* setfib(2) */ +static inline abi_long do_freebsd_setfib(abi_long fib) +{ + + qemu_log("qemu: Unsupported syscall setfib()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_peeloff(2) */ +static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id) +{ + + qemu_log("qemu: Unsupported syscall sctp_peeloff()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_sendmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s, + abi_ulong target_msg, abi_long msglen, abi_ulong target_to, + abi_ulong len, abi_ulong target_sinfo, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_recvmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s, + abi_ulong target_iov, abi_long iovlen, abi_ulong target_from, + abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n"); + return -TARGET_ENOSYS; +} + +#endif /* !__NETBSD_SOCKET_H_ */ diff --git a/bsd-user/openbsd/os-socket.c b/bsd-user/openbsd/os-socket.c new file mode 100644 index 0000000..183002d --- /dev/null +++ b/bsd-user/openbsd/os-socket.c @@ -0,0 +1 @@ +/* XXX OpenBSD socket related helpers */ diff --git a/bsd-user/openbsd/os-socket.h b/bsd-user/openbsd/os-socket.h new file mode 100644 index 0000000..b8b1e99 --- /dev/null +++ b/bsd-user/openbsd/os-socket.h @@ -0,0 +1,98 @@ +/* + * OpenBSD socket related system call shims + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef __OPENBSD_SOCKET_H_ +#define __OPENBSD_SOCKET_H_ + +/* + * XXX To support FreeBSD binaries on OpenBSD these syscalls will need + * to be emulated. + */ + +/* sendmsg(2) */ +static inline abi_long do_freebsd_sendmsg(int fd, abi_ulong target_msg, + int flags) +{ + + qemu_log("qemu: Unsupported syscall sendmsg()\n"); + return -TARGET_ENOSYS; +} + +/* recvmsg(2) */ +static inline abi_long do_freebsd_recvmsg(int fd, abi_ulong target_msg, + int flags) +{ + + qemu_log("qemu: Unsupported syscall recvmsg()\n"); + return -TARGET_ENOSYS; +} + +/* setsockopt(2) */ +static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, socklen_t optlen) +{ + + qemu_log("qemu: Unsupported syscall setsockopt()\n"); + return -TARGET_ENOSYS; +} + +/* getsockopt(2) */ +static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname, + abi_ulong optval_addr, abi_ulong optlen) +{ + + qemu_log("qemu: Unsupported syscall getsockopt()\n"); + return -TARGET_ENOSYS; +} + +/* setfib(2) */ +static inline abi_long do_freebsd_setfib(abi_long fib) +{ + + qemu_log("qemu: Unsupported syscall setfib()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_peeloff(2) */ +static inline abi_long do_freebsd_sctp_peeloff(abi_long s, abi_ulong id) +{ + + qemu_log("qemu: Unsupported syscall sctp_peeloff()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_sendmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_sendmsg(abi_long s, + abi_ulong target_msg, abi_long msglen, abi_ulong target_to, + abi_ulong len, abi_ulong target_sinfo, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_sendmsg()\n"); + return -TARGET_ENOSYS; +} + +/* sctp_generic_recvmsg(2) */ +static inline abi_long do_freebsd_sctp_generic_recvmsg(abi_long s, + abi_ulong target_iov, abi_long iovlen, abi_ulong target_from, + abi_ulong fromlen, abi_ulong target_sinfo, abi_ulong target_msgflags) +{ + + qemu_log("qemu: Unsupported syscall sctp_generic_recvmsg()\n"); + return -TARGET_ENOSYS; +} + +#endif /* !__OPENBSD_SOCKET_H_ */ diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h index f562aad..09b99ef 100644 --- a/bsd-user/qemu-bsd.h +++ b/bsd-user/qemu-bsd.h @@ -50,4 +50,12 @@ abi_long host_to_target_rusage(abi_ulong target_addr, const struct rusage *rusage); int host_to_target_waitstatus(int status); +/* bsd-socket.c */ +abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, + socklen_t len); +abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr, + socklen_t len); +abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr, + socklen_t len); + #endif /* !_QEMU_BSD_H_ */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index e3967fa..286c71e 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -39,11 +39,13 @@ static int host_to_target_errno(int err); #include "bsd-mem.h" #include "bsd-proc.h" #include "bsd-signal.h" +#include "bsd-socket.h" /* *BSD dependent syscall shims */ #include "os-time.h" #include "os-proc.h" #include "os-signal.h" +#include "os-socket.h" #include "os-stat.h" /* #define DEBUG */ @@ -1017,6 +1019,97 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; /* + * socket related system calls + */ + case TARGET_FREEBSD_NR_accept: /* accept(2) */ + ret = do_bsd_accept(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_bind: /* bind(2) */ + ret = do_bsd_bind(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_connect: /* connect(2) */ + ret = do_bsd_connect(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getpeername: /* getpeername(2) */ + ret = do_bsd_getpeername(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getsockname: /* getsockname(2) */ + ret = do_bsd_getsockname(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getsockopt: /* getsockopt(2) */ + ret = do_bsd_getsockopt(arg1, arg2, arg3, arg4, arg5); + break; + + case TARGET_FREEBSD_NR_setsockopt: /* setsockopt(2) */ + ret = do_bsd_setsockopt(arg1, arg2, arg3, arg4, arg5); + break; + + case TARGET_FREEBSD_NR_listen: /* listen(2) */ + ret = get_errno(listen(arg1, arg2)); + break; + + case TARGET_FREEBSD_NR_recvfrom: /* recvfrom(2) */ + ret = do_bsd_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_recvmsg: /* recvmsg(2) */ + ret = do_freebsd_recvmsg(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sendmsg: /* sendmsg(2) */ + ret = do_freebsd_sendmsg(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sendto: /* sendto(2) */ + ret = do_bsd_sendto(arg1, arg2, arg3, arg4, arg5, arg6); + break; + + case TARGET_FREEBSD_NR_socket: /* socket(2) */ + ret = do_bsd_socket(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_socketpair: /* socketpair(2) */ + ret = do_bsd_socketpair(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_shutdown: /* shutdown(2) */ + ret = do_bsd_shutdown(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_setfib: /* setfib(2) */ + ret = do_freebsd_setfib(arg1); + break; + + case TARGET_FREEBSD_NR_sctp_peeloff: /* sctp_peeloff(2) */ + ret = do_freebsd_sctp_peeloff(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_sctp_generic_sendmsg: /* sctp_generic_sendmsg(2) */ + ret = do_freebsd_sctp_generic_sendmsg(arg1, arg2, arg2, arg4, arg5, + arg6, arg7); + break; + + case TARGET_FREEBSD_NR_sctp_generic_recvmsg: /* sctp_generic_recvmsg(2) */ + ret = do_freebsd_sctp_generic_recvmsg(arg1, arg2, arg2, arg4, arg5, + arg6, arg7); + break; + + case TARGET_FREEBSD_NR_sendfile: /* sendfile(2) */ + ret = do_freebsd_sendfile(arg1, arg2, arg2, arg4, arg5, arg6, arg7, + arg8); + break; + + case TARGET_FREEBSD_NR_freebsd4_sendfile: /* freebsd4_sendfile(2) */ + ret = do_freebsd_freebsd4_sendfile(arg1, arg2, arg2, arg4, arg5, + arg6, arg7, arg8); + break; + + /* * sys{ctl, arch, call} */ case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */ -- 1.7.8