linux-user: convert /proc/net/route when endianess differs

This patch allows to have IP addresses in correct order
in the case of "netstat -nr" when the endianess of the
guest differs from one of the host.

For instance, an m68k guest on an x86_64 host:

WITHOUT this patch:

$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         1.3.0.10        0.0.0.0         UG        0 0          0 eth0
0.3.0.10        0.0.0.0         0.255.255.255   U         0 0          0 eth0
$ cat /proc/net/route
Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask	MTU	Window	IRTT

eth0	00000000	0103000A	0003	0	0	0	000000000	0	0
eth0	0003000A	00000000	0001	0	0	0	00FFFFFF0	0	0

WITH this patch:

$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.0.3.1        0.0.0.0         UG        0 0          0 eth0
10.0.3.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0
$ cat /proc/net/route
Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask	MTU	Window	IRTT
eth0	00000000	0a000301	0003	0	0	0	000000000	0	0
eth0	0a000300	00000000	0001	0	0	0	ffffff000	0	0

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
Laurent Vivier 2013-08-30 01:46:40 +02:00 committed by Riku Voipio
parent 868e34d7bd
commit de6b993377

View File

@ -5071,22 +5071,70 @@ static int is_proc_myself(const char *filename, const char *entry)
return 0; return 0;
} }
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
static int is_proc(const char *filename, const char *entry)
{
return strcmp(filename, entry) == 0;
}
static int open_net_route(void *cpu_env, int fd)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/proc/net/route", "r");
if (fp == NULL) {
return -EACCES;
}
/* read header */
read = getline(&line, &len, fp);
dprintf(fd, "%s", line);
/* read routes */
while ((read = getline(&line, &len, fp)) != -1) {
char iface[16];
uint32_t dest, gw, mask;
unsigned int flags, refcnt, use, metric, mtu, window, irtt;
sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
iface, &dest, &gw, &flags, &refcnt, &use, &metric,
&mask, &mtu, &window, &irtt);
dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
metric, tswap32(mask), mtu, window, irtt);
}
free(line);
fclose(fp);
return 0;
}
#endif
static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{ {
struct fake_open { struct fake_open {
const char *filename; const char *filename;
int (*fill)(void *cpu_env, int fd); int (*fill)(void *cpu_env, int fd);
int (*cmp)(const char *s1, const char *s2);
}; };
const struct fake_open *fake_open; const struct fake_open *fake_open;
static const struct fake_open fakes[] = { static const struct fake_open fakes[] = {
{ "maps", open_self_maps }, { "maps", open_self_maps, is_proc_myself },
{ "stat", open_self_stat }, { "stat", open_self_stat, is_proc_myself },
{ "auxv", open_self_auxv }, { "auxv", open_self_auxv, is_proc_myself },
{ NULL, NULL } #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
{ "/proc/net/route", open_net_route, is_proc },
#endif
{ NULL, NULL, NULL }
}; };
for (fake_open = fakes; fake_open->filename; fake_open++) { for (fake_open = fakes; fake_open->filename; fake_open++) {
if (is_proc_myself(pathname, fake_open->filename)) { if (fake_open->cmp(pathname, fake_open->filename)) {
break; break;
} }
} }