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).
Signed-off-by: Stacey Son <s...@freebsd.org> --- 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 1a33a6d..9869837 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_ABI_DIR)/os-proc.o \ - $(HOST_ABI_DIR)/os-stat.o \ + $(HOST_ABI_DIR)/os-socket.o $(HOST_ABI_DIR)/os-stat.o \ $(HOST_ABI_DIR)/os-sys.o \ $(HOST_ABI_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 <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> + +#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 <http://www.gnu.org/licenses/>. + */ +#ifndef __BSD_SOCKET_H_ +#define __BSD_SOCKET_H_ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> + +#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 <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#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 <http://www.gnu.org/licenses/>. + */ +#ifndef __FREEBSD_SOCKET_H_ +#define __FREEBSD_SOCKET_H_ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> + +#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 <http://www.gnu.org/licenses/>. + */ +#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 <http://www.gnu.org/licenses/>. + */ +#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