Patchwork [15/23] bsd-user: add shims for socket related system calls

login
register
mail settings
Submitter Stacey Son
Date June 24, 2013, 2:03 a.m.
Message ID <1372039435-41921-16-git-send-email-sson@FreeBSD.org>
Download mbox | patch
Permalink /patch/253925/
State New
Headers show

Comments

Stacey Son - June 24, 2013, 2:03 a.m.
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 <sson@FreeBSD.org>
---
 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

Patch

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 <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..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 <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
+        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 <sys/types.h>
+#include <sys/timex.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <time.h>
+
 /* 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 <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 893a475..c7c39c6 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -24,7 +24,10 @@ 
 #include <sys/ipc.h>
 #include <sys/resource.h>
 #include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/wait.h>
+#include <netinet/in.h>
 
 /* 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_ */