diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 111 |
1 files changed, 80 insertions, 31 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b187c1281d..d2c9817938 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -102,6 +102,7 @@ #include <linux/blkpg.h> #include <netpacket/packet.h> #include <linux/netlink.h> +#include <linux/if_alg.h> #include "linux_loop.h" #include "uname.h" @@ -762,50 +763,21 @@ safe_syscall2(int, nanosleep, const struct timespec *, req, safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags, const struct timespec *, req, struct timespec *, rem) #endif -#if !defined(__NR_msgsnd) || !defined(__NR_msgrcv) || !defined(__NR_semtimedop) -/* This host kernel architecture uses a single ipc syscall; fake up - * wrappers for the sub-operations to hide this implementation detail. - * Annoyingly we can't include linux/ipc.h to get the constant definitions - * for the call parameter because some structs in there conflict with the - * sys/ipc.h ones. So we just define them here, and rely on them being - * the same for all host architectures. - */ -#define Q_SEMTIMEDOP 4 -#define Q_MSGSND 11 -#define Q_MSGRCV 12 -#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP)) - +#ifdef __NR_ipc safe_syscall6(int, ipc, int, call, long, first, long, second, long, third, void *, ptr, long, fifth) #endif #ifdef __NR_msgsnd safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz, int, flags) -#else -static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags) -{ - return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0); -} #endif #ifdef __NR_msgrcv safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz, long, msgtype, int, flags) -#else -static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags) -{ - return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type); -} #endif #ifdef __NR_semtimedop safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops, unsigned, nsops, const struct timespec *, timeout) -#else -static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops, - const struct timespec *timeout) -{ - return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops, - (long)timeout); -} #endif #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr, @@ -1920,6 +1892,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, &pki, sizeof(pki))); break; } + case IPV6_ADD_MEMBERSHIP: + case IPV6_DROP_MEMBERSHIP: + { + struct ipv6_mreq ipv6mreq; + + if (optlen < sizeof(ipv6mreq)) { + return -TARGET_EINVAL; + } + + if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) { + return -TARGET_EFAULT; + } + + ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface); + + ret = get_errno(setsockopt(sockfd, level, optname, + &ipv6mreq, sizeof(ipv6mreq))); + break; + } default: goto unimplemented; } @@ -1970,6 +1961,36 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } break; +#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE) + case SOL_ALG: + switch (optname) { + case ALG_SET_KEY: + { + char *alg_key = g_malloc(optlen); + + if (!alg_key) { + return -TARGET_ENOMEM; + } + if (copy_from_user(alg_key, optval_addr, optlen)) { + g_free(alg_key); + return -TARGET_EFAULT; + } + ret = get_errno(setsockopt(sockfd, level, optname, + alg_key, optlen)); + g_free(alg_key); + break; + } + case ALG_SET_AEAD_AUTHSIZE: + { + ret = get_errno(setsockopt(sockfd, level, optname, + NULL, optlen)); + break; + } + default: + goto unimplemented; + } + break; +#endif case TARGET_SOL_SOCKET: switch (optname) { case TARGET_SO_RCVTIMEO: @@ -3529,11 +3550,21 @@ static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf, static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops) { struct sembuf sops[nsops]; + abi_long ret; if (target_to_host_sembuf(sops, ptr, nsops)) return -TARGET_EFAULT; - return get_errno(safe_semtimedop(semid, sops, nsops, NULL)); + ret = -TARGET_ENOSYS; +#ifdef __NR_semtimedop + ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0)); + } +#endif + return ret; } struct target_msqid_ds @@ -3688,7 +3719,16 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, } host_mb->mtype = (abi_long) tswapal(target_mb->mtype); memcpy(host_mb->mtext, target_mb->mtext, msgsz); + ret = -TARGET_ENOSYS; +#ifdef __NR_msgsnd ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, + host_mb, 0)); + } +#endif g_free(host_mb); unlock_user_struct(target_mb, msgp, 0); @@ -3716,7 +3756,16 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, ret = -TARGET_ENOMEM; goto end; } + ret = -TARGET_ENOSYS; +#ifdef __NR_msgrcv ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg)); +#endif +#ifdef __NR_ipc + if (ret == -TARGET_ENOSYS) { + ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz, + msgflg, host_mb, msgtyp)); + } +#endif if (ret > 0) { abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); |