diff mbox

[2/7] linux-user: add SIOCADDRT/SIOCDELRT support

Message ID 7ff7b666186a86f0121e6e7db6784222cefe22a2.1373051589.git.riku.voipio@linaro.org
State New
Headers show

Commit Message

Riku Voipio July 10, 2013, 10:20 a.m. UTC
From: Laurent Vivier <laurent@vivier.eu>

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>
---
 linux-user/ioctls.h  |  6 +++--
 linux-user/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 8a47767..439c2a9 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -88,8 +88,6 @@ 
 #endif
 
   IOCTL(SIOCATMARK, 0, TYPE_NULL)
-  IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
-  IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
   IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
   IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
   IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
@@ -379,3 +377,7 @@ 
                 MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
   IOCTL_SPECIAL(DM_DEV_SET_GEOMETRY, IOC_RW, do_ioctl_dm,
                 MK_PTR(MK_STRUCT(STRUCT_dm_ioctl)))
+  IOCTL_SPECIAL(SIOCADDRT, IOC_W, do_ioctl_rt,
+                MK_PTR(MK_STRUCT(STRUCT_rtentry)))
+  IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt,
+                MK_PTR(MK_STRUCT(STRUCT_rtentry)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ed2c930..4b134dd 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__ } },