mirror of https://gitee.com/openkylin/qemu.git
linux-user: convert ioctl(SIOCGIFCONF, ...) result.
The result needs to be converted as it is stored in an array of struct ifreq and sizeof(struct ifreq) differs according to target and host alignment rules. This patch allows to execute correctly the following program on arm and m68k: #include <stdio.h> #include <sys/ioctl.h> #include <net/if.h> #include <alloca.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void) { int s, ret; struct ifconf ifc; int i; memset( &ifc, 0, sizeof( struct ifconf ) ); ifc.ifc_len = 8 * sizeof(struct ifreq); ifc.ifc_buf = alloca(ifc.ifc_len); s = socket( AF_INET, SOCK_DGRAM, 0 ); if (s < 0) { perror("Cannot open socket"); return 1; } ret = ioctl( s, SIOCGIFCONF, &ifc ); if (s < 0) { perror("ioctl() failed"); return 1; } for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq) ; i ++) { struct sockaddr_in *s; s = (struct sockaddr_in*)&ifc.ifc_req[i].ifr_addr; printf("%s\n", ifc.ifc_req[i].ifr_name); printf("%s\n", inet_ntoa(s->sin_addr)); } } Signed-off-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
This commit is contained in:
parent
608e559217
commit
059c2f2cd7
|
@ -112,7 +112,8 @@
|
|||
IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
|
||||
IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
|
||||
IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
|
||||
IOCTL(SIOCGIFCONF, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifconf)))
|
||||
IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
|
||||
MK_PTR(MK_STRUCT(STRUCT_ifconf)))
|
||||
IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT))
|
||||
IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT))
|
||||
IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
|
||||
|
|
|
@ -59,6 +59,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
|
|||
//#include <sys/user.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <net/if.h>
|
||||
#include <qemu-common.h>
|
||||
#ifdef TARGET_GPROF
|
||||
#include <sys/gmon.h>
|
||||
|
@ -2970,7 +2971,6 @@ static abi_long do_ipc(unsigned int call, int first,
|
|||
#endif
|
||||
|
||||
/* kernel structure types definitions */
|
||||
#define IFNAMSIZ 16
|
||||
|
||||
#define STRUCT(name, ...) STRUCT_ ## name,
|
||||
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
|
||||
|
@ -3095,6 +3095,100 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
|
|||
}
|
||||
#endif
|
||||
|
||||
static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||
int fd, abi_long cmd, abi_long arg)
|
||||
{
|
||||
const argtype *arg_type = ie->arg_type;
|
||||
int target_size;
|
||||
void *argptr;
|
||||
int ret;
|
||||
struct ifconf *host_ifconf;
|
||||
uint32_t outbufsz;
|
||||
const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
|
||||
int target_ifreq_size;
|
||||
int nb_ifreq;
|
||||
int free_buf = 0;
|
||||
int i;
|
||||
int target_ifc_len;
|
||||
abi_long target_ifc_buf;
|
||||
int host_ifc_len;
|
||||
char *host_ifc_buf;
|
||||
|
||||
assert(arg_type[0] == TYPE_PTR);
|
||||
assert(ie->access == IOC_RW);
|
||||
|
||||
arg_type++;
|
||||
target_size = thunk_type_size(arg_type, 0);
|
||||
|
||||
argptr = lock_user(VERIFY_READ, arg, target_size, 1);
|
||||
if (!argptr)
|
||||
return -TARGET_EFAULT;
|
||||
thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
|
||||
unlock_user(argptr, arg, 0);
|
||||
|
||||
host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
|
||||
target_ifc_len = host_ifconf->ifc_len;
|
||||
target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
|
||||
|
||||
target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
|
||||
nb_ifreq = target_ifc_len / target_ifreq_size;
|
||||
host_ifc_len = nb_ifreq * sizeof(struct ifreq);
|
||||
|
||||
outbufsz = sizeof(*host_ifconf) + host_ifc_len;
|
||||
if (outbufsz > MAX_STRUCT_SIZE) {
|
||||
/* We can't fit all the extents into the fixed size buffer.
|
||||
* Allocate one that is large enough and use it instead.
|
||||
*/
|
||||
host_ifconf = malloc(outbufsz);
|
||||
if (!host_ifconf) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
|
||||
free_buf = 1;
|
||||
}
|
||||
host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
|
||||
|
||||
host_ifconf->ifc_len = host_ifc_len;
|
||||
host_ifconf->ifc_buf = host_ifc_buf;
|
||||
|
||||
ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
|
||||
if (!is_error(ret)) {
|
||||
/* convert host ifc_len to target ifc_len */
|
||||
|
||||
nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
|
||||
target_ifc_len = nb_ifreq * target_ifreq_size;
|
||||
host_ifconf->ifc_len = target_ifc_len;
|
||||
|
||||
/* restore target ifc_buf */
|
||||
|
||||
host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
|
||||
|
||||
/* copy struct ifconf to target user */
|
||||
|
||||
argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
|
||||
if (!argptr)
|
||||
return -TARGET_EFAULT;
|
||||
thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
|
||||
unlock_user(argptr, arg, target_size);
|
||||
|
||||
/* copy ifreq[] to target user */
|
||||
|
||||
argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
|
||||
for (i = 0; i < nb_ifreq ; i++) {
|
||||
thunk_convert(argptr + i * target_ifreq_size,
|
||||
host_ifc_buf + i * sizeof(struct ifreq),
|
||||
ifreq_arg_type, THUNK_TARGET);
|
||||
}
|
||||
unlock_user(argptr, target_ifc_buf, target_ifc_len);
|
||||
}
|
||||
|
||||
if (free_buf) {
|
||||
free(host_ifconf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IOCTLEntry ioctl_entries[] = {
|
||||
#define IOCTL(cmd, access, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
||||
|
|
Loading…
Reference in New Issue