diff options
author | iedowse <iedowse@FreeBSD.org> | 2001-11-19 15:43:50 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2001-11-19 15:43:50 +0000 |
commit | a7c89cf1a83e437aca0b87219683aebe33f8146b (patch) | |
tree | ca52f5c1cc767655fbdfdfd1f319579fc5996098 /sys | |
parent | a9c3d65330ced3ef34a2a3a9aa5eac51e1383ec2 (diff) | |
download | FreeBSD-src-a7c89cf1a83e437aca0b87219683aebe33f8146b.zip FreeBSD-src-a7c89cf1a83e437aca0b87219683aebe33f8146b.tar.gz |
Deal with a few issues that cropped up following the recent changes
to the code for translating socket and private ioctls:
- Only perform socket ioctl translation if the file descriptor is a
socket.
- Treat socket ioctls on non-sockets specially, and for now assume
that these are directed at a tap/vmnet device, so translate the
ioctl numbers as appropriate (the way if_tap abuses some socket
ioctls to pass non-ifreq data is utterly bogus, but this is how
VMware on FreeBSD has always "worked"; I will deal with this
later).
- Add (untested) support for translating SIOCSIFADDR.
- In all cases where we fail to translate an ioctl, return ENOIOCTL
so that other handlers have a chance to do the translation.
This should fix the "/dev/vmnet1: Invalid argument" errors that
users of VMware were experiencing, though I have only verified this
on RELENG_4.
Submitted by: des (mostly)
MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/linux/linux_ioctl.c | 83 | ||||
-rw-r--r-- | sys/compat/linux/linux_ioctl.h | 1 |
2 files changed, 70 insertions, 14 deletions
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 83ee211..d3eea0d 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -67,6 +67,7 @@ static linux_ioctl_function_t linux_ioctl_socket; static linux_ioctl_function_t linux_ioctl_sound; static linux_ioctl_function_t linux_ioctl_termio; static linux_ioctl_function_t linux_ioctl_private; +static linux_ioctl_function_t linux_ioctl_special; static struct linux_ioctl_handler cdrom_handler = { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX }; @@ -1726,9 +1727,10 @@ linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) return (ENOIOCTL); } -#define IFP_IS_ETH(ifp) ((ifp->if_flags & \ - (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST)) == \ - IFF_BROADCAST) +/* + * Criteria for interface name translation + */ +#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) /* * Construct the Linux name for an interface @@ -1920,7 +1922,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) { char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ]; struct ifnet *ifp; - int error; + struct file *fp; + int error, type; KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ, (__FUNCTION__ "(): LINUX_IFNAMSIZ != IFNAMSIZ")); @@ -1928,6 +1931,27 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) ifp = NULL; error = 0; + mtx_lock(&Giant); + if ((error = fget(td, args->fd, &fp)) != 0) { + mtx_unlock(&Giant); + return (error); + } + type = fp->f_type; + fdrop(fp, td); + mtx_unlock(&Giant); + + if (type != DTYPE_SOCKET) { + /* not a socket - probably a tap / vmnet device */ + switch (args->cmd) { + case LINUX_SIOCGIFADDR: + case LINUX_SIOCSIFADDR: + case LINUX_SIOCGIFFLAGS: + return (linux_ioctl_special(td, args)); + default: + return (ENOIOCTL); + } + } + switch (args->cmd & 0xffff) { case LINUX_FIOGETOWN: @@ -1947,6 +1971,7 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) case LINUX_SIOCGIFFLAGS: case LINUX_SIOCGIFADDR: + case LINUX_SIOCSIFADDR: case LINUX_SIOCGIFDSTADDR: case LINUX_SIOCGIFBRDADDR: case LINUX_SIOCGIFNETMASK: @@ -2031,6 +2056,12 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) error = ioctl(td, (struct ioctl_args *)args); break; + case LINUX_SIOCSIFADDR: + /* XXX probably doesn't work, included for completeness */ + args->cmd = SIOCSIFADDR; + error = ioctl(td, (struct ioctl_args *)args); + break; + case LINUX_SIOCGIFDSTADDR: args->cmd = OSIOCGIFDSTADDR; error = ioctl(td, (struct ioctl_args *)args); @@ -2113,24 +2144,48 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) static int linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) { - struct filedesc *fdp; struct file *fp; - int type; + int error, type; - /* XXX is it sufficient to PROC_LOCK td->td_proc? */ mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - if (args->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[args->fd]) == NULL) { + if ((error = fget(td, args->fd, &fp)) != 0) { mtx_unlock(&Giant); - return (EBADF); - } else { - type = fp->f_type; + return (error); } + type = fp->f_type; + fdrop(fp, td); mtx_unlock(&Giant); if (type == DTYPE_SOCKET) return (linux_ioctl_socket(td, args)); - return (ioctl(td, (struct ioctl_args *)args)); + return (ENOIOCTL); +} + +/* + * Special ioctl handler + */ +static int +linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args) +{ + int error; + + switch (args->cmd) { + case LINUX_SIOCGIFADDR: + args->cmd = SIOCGIFADDR; + error = ioctl(td, (struct ioctl_args *)args); + break; + case LINUX_SIOCSIFADDR: + args->cmd = SIOCSIFADDR; + error = ioctl(td, (struct ioctl_args *)args); + break; + case LINUX_SIOCGIFFLAGS: + args->cmd = SIOCGIFFLAGS; + error = ioctl(td, (struct ioctl_args *)args); + break; + default: + error = ENOIOCTL; + } + + return (error); } /* diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 59ffed7..0d77e0d 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -166,6 +166,7 @@ #define LINUX_SIOCGIFCONF 0x8912 #define LINUX_SIOCGIFFLAGS 0x8913 #define LINUX_SIOCGIFADDR 0x8915 +#define LINUX_SIOCSIFADDR 0x8916 #define LINUX_SIOCGIFDSTADDR 0x8917 #define LINUX_SIOCGIFBRDADDR 0x8919 #define LINUX_SIOCGIFNETMASK 0x891b |