summaryrefslogtreecommitdiffstats
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorAleksandar Markovic2016-09-22 18:56:57 +0200
committerRiku Voipio2016-10-21 14:19:40 +0200
commitff71a4545c0d9b452e77a91ab1c46f79a10a9eca (patch)
tree1ef9e290fcfde01d191da39f12bfbd2f171b6195 /linux-user/syscall.c
parentlinux-user: Fix msgrcv() and msgsnd() syscalls support (diff)
downloadqemu-ff71a4545c0d9b452e77a91ab1c46f79a10a9eca.tar.gz
qemu-ff71a4545c0d9b452e77a91ab1c46f79a10a9eca.tar.xz
qemu-ff71a4545c0d9b452e77a91ab1c46f79a10a9eca.zip
linux-user: Fix socketcall() syscall support
Since not all Linux host platforms support socketcall() (most notably Intel), do_socketcall() function in Qemu's syscalls.c is implemented to mirror the corespondant implementation of socketcall() in Linux kernel, and to utilise individual socket operations that are supported on all Linux platforms. (see kernel source file net/socket.c, definition of socketcall). However, error codes produced by Qemu implementation are wrong for the cases of invalid values of the first argument. Also, naming of constants is not consistent with kernel one, and not consistant with Qemu convention of prefixing such constants with "TARGET_". This patch in that light brings do_socketcall() closer to its kernel counterpart, and in that way fixes the errors and yields more consisrtent Qemu code. There were also three missing cases (among 20) for strace support for socketcall(). The array that contains pointers for appropriate printing functions is updated with 3 elements, however pointers to functions are left NULL, and its implementation is left for future. Also, this patch fixes failure of LTP test socketcall02, if executed on some Qemu emulated sywstems (uer mode). Signed-off-by: Aleksandar Markovic <aleksandar.markovic@imgtec.com> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c119
1 files changed, 62 insertions, 57 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 36ca921a7e..7ea23ad6ce 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3897,89 +3897,94 @@ fail:
}
#ifdef TARGET_NR_socketcall
-/* do_socketcall() Must return target values and target errnos. */
+/* do_socketcall() must return target values and target errnos. */
static abi_long do_socketcall(int num, abi_ulong vptr)
{
- static const unsigned ac[] = { /* number of arguments per call */
- [SOCKOP_socket] = 3, /* domain, type, protocol */
- [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */
- [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */
- [SOCKOP_listen] = 2, /* sockfd, backlog */
- [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */
- [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */
- [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */
- [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */
- [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */
- [SOCKOP_send] = 4, /* sockfd, msg, len, flags */
- [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */
- [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */
- [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */
- [SOCKOP_shutdown] = 2, /* sockfd, how */
- [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */
- [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */
- [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */
- [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */
- [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */
- [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */
+ static const unsigned nargs[] = { /* number of arguments per operation */
+ [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */
+ [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */
+ [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */
+ [TARGET_SYS_LISTEN] = 2, /* fd, backlog */
+ [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */
+ [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */
+ [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */
+ [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */
+ [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */
+ [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */
+ [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */
+ [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */
+ [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */
+ [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
+ [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */
+ [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */
+ [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */
+ [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */
+ [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */
+ [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */
};
abi_long a[6]; /* max 6 args */
+ unsigned i;
- /* first, collect the arguments in a[] according to ac[] */
- if (num >= 0 && num < ARRAY_SIZE(ac)) {
- unsigned i;
- assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */
- for (i = 0; i < ac[num]; ++i) {
- if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
- return -TARGET_EFAULT;
- }
+ /* check the range of the first argument num */
+ /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */
+ if (num < 1 || num > TARGET_SYS_SENDMMSG) {
+ return -TARGET_EINVAL;
+ }
+ /* ensure we have space for args */
+ if (nargs[num] > ARRAY_SIZE(a)) {
+ return -TARGET_EINVAL;
+ }
+ /* collect the arguments in a[] according to nargs[] */
+ for (i = 0; i < nargs[num]; ++i) {
+ if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) {
+ return -TARGET_EFAULT;
}
}
-
- /* now when we have the args, actually handle the call */
+ /* now when we have the args, invoke the appropriate underlying function */
switch (num) {
- case SOCKOP_socket: /* domain, type, protocol */
+ case TARGET_SYS_SOCKET: /* domain, type, protocol */
return do_socket(a[0], a[1], a[2]);
- case SOCKOP_bind: /* sockfd, addr, addrlen */
+ case TARGET_SYS_BIND: /* sockfd, addr, addrlen */
return do_bind(a[0], a[1], a[2]);
- case SOCKOP_connect: /* sockfd, addr, addrlen */
+ case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */
return do_connect(a[0], a[1], a[2]);
- case SOCKOP_listen: /* sockfd, backlog */
+ case TARGET_SYS_LISTEN: /* sockfd, backlog */
return get_errno(listen(a[0], a[1]));
- case SOCKOP_accept: /* sockfd, addr, addrlen */
+ case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */
return do_accept4(a[0], a[1], a[2], 0);
- case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */
- return do_accept4(a[0], a[1], a[2], a[3]);
- case SOCKOP_getsockname: /* sockfd, addr, addrlen */
+ case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */
return do_getsockname(a[0], a[1], a[2]);
- case SOCKOP_getpeername: /* sockfd, addr, addrlen */
+ case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */
return do_getpeername(a[0], a[1], a[2]);
- case SOCKOP_socketpair: /* domain, type, protocol, tab */
+ case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */
return do_socketpair(a[0], a[1], a[2], a[3]);
- case SOCKOP_send: /* sockfd, msg, len, flags */
+ case TARGET_SYS_SEND: /* sockfd, msg, len, flags */
return do_sendto(a[0], a[1], a[2], a[3], 0, 0);
- case SOCKOP_recv: /* sockfd, msg, len, flags */
+ case TARGET_SYS_RECV: /* sockfd, msg, len, flags */
return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0);
- case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */
+ case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */
return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]);
- case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */
+ case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */
return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]);
- case SOCKOP_shutdown: /* sockfd, how */
+ case TARGET_SYS_SHUTDOWN: /* sockfd, how */
return get_errno(shutdown(a[0], a[1]));
- case SOCKOP_sendmsg: /* sockfd, msg, flags */
+ case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */
+ return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
+ case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */
+ return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
+ case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */
return do_sendrecvmsg(a[0], a[1], a[2], 1);
- case SOCKOP_recvmsg: /* sockfd, msg, flags */
+ case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */
return do_sendrecvmsg(a[0], a[1], a[2], 0);
- case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */
- return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
- case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */
+ case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */
+ return do_accept4(a[0], a[1], a[2], a[3]);
+ case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */
return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0);
- case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */
- return do_setsockopt(a[0], a[1], a[2], a[3], a[4]);
- case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */
- return do_getsockopt(a[0], a[1], a[2], a[3], a[4]);
+ case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */
+ return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1);
default:
gemu_log("Unsupported socketcall: %d\n", num);
- return -TARGET_ENOSYS;
+ return -TARGET_EINVAL;
}
}
#endif