aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_ioctl.c
diff options
context:
space:
mode:
authorIan Dowse <iedowse@FreeBSD.org>2001-11-19 15:43:50 +0000
committerIan Dowse <iedowse@FreeBSD.org>2001-11-19 15:43:50 +0000
commitb0cb4883b11114ae2ae45397f997b49328f9e575 (patch)
treeca52f5c1cc767655fbdfdfd1f319579fc5996098 /sys/compat/linux/linux_ioctl.c
parent123f65b0e953adb37b37d2d194a02139c7a6ce36 (diff)
downloadsrc-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.c83
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);
}
/*