aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c67
1 files changed, 55 insertions, 12 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3ba3ef5719..41c869bfe0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -60,6 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/wireless.h>
+#include <linux/icmp.h>
#include "qemu-common.h"
#ifdef TARGET_GPROF
#include <sys/gmon.h>
@@ -1268,7 +1269,6 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
return 0;
}
-/* ??? Should this also swap msgh->name? */
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
struct target_msghdr *target_msgh)
{
@@ -1325,7 +1325,6 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
return 0;
}
-/* ??? Should this also swap msgh->name? */
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct msghdr *msgh)
{
@@ -1360,16 +1359,28 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
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) {
- gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
- memcpy(target_data, data, len);
- } else {
+ 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);
@@ -1454,6 +1465,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented;
}
break;
+ case SOL_RAW:
+ switch (optname) {
+ case ICMP_FILTER:
+ /* struct icmp_filter takes an u32 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;
+
+ default:
+ goto unimplemented;
+ }
+ break;
case TARGET_SOL_SOCKET:
switch (optname) {
/* Options with 'int' argument. */
@@ -1885,10 +1915,22 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
if (!is_error(ret)) {
len = ret;
ret = host_to_target_cmsg(msgp, &msg);
- if (!is_error(ret))
+ 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;
@@ -4606,6 +4648,12 @@ void syscall_init(void)
#undef STRUCT
#undef STRUCT_SPECIAL
+ /* Build target_to_host_errno_table[] table from
+ * host_to_target_errno_table[]. */
+ for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
+ target_to_host_errno_table[host_to_target_errno_table[i]] = i;
+ }
+
/* we patch the ioctl size if necessary. We rely on the fact that
no ioctl has all the bits at '1' in the size field */
ie = ioctl_entries;
@@ -4625,11 +4673,6 @@ void syscall_init(void)
(size << TARGET_IOC_SIZESHIFT);
}
- /* Build target_to_host_errno_table[] table from
- * host_to_target_errno_table[]. */
- for (i=0; i < ERRNO_TABLE_SIZE; i++)
- target_to_host_errno_table[host_to_target_errno_table[i]] = i;
-
/* automatic consistency check if same arch */
#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
(defined(__x86_64__) && defined(TARGET_X86_64))