mips socket calls (initial patch by Raphael Rigo)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2006 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2006-06-24 15:06:03 +00:00
parent 480c1cdb39
commit 3532fa7402
3 changed files with 408 additions and 80 deletions

138
linux-user/socket.h Normal file
View File

@ -0,0 +1,138 @@
#if defined(TARGET_MIPS)
// MIPS special values for constants
/*
* For setsockopt(2)
*
* This defines are ABI conformant as far as Linux supports these ...
*/
#define TARGET_SOL_SOCKET 0xffff
#define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */
#define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */
#define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send
SIGPIPE when they die. */
#define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */
#define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of
broadcast messages. */
#define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable
socket to transmit pending data. */
#define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */
#if 0
To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#endif
#define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
#define TARGET_SO_STYLE SO_TYPE /* Synonym */
#define TARGET_SO_ERROR 0x1007 /* get error status and clear */
#define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */
#define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
#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_ACCEPTCONN 0x1009
/* linux-specific, might as well be the same as on i386 */
#define TARGET_SO_NO_CHECK 11
#define TARGET_SO_PRIORITY 12
#define TARGET_SO_BSDCOMPAT 14
#define TARGET_SO_PASSCRED 17
#define TARGET_SO_PEERCRED 18
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 22
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
#define TARGET_SO_BINDTODEVICE 25
/* Socket filtering */
#define TARGET_SO_ATTACH_FILTER 26
#define TARGET_SO_DETACH_FILTER 27
#define TARGET_SO_PEERNAME 28
#define TARGET_SO_TIMESTAMP 29
#define SCM_TIMESTAMP SO_TIMESTAMP
#define TARGET_SO_PEERSEC 30
#define TARGET_SO_SNDBUFFORCE 31
#define TARGET_SO_RCVBUFFORCE 33
/** sock_type - Socket types
*
* Please notice that for binary compat reasons MIPS has to
* override the enum sock_type in include/linux/net.h, so
* we define ARCH_HAS_SOCKET_TYPES here.
*
* @SOCK_DGRAM - datagram (conn.less) socket
* @SOCK_STREAM - stream (connection) socket
* @SOCK_RAW - raw socket
* @SOCK_RDM - reliably-delivered message
* @SOCK_SEQPACKET - sequential packet socket
* @SOCK_PACKET - linux specific way of getting packets at the dev level.
* For writing rarp and other similar things on the user level.
*/
enum sock_type {
TARGET_SOCK_DGRAM = 1,
TARGET_SOCK_STREAM = 2,
TARGET_SOCK_RAW = 3,
TARGET_SOCK_RDM = 4,
TARGET_SOCK_SEQPACKET = 5,
TARGET_SOCK_DCCP = 6,
TARGET_SOCK_PACKET = 10,
};
#define TARGET_SOCK_MAX (SOCK_PACKET + 1)
#else
/* For setsockopt(2) */
#define TARGET_SOL_SOCKET 1
#define TARGET_SO_DEBUG 1
#define TARGET_SO_REUSEADDR 2
#define TARGET_SO_TYPE 3
#define TARGET_SO_ERROR 4
#define TARGET_SO_DONTROUTE 5
#define TARGET_SO_BROADCAST 6
#define TARGET_SO_SNDBUF 7
#define TARGET_SO_RCVBUF 8
#define TARGET_SO_SNDBUFFORCE 32
#define TARGET_SO_RCVBUFFORCE 33
#define TARGET_SO_KEEPALIVE 9
#define TARGET_SO_OOBINLINE 10
#define TARGET_SO_NO_CHECK 11
#define TARGET_SO_PRIORITY 12
#define TARGET_SO_LINGER 13
#define TARGET_SO_BSDCOMPAT 14
/* To add :#define TARGET_SO_REUSEPORT 15 */
#define TARGET_SO_PASSCRED 16
#define TARGET_SO_PEERCRED 17
#define TARGET_SO_RCVLOWAT 18
#define TARGET_SO_SNDLOWAT 19
#define TARGET_SO_RCVTIMEO 20
#define TARGET_SO_SNDTIMEO 21
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 22
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
#define TARGET_SO_BINDTODEVICE 25
/* Socket filtering */
#define TARGET_SO_ATTACH_FILTER 26
#define TARGET_SO_DETACH_FILTER 27
#define TARGET_SO_PEERNAME 28
#define TARGET_SO_TIMESTAMP 29
#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
#define TARGET_SO_ACCEPTCONN 30
#define TARGET_SO_PEERSEC 31
#endif

View File

@ -446,7 +446,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh,
cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
cmsg->cmsg_len = CMSG_LEN(len); cmsg->cmsg_len = CMSG_LEN(len);
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 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); gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(data, target_data, len); memcpy(data, target_data, len);
} else { } else {
@ -490,7 +490,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 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); gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(target_data, data, len); memcpy(target_data, data, len);
} else { } else {
@ -552,38 +552,74 @@ static long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented; goto unimplemented;
} }
break; break;
case SOL_SOCKET: case TARGET_SOL_SOCKET:
switch (optname) { switch (optname) {
/* Options with 'int' argument. */ /* Options with 'int' argument. */
case SO_DEBUG: case TARGET_SO_DEBUG:
case SO_REUSEADDR: optname = SO_DEBUG;
case SO_TYPE: break;
case SO_ERROR: case TARGET_SO_REUSEADDR:
case SO_DONTROUTE: optname = SO_REUSEADDR;
case SO_BROADCAST: break;
case SO_SNDBUF: case TARGET_SO_TYPE:
case SO_RCVBUF: optname = SO_TYPE;
case SO_KEEPALIVE: break;
case SO_OOBINLINE: case TARGET_SO_ERROR:
case SO_NO_CHECK: optname = SO_ERROR;
case SO_PRIORITY: break;
case TARGET_SO_DONTROUTE:
optname = SO_DONTROUTE;
break;
case TARGET_SO_BROADCAST:
optname = SO_BROADCAST;
break;
case TARGET_SO_SNDBUF:
optname = SO_SNDBUF;
break;
case TARGET_SO_RCVBUF:
optname = SO_RCVBUF;
break;
case TARGET_SO_KEEPALIVE:
optname = SO_KEEPALIVE;
break;
case TARGET_SO_OOBINLINE:
optname = SO_OOBINLINE;
break;
case TARGET_SO_NO_CHECK:
optname = SO_NO_CHECK;
break;
case TARGET_SO_PRIORITY:
optname = SO_PRIORITY;
break;
#ifdef SO_BSDCOMPAT #ifdef SO_BSDCOMPAT
case SO_BSDCOMPAT: case TARGET_SO_BSDCOMPAT:
optname = SO_BSDCOMPAT;
break;
#endif #endif
case SO_PASSCRED: case TARGET_SO_PASSCRED:
case SO_TIMESTAMP: optname = SO_PASSCRED;
case SO_RCVLOWAT: break;
case SO_RCVTIMEO: case TARGET_SO_TIMESTAMP:
case SO_SNDTIMEO: optname = SO_TIMESTAMP;
if (optlen < sizeof(uint32_t)) break;
return -EINVAL; case TARGET_SO_RCVLOWAT:
optname = SO_RCVLOWAT;
val = tget32(optval); break;
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); case TARGET_SO_RCVTIMEO:
optname = SO_RCVTIMEO;
break;
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
break;
break; break;
default: default:
goto unimplemented; goto unimplemented;
} }
if (optlen < sizeof(uint32_t))
return -EINVAL;
val = tget32(optval);
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
break; break;
default: default:
unimplemented: unimplemented:
@ -599,13 +635,14 @@ static long do_getsockopt(int sockfd, int level, int optname,
int len, lv, val, ret; int len, lv, val, ret;
switch(level) { switch(level) {
case SOL_SOCKET: case TARGET_SOL_SOCKET:
level = SOL_SOCKET;
switch (optname) { switch (optname) {
case SO_LINGER: case TARGET_SO_LINGER:
case SO_RCVTIMEO: case TARGET_SO_RCVTIMEO:
case SO_SNDTIMEO: case TARGET_SO_SNDTIMEO:
case SO_PEERCRED: case TARGET_SO_PEERCRED:
case SO_PEERNAME: case TARGET_SO_PEERNAME:
/* These don't just return a single integer */ /* These don't just return a single integer */
goto unimplemented; goto unimplemented;
default: default:
@ -711,6 +748,94 @@ static void unlock_iovec(struct iovec *vec, target_ulong target_addr,
unlock_user (target_vec, target_addr, 0); unlock_user (target_vec, target_addr, 0);
} }
static long do_socket(int domain, int type, int protocol)
{
#if defined(TARGET_MIPS)
switch(type) {
case TARGET_SOCK_DGRAM:
type = SOCK_DGRAM;
break;
case TARGET_SOCK_STREAM:
type = SOCK_STREAM;
break;
case TARGET_SOCK_RAW:
type = SOCK_RAW;
break;
case TARGET_SOCK_RDM:
type = SOCK_RDM;
break;
case TARGET_SOCK_SEQPACKET:
type = SOCK_SEQPACKET;
break;
case TARGET_SOCK_PACKET:
type = SOCK_PACKET;
break;
}
#endif
return get_errno(socket(domain, type, protocol));
}
static long do_bind(int sockfd, target_ulong target_addr,
socklen_t addrlen)
{
void *addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
}
static long do_connect(int sockfd, target_ulong target_addr,
socklen_t addrlen)
{
void *addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(connect(sockfd, addr, addrlen));
}
static long do_sendrecvmsg(int fd, target_ulong target_msg,
int flags, int send)
{
long ret;
struct target_msghdr *msgp;
struct msghdr msg;
int count;
struct iovec *vec;
target_ulong target_vec;
lock_user_struct(msgp, target_msg, 1);
if (msgp->msg_name) {
msg.msg_namelen = tswap32(msgp->msg_namelen);
msg.msg_name = alloca(msg.msg_namelen);
target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
msg.msg_namelen);
} else {
msg.msg_name = NULL;
msg.msg_namelen = 0;
}
msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
msg.msg_control = alloca(msg.msg_controllen);
msg.msg_flags = tswap32(msgp->msg_flags);
count = tswapl(msgp->msg_iovlen);
vec = alloca(count * sizeof(struct iovec));
target_vec = tswapl(msgp->msg_iov);
lock_iovec(vec, target_vec, count, send);
msg.msg_iovlen = count;
msg.msg_iov = vec;
if (send) {
target_to_host_cmsg(&msg, msgp);
ret = get_errno(sendmsg(fd, &msg, flags));
} else {
ret = get_errno(recvmsg(fd, &msg, flags));
if (!is_error(ret))
host_to_target_cmsg(msgp, &msg);
}
unlock_iovec(vec, target_vec, count, !send);
return ret;
}
static long do_socketcall(int num, target_ulong vptr) static long do_socketcall(int num, target_ulong vptr)
{ {
long ret; long ret;
@ -722,8 +847,7 @@ static long do_socketcall(int num, target_ulong vptr)
int domain = tgetl(vptr); int domain = tgetl(vptr);
int type = tgetl(vptr + n); int type = tgetl(vptr + n);
int protocol = tgetl(vptr + 2 * n); int protocol = tgetl(vptr + 2 * n);
ret = do_socket(domain, type, protocol);
ret = get_errno(socket(domain, type, protocol));
} }
break; break;
case SOCKOP_bind: case SOCKOP_bind:
@ -731,10 +855,7 @@ static long do_socketcall(int num, target_ulong vptr)
int sockfd = tgetl(vptr); int sockfd = tgetl(vptr);
target_ulong target_addr = tgetl(vptr + n); target_ulong target_addr = tgetl(vptr + n);
socklen_t addrlen = tgetl(vptr + 2 * n); socklen_t addrlen = tgetl(vptr + 2 * n);
void *addr = alloca(addrlen); ret = do_bind(sockfd, target_addr, addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
ret = get_errno(bind(sockfd, addr, addrlen));
} }
break; break;
case SOCKOP_connect: case SOCKOP_connect:
@ -742,17 +863,13 @@ static long do_socketcall(int num, target_ulong vptr)
int sockfd = tgetl(vptr); int sockfd = tgetl(vptr);
target_ulong target_addr = tgetl(vptr + n); target_ulong target_addr = tgetl(vptr + n);
socklen_t addrlen = tgetl(vptr + 2 * n); socklen_t addrlen = tgetl(vptr + 2 * n);
void *addr = alloca(addrlen); ret = do_connect(sockfd, target_addr, addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
ret = get_errno(connect(sockfd, addr, addrlen));
} }
break; break;
case SOCKOP_listen: case SOCKOP_listen:
{ {
int sockfd = tgetl(vptr); int sockfd = tgetl(vptr);
int backlog = tgetl(vptr + n); int backlog = tgetl(vptr + n);
ret = get_errno(listen(sockfd, backlog)); ret = get_errno(listen(sockfd, backlog));
} }
break; break;
@ -895,46 +1012,14 @@ static long do_socketcall(int num, target_ulong vptr)
{ {
int fd; int fd;
target_ulong target_msg; target_ulong target_msg;
struct target_msghdr *msgp; int flags;
struct msghdr msg;
int flags, count;
struct iovec *vec;
target_ulong target_vec;
int send = (num == SOCKOP_sendmsg);
target_msg = tgetl(vptr + n);
lock_user_struct(msgp, target_msg, 1);
if (msgp->msg_name) {
msg.msg_namelen = tswap32(msgp->msg_namelen);
msg.msg_name = alloca(msg.msg_namelen);
target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
msg.msg_namelen);
} else {
msg.msg_name = NULL;
msg.msg_namelen = 0;
}
msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
msg.msg_control = alloca(msg.msg_controllen);
msg.msg_flags = tswap32(msgp->msg_flags);
count = tswapl(msgp->msg_iovlen);
vec = alloca(count * sizeof(struct iovec));
target_vec = tswapl(msgp->msg_iov);
lock_iovec(vec, target_vec, count, send);
msg.msg_iovlen = count;
msg.msg_iov = vec;
fd = tgetl(vptr); fd = tgetl(vptr);
target_msg = tgetl(vptr + n);
flags = tgetl(vptr + 2 * n); flags = tgetl(vptr + 2 * n);
if (send) {
target_to_host_cmsg(&msg, msgp); ret = do_sendrecvmsg(fd, target_msg, flags,
ret = get_errno(sendmsg(fd, &msg, flags)); (num == SOCKOP_sendmsg));
} else {
ret = get_errno(recvmsg(fd, &msg, flags));
if (!is_error(ret))
host_to_target_cmsg(msgp, &msg);
}
unlock_iovec(vec, target_vec, count, !send);
} }
break; break;
case SOCKOP_setsockopt: case SOCKOP_setsockopt:
@ -967,6 +1052,22 @@ static long do_socketcall(int num, target_ulong vptr)
return ret; return ret;
} }
/* XXX: suppress this function and call directly the related socket
functions */
static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6)
{
target_long args[6];
tputl(args, arg1);
tputl(args+1, arg2);
tputl(args+2, arg3);
tputl(args+3, arg4);
tputl(args+4, arg5);
tputl(args+5, arg6);
return do_socketcall(num, (target_ulong) args);
}
#define N_SHM_REGIONS 32 #define N_SHM_REGIONS 32
@ -2616,6 +2717,93 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_socketcall: case TARGET_NR_socketcall:
ret = do_socketcall(arg1, arg2); ret = do_socketcall(arg1, arg2);
break; break;
#ifdef TARGET_NR_accept
case TARGET_NR_accept:
ret = do_socketcallwrapper(SOCKOP_accept, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_bind
case TARGET_NR_bind:
ret = do_bind(arg1, arg2, arg3);
break;
#endif
#ifdef TARGET_NR_connect
case TARGET_NR_connect:
ret = do_connect(arg1, arg2, arg3);
break;
#endif
#ifdef TARGET_NR_getpeername
case TARGET_NR_getpeername:
ret = do_socketcallwrapper(SOCKOP_getpeername, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_getsockname
case TARGET_NR_getsockname:
ret = do_socketcallwrapper(SOCKOP_getsockname, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_getsockopt
case TARGET_NR_getsockopt:
ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
break;
#endif
#ifdef TARGET_NR_listen
case TARGET_NR_listen:
ret = do_socketcallwrapper(SOCKOP_listen, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_recv
case TARGET_NR_recv:
ret = do_socketcallwrapper(SOCKOP_recv, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_recvfrom
case TARGET_NR_recvfrom:
ret = do_socketcallwrapper(SOCKOP_recvfrom, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_recvmsg
case TARGET_NR_recvmsg:
ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
break;
#endif
#ifdef TARGET_NR_send
case TARGET_NR_send:
ret = do_socketcallwrapper(SOCKOP_send, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_sendmsg
case TARGET_NR_sendmsg:
ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
break;
#endif
#ifdef TARGET_NR_sendto
case TARGET_NR_sendto:
ret = do_socketcallwrapper(SOCKOP_sendto, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_shutdown
case TARGET_NR_shutdown:
ret = do_socketcallwrapper(SOCKOP_shutdown, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_socket
case TARGET_NR_socket:
ret = do_socket(arg1, arg2, arg3);
break;
#endif
#ifdef TARGET_NR_socketpair
case TARGET_NR_socketpair:
ret = do_socketcallwrapper(SOCKOP_socketpair, arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_setsockopt
case TARGET_NR_setsockopt:
ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
break;
#endif
case TARGET_NR_syslog: case TARGET_NR_syslog:
goto unimplemented; goto unimplemented;
case TARGET_NR_setitimer: case TARGET_NR_setitimer:

View File

@ -1502,3 +1502,5 @@ struct target_sysinfo {
unsigned int mem_unit; /* Memory unit size in bytes */ unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
}; };
#include "socket.h"