summaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2013-07-02 14:04:12 +0100
committerRiku Voipio <riku.voipio@linaro.org>2013-07-05 15:45:40 +0300
commit7ff7b666186a86f0121e6e7db6784222cefe22a2 (patch)
tree2964e8f4f315cafed504359f22f440f182908d5a /linux-user/syscall.c
parent463d8e7393681b300946d6bf9f9d5b7035d718c6 (diff)
downloadqemu-7ff7b666186a86f0121e6e7db6784222cefe22a2.tar.gz
linux-user: add SIOCADDRT/SIOCDELRT support
This allows to pass the device name. You can test this with the "route" command. WITHOUT this patch: $ sudo route add -net default gw 10.0.3.1 eth0 SIOCADDRT: Bad address $ netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Ifa 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth WITH this patch: $ sudo route add -net default gw 10.0.3.1 eth0 $ netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Ifa 0.0.0.0 10.0.3.1 0.0.0.0 UG 0 0 0 eth 10.0.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ed2c9305b1..4b134dda57 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -105,6 +105,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/vt.h>
#include <linux/dm-ioctl.h>
#include <linux/reboot.h>
+#include <linux/route.h>
#include "linux_loop.h"
#include "cpu-uname.h"
@@ -3551,6 +3552,69 @@ out:
return ret;
}
+static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
+ int fd, abi_long cmd, abi_long arg)
+{
+ const argtype *arg_type = ie->arg_type;
+ const StructEntry *se;
+ const argtype *field_types;
+ const int *dst_offsets, *src_offsets;
+ int target_size;
+ void *argptr;
+ abi_ulong *target_rt_dev_ptr;
+ unsigned long *host_rt_dev_ptr;
+ abi_long ret;
+ int i;
+
+ assert(ie->access == IOC_W);
+ assert(*arg_type == TYPE_PTR);
+ arg_type++;
+ assert(*arg_type == TYPE_STRUCT);
+ target_size = thunk_type_size(arg_type, 0);
+ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+ if (!argptr) {
+ return -TARGET_EFAULT;
+ }
+ arg_type++;
+ assert(*arg_type == (int)STRUCT_rtentry);
+ se = struct_entries + *arg_type++;
+ assert(se->convert[0] == NULL);
+ /* convert struct here to be able to catch rt_dev string */
+ field_types = se->field_types;
+ dst_offsets = se->field_offsets[THUNK_HOST];
+ src_offsets = se->field_offsets[THUNK_TARGET];
+ for (i = 0; i < se->nb_fields; i++) {
+ if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
+ assert(*field_types == TYPE_PTRVOID);
+ target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
+ host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
+ if (*target_rt_dev_ptr != 0) {
+ *host_rt_dev_ptr = (unsigned long)lock_user_string(
+ tswapal(*target_rt_dev_ptr));
+ if (!*host_rt_dev_ptr) {
+ unlock_user(argptr, arg, 0);
+ return -TARGET_EFAULT;
+ }
+ } else {
+ *host_rt_dev_ptr = 0;
+ }
+ field_types++;
+ continue;
+ }
+ field_types = thunk_convert(buf_temp + dst_offsets[i],
+ argptr + src_offsets[i],
+ field_types, THUNK_HOST);
+ }
+ unlock_user(argptr, arg, 0);
+
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (*host_rt_dev_ptr != 0) {
+ unlock_user((void *)*host_rt_dev_ptr,
+ *target_rt_dev_ptr, 0);
+ }
+ return ret;
+}
+
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },