Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add the socket system call shims.

Includes accept, bind, connect, getpeername, getsockopt, setsockopt,
listen, recvfrom, recmsg, sendmsg, sendto, socket, and socketpair.
  • Loading branch information...
commit c322e2d6688393af11e96c73e37ade48551eefaf 1 parent 3f304df
@staceyson authored
View
66 work/qemu-1.2.0/bsd-user/socket.h
@@ -0,0 +1,66 @@
+/*
+ * Target socket definitions.
+ */
+
+/*
+ * 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
View
752 work/qemu-1.2.0/bsd-user/syscall.c
@@ -36,8 +36,12 @@
#include <sys/event.h>
#include <sys/mount.h>
#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <utime.h>
+#include <netinet/in.h>
+
#include "qemu.h"
#include "qemu-common.h"
@@ -340,6 +344,179 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
return 0;
}
+static inline 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)
+ return -TARGET_EFAULT;
+
+ sa_family = tswap16(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 (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;
+ unlock_user(target_saddr, target_addr, 0);
+
+ return (0);
+}
+
+static inline 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)
+ return (-TARGET_EFAULT);
+ memcpy(target_saddr, addr, len);
+ target_saddr->sa_family = tswap16(addr->sa_family);
+ unlock_user(target_saddr, target_addr, len);
+
+ return (0);
+}
+
+static inline abi_long
+target_to_host_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)
+ 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);
+}
+
+static inline abi_long
+host_to_target_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)
+ 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_timeval *target_tv =
+ (struct target_timeval *)target_data;
+ target_tv->tv_sec = tswapal(tv->tv_sec);
+ target_tv->tv_usec = tswapal(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);
+}
+
static inline rlim_t
target_to_host_rlim(abi_ulong target_rlim)
{
@@ -676,6 +853,287 @@ unimplemented(int num)
return (-TARGET_ENOSYS);
}
+/* do_bind() must return target values and target errnos. */
+static abi_long
+do_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 (ret)
+ return (ret);
+
+ return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* do_connect() must return target values and target errnos. */
+static abi_long
+do_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 (ret)
+ return (ret);
+
+ return (get_errno(connect(sockfd, addr, addrlen)));
+}
+
+/* do_sendrecvmsg() must return target values and target errnos. */
+static abi_long
+do_sendrecvmsg(int fd, abi_ulong target_msg, int flags, int send)
+{
+ abi_long ret, len;
+ struct target_msghdr *msgp;
+ struct msghdr msg;
+ int count;
+ struct iovec *vec;
+ abi_ulong target_vec;
+
+ if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, msgp,
+ target_msg, send ? 1 : 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 (ret) {
+ unlock_user_struct(msgp, target_msg, send ? 0 : 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(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count,
+ send);
+ msg.msg_iovlen = count;
+ msg.msg_iov = vec;
+
+ if (send) {
+ ret = target_to_host_cmsg(&msg, msgp);
+ if (0 == ret)
+ ret = get_errno(sendmsg(fd, &msg, flags));
+ } else {
+ ret = get_errno(recvmsg(fd, &msg, flags));
+ if (!is_error(ret)) {
+ len = ret;
+ ret = host_to_target_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 (ret)
+ goto out;
+ }
+ }
+ ret = len;
+ }
+ }
+out:
+ unlock_iovec(vec, target_vec, count, !send);
+ unlock_user_struct(msgp, target_msg, send ? 0 : 1);
+ return (ret);
+}
+
+/* do_accept() must return target values and target errnos. */
+static abi_long
+do_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);
+}
+
+/* do_getpeername() must return target values and target errnos. */
+static abi_long
+do_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);
+}
+
+/* do_getsockname() must return target values and target errnos. */
+static abi_long
+do_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);
+}
+
+/* do_socketpair() must return target values and target errnos. */
+static abi_long
+do_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);
+}
+
+/* do_sendto() must return target values and target errnos. */
+static abi_long
+do_sendto(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr,
+ socklen_t addrlen)
+{
+ void *addr;
+ 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) {
+ addr = alloca(addrlen);
+ ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+ if (ret) {
+ unlock_user(host_msg, msg, 0);
+ return (ret);
+ }
+ ret = get_errno(sendto(fd, host_msg, len, flags, addr,
+ addrlen));
+ } else {
+ ret = get_errno(send(fd, host_msg, len, flags));
+ }
+ unlock_user(host_msg, msg, 0);
+ return (ret);
+}
+
+/* do_recvfrom() must return target values and target errnos. */
+static abi_long
+do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr,
+ abi_ulong target_addrlen)
+{
+ socklen_t addrlen;
+ void *addr;
+ 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;
+ }
+ addr = alloca(addrlen);
+ ret = get_errno(recvfrom(fd, host_msg, len, flags, addr,
+ &addrlen));
+ } else {
+ addr = 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, addr, 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);
+}
+
/* do_freebsd_select() must return target values and target errnos. */
static abi_long
do_freebsd_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr,
@@ -722,6 +1180,230 @@ do_freebsd_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr,
return (ret);
}
+/* do_getsockopt() must return target values and target errnos. */
+static abi_long
+do_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;
+
+ default:
+unimplemented:
+ gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+ level, optname);
+ ret = -TARGET_EOPNOTSUPP;
+ break;
+ }
+ return (ret);
+}
+
+/* do_setsockopt() must return target values and target errnos. */
+static abi_long
+do_setsockopt(int sockfd, int level, int optname, abi_ulong optval_addr,
+ socklen_t optlen)
+{
+ abi_long ret;
+
+ switch(level) {
+ 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;
+
+ case TARGET_SO_USER_COOKIE:
+ optname = SO_USER_COOKIE;
+ break;
+
+ default:
+ goto unimplemented;
+ }
+ break;
+
+ default:
+unimplemented:
+ gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+ level, optname);
+ ret = -TARGET_ENOPROTOOPT;
+ }
+
+ return (ret);
+}
+
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -1821,6 +2503,62 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
}
break;
+ case TARGET_FREEBSD_NR_accept:
+ ret = do_accept(arg1, arg2, arg3);
+ break;
+
+ case TARGET_FREEBSD_NR_bind:
+ ret = do_bind(arg1, arg2, arg3);
+ break;
+
+ case TARGET_FREEBSD_NR_connect:
+ ret = do_connect(arg1, arg2, arg3);
+ break;
+
+ case TARGET_FREEBSD_NR_getpeername:
+ ret = do_getpeername(arg1, arg2, arg3);
+ break;
+
+ case TARGET_FREEBSD_NR_getsockname:
+ ret = do_getsockname(arg1, arg2, arg3);
+ break;
+
+ case TARGET_FREEBSD_NR_getsockopt:
+ ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
+ break;
+
+ case TARGET_FREEBSD_NR_setsockopt:
+ ret = do_setsockopt(arg1, arg2, arg3, arg4, arg5);
+ break;
+
+ case TARGET_FREEBSD_NR_listen:
+ ret = get_errno(listen(arg1, arg2));
+ break;
+
+ case TARGET_FREEBSD_NR_recvfrom:
+ ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+ break;
+
+ case TARGET_FREEBSD_NR_recvmsg:
+ ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
+ break;
+
+ case TARGET_FREEBSD_NR_sendmsg:
+ ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
+ break;
+
+ case TARGET_FREEBSD_NR_sendto:
+ ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+ break;
+
+ case TARGET_FREEBSD_NR_socket:
+ ret = get_errno(socket(arg1, arg2, arg3));
+ break;
+
+ case TARGET_FREEBSD_NR_socketpair:
+ ret = do_socketpair(arg1, arg2, arg3, arg4);
+ break;
+
case TARGET_FREEBSD_NR_kill:
case TARGET_FREEBSD_NR_sigaction:
case TARGET_FREEBSD_NR_sigprocmask:
@@ -1837,20 +2575,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_FREEBSD_NR_getpriority:
case TARGET_FREEBSD_NR_setpriority:
- case TARGET_FREEBSD_NR_accept:
- case TARGET_FREEBSD_NR_bind:
- case TARGET_FREEBSD_NR_connect:
- case TARGET_FREEBSD_NR_getpeername:
- case TARGET_FREEBSD_NR_getsockname:
- case TARGET_FREEBSD_NR_getsockopt:
- /* case TARGET_FREEBSD_NR_listen: */
- case TARGET_FREEBSD_NR_recvfrom:
- case TARGET_FREEBSD_NR_recvmsg:
- case TARGET_FREEBSD_NR_sendmsg:
- case TARGET_FREEBSD_NR_sendto:
- /* case TARGET_FREEBSD_NR_socket: */
- case TARGET_FREEBSD_NR_socketpair:
-
case TARGET_FREEBSD_NR_swapon:
case TARGET_FREEBSD_NR_swapoff:
View
54 work/qemu-1.2.0/bsd-user/syscall_defs.h
@@ -178,6 +178,7 @@ struct target_rlimit {
#define TARGET_O_ASYNC 0x00000040
#define TARGET_O_DIRECT 0x00010000
+#include "socket.h"
#include "errno_defs.h"
#include "freebsd/syscall_nr.h"
@@ -198,6 +199,59 @@ struct target_iovec {
abi_long iov_len; /* Number of bytes */
};
+struct target_msghdr {
+ abi_long msg_name; /* Socket name */
+ int 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 */
+ int msg_flags; /* flags on received message */
+};
+
+struct target_cmsghdr {
+ abi_long cmsg_len;
+ int cmsg_level;
+ int 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);
+}
+
+struct target_sockaddr {
+ uint16_t sa_family;
+ uint8_t sa_data[14];
+};
+
+struct target_in_addr {
+ uint32_t s_addr; /* big endian */
+};
+
+
struct target_timeval {
abi_long tv_sec;
abi_long tv_usec;
Please sign in to comment.
Something went wrong with that request. Please try again.