diff options
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/ioctls.h | 6 | ||||
-rw-r--r-- | linux-user/syscall.c | 64 |
2 files changed, 68 insertions, 2 deletions
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8a4776756a..439c2a9e32 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 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__ } }, |