From 615536e1c66e22ca49dd38ff29b43c297cbf64d4 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Thu, 30 May 2013 09:00:00 -0500 Subject: [PATCH 15/23] bsd-user: add shims for socket related system calls To: Cc: This change adds support for socket related system calls including socket, bind, accept, getsockopt, setsocketopt, etc. Like the other changes to add shims for system calls some are FreeBSD dependent. These shims are defined in freebsd/os-socket.h. Stubs to emulate these on other *BSDs are included in *bsd/os-socket.h. Signed-off-by: Stacey Son --- bsd-user/Makefile.objs | 2 +- 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 | 14 + 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 | 11 + bsd-user/syscall.c | 98 ++++++++- bsd-user/syscall_defs.h | 134 ++++++++++ 13 files changed, 1524 insertions(+), 4 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 d21ddfa..01f315e 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,3 +1,3 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ uaccess.o bsd-mem.o bsd-proc.o $(TARGET_OS)/os-time.o \ - $(TARGET_OS)/os-proc.o + $(TARGET_OS)/os-proc.o bsd-socket.o $(TARGET_OS)/os-socket.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..d7fd9e1 --- /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 + 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 7a1ed9c..ff3a2c2 100644 --- a/bsd-user/freebsd/qemu-os.h +++ b/bsd-user/freebsd/qemu-os.h @@ -20,6 +20,14 @@ #ifndef _QEMU_OS_H_ #define _QEMU_OS_H_ +#include +#include +#include +#include +#include + +#include + /* os-time.c */ abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr); abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr); @@ -38,4 +46,10 @@ 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); + #endif /* !_QEMU_OS_H_ */ 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 893a475..c7c39c6 100644 --- a/bsd-user/qemu-bsd.h +++ b/bsd-user/qemu-bsd.h @@ -24,7 +24,10 @@ #include #include #include +#include +#include #include +#include /* bsd-mem.c */ abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, @@ -44,4 +47,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 e8fe25c..98b1339 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -36,12 +36,14 @@ static int host_to_target_errno(int err); #include "bsd-file.h" #include "bsd-mem.h" -#include "bsd-signal.h" #include "bsd-proc.h" +#include "bsd-signal.h" +#include "bsd-socket.h" #include "os-time.h" -#include "os-signal.h" #include "os-proc.h" +#include "os-signal.h" +#include "os-socket.h" /* #define DEBUG */ @@ -1027,7 +1029,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_ktimer_gettime(arg1, arg2); break; - case TARGET_FREEBSD_NR_ktimer_getoverrun: /* undocumented */ ret = do_freebsd_ktimer_getoverrun(arg1); break; @@ -1103,6 +1104,97 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_pdkill(arg1, arg2); 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; + case TARGET_FREEBSD_NR_break: ret = do_obreak(arg1); diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index a69b31b..84d2f6f 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -209,4 +209,138 @@ struct target_freebsd_rusage { abi_long ru_nivcsw; /* involuntary context switches */ }; +/* + * sys/socket.h + */ + +/* + * Types + */ +#define TARGET_SOCK_STREAM 1 /* stream socket */ +#define TARGET_SOCK_DGRAM 2 /* datagram socket */ +#define TARGET_SOCK_RAW 3 /* raw-protocol interface */ +#define TARGET_SOCK_RDM 4 /* reliably-delivered message */ +#define TARGET_SOCK_SEQPACKET 5 /* sequenced packet stream */ + + +/* + * Option flags per-socket. + */ + +#define TARGET_SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define TARGET_SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define TARGET_SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define TARGET_SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define TARGET_SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define TARGET_SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define TARGET_SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define TARGET_SO_LINGER 0x0080 /* linger on close if data present */ +#define TARGET_SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define TARGET_SO_REUSEPORT 0x0200 /* allow local address & port reuse */ +#define TARGET_SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */ +#define TARGET_SO_NOSIGPIPE 0x0800 /* no SIGPIPE from EPIPE */ +#define TARGET_SO_ACCEPTFILTER 0x1000 /* there is an accept filter */ +#define TARGET_SO_BINTIME 0x2000 /* timestamp received dgram traffic */ +#define TARGET_SO_NO_OFFLOAD 0x4000 /* socket cannot be offloaded */ +#define TARGET_SO_NO_DDP 0x8000 /* disable direct data placement */ + +/* + * Additional options, not kept in so_options. + */ +#define TARGET_SO_SNDBUF 0x1001 /* send buffer size */ +#define TARGET_SO_RCVBUF 0x1002 /* receive buffer size */ +#define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ +#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ +#define TARGET_SO_ERROR 0x1007 /* get error status and clear */ +#define TARGET_SO_TYPE 0x1008 /* get socket type */ +#define TARGET_SO_LABEL 0x1009 /* socket's MAC label */ +#define TARGET_SO_PEERLABEL 0x1010 /* socket's peer's MAC label */ +#define TARGET_SO_LISTENQLIMIT 0x1011 /* socket's backlog limit */ +#define TARGET_SO_LISTENQLEN 0x1012 /* socket's complete queue length */ +#define TARGET_SO_LISTENINCQLEN 0x1013 /* socket's incomplete queue length */ +#define TARGET_SO_SETFIB 0x1014 /* use this FIB to route */ +#define TARGET_SO_USER_COOKIE 0x1015 /* user cookie (dummynet etc.) */ +#define TARGET_SO_PROTOCOL 0x1016 /* get socket protocol (Linux name) */ + +/* alias for SO_PROTOCOL (SunOS name) */ +#define TARGET_SO_PROTOTYPE TARGET_SO_PROTOCOL + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define TARGET_SOL_SOCKET 0xffff /* options for socket level */ + +#ifndef CMSG_ALIGN +#define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1)) +#endif + +struct target_msghdr { + abi_long msg_name; /* So cket name */ + int32_t msg_namelen; /* Length of name */ + abi_long msg_iov; /* Data blocks */ + abi_long msg_iovlen; /* Number of blocks */ + abi_long msg_control; /* Per protocol magic + (eg BSD file descriptor passing) */ + abi_long msg_controllen; /* Length of cmsg list */ + int32_t msg_flags; /* flags on received message */ +}; + +struct target_sockaddr { + uint8_t sa_len; + uint8_t sa_family; + uint8_t sa_data[14]; +} QEMU_PACKED; + +struct target_in_addr { + uint32_t s_addr; /* big endian */ +}; + +struct target_cmsghdr { + abi_long cmsg_len; + int32_t cmsg_level; + int32_t cmsg_type; +}; + +#define TARGET_CMSG_DATA(cmsg) \ + ((unsigned char *)((struct target_cmsghdr *) (cmsg) + 1)) +#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr(mhdr, cmsg) +#define TARGET_CMSG_ALIGN(len) (((len) + sizeof(abi_long) - 1) \ + & (size_t) ~(sizeof(abi_long) - 1)) +#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN(len) \ + + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr))) +#define TARGET_CMSG_LEN(len) \ + (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + (len)) + +static inline struct target_cmsghdr *__target_cmsg_nxthdr( + struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg) +{ + struct target_cmsghdr *__ptr; + + __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg + + TARGET_CMSG_ALIGN(tswapal(__cmsg->cmsg_len))); + if ((unsigned long)((char *)(__ptr+1) - + (char *)(size_t)tswapal(__mhdr->msg_control)) > + tswapal(__mhdr->msg_controllen)) { + /* No more entries. */ + return (struct target_cmsghdr *)0; + } + return __cmsg; +} + +/* + * netinet/in.h + */ +struct target_ip_mreq { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_interface; +}; + +struct target_ip_mreqn { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_address; + int32_t imr_ifindex; +}; + #endif /* ! _SYSCALL_DEFS_H_ */ -- 1.7.8