diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3ba3ef5..6257a04 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; @@ -2806,7 +2848,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) return -TARGET_EFAULT; - host_mb = malloc(msgsz+sizeof(long)); + host_mb = g_malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg)); if (ret > 0) { @@ -2821,11 +2863,11 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, } target_mb->mtype = tswapal(host_mb->mtype); - free(host_mb); end: if (target_mb) unlock_user_struct(target_mb, msgp, 1); + g_free(host_mb); 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)) @@ -6982,15 +7025,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, tde = target_dirp; while (len > 0) { reclen = de->d_reclen; - treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long))); + tnamelen = reclen - offsetof(struct linux_dirent, d_name); + assert(tnamelen >= 0); + treclen = tnamelen + offsetof(struct target_dirent, d_name); + assert(count1 + treclen <= count); tde->d_reclen = tswap16(treclen); tde->d_ino = tswapal(de->d_ino); tde->d_off = tswapal(de->d_off); - tnamelen = treclen - (2 * sizeof(abi_long) + 2); - if (tnamelen > 256) - tnamelen = 256; - /* XXX: may not be correct */ - pstrcpy(tde->d_name, tnamelen, de->d_name); + memcpy(tde->d_name, de->d_name, tnamelen); de = (struct linux_dirent *)((char *)de + reclen); len -= reclen; tde = (struct target_dirent *)((char *)tde + treclen); |