diff options
author | Ian Dowse <iedowse@FreeBSD.org> | 2001-11-19 15:43:50 +0000 |
---|---|---|
committer | Ian Dowse <iedowse@FreeBSD.org> | 2001-11-19 15:43:50 +0000 |
commit | b0cb4883b11114ae2ae45397f997b49328f9e575 (patch) | |
tree | ca52f5c1cc767655fbdfdfd1f319579fc5996098 /sys/compat/linux/linux_ioctl.c | |
parent | 123f65b0e953adb37b37d2d194a02139c7a6ce36 (diff) | |
download | src-b0cb4883b11114ae2ae45397f997b49328f9e575.tar.gz src-b0cb4883b11114ae2ae45397f997b49328f9e575.zip |
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
Notes
Notes:
svn path=/head/; revision=86607
Diffstat (limited to 'sys/compat/linux/linux_ioctl.c')
-rw-r--r-- | sys/compat/linux/linux_ioctl.c | 83 |
1 files changed, 69 insertions, 14 deletions
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 83ee211b90a4..d3eea0d5de6e 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); } /* |