Search Linux Wireless

[PATCH] wext: allow wext users without rtnl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch modifies wext adding a flag that allows drivers to specify that
they do not wish their wext calls made under rtnl. The default is to still
acquire the rtnl.

Warning: a device reference is held for the new no_locking API,
therefore it is not safe to call unregister_netdev on the passed device!

Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>

---
 include/net/iw_handler.h   |    3 +
 net/wireless/wext-common.c |    6 --
 net/wireless/wext-old.c    |  127 ++++++++++++++++++++++++---------------------
 3 files changed, 72 insertions(+), 64 deletions(-)

--- wireless-dev.orig/include/net/iw_handler.h	2007-04-13 23:20:56.755356880 +0200
+++ wireless-dev/include/net/iw_handler.h	2007-04-13 23:36:48.635356880 +0200
@@ -349,6 +349,9 @@ struct iw_handler_def
 	 * The old pointer in struct net_device will be gradually phased
 	 * out, and drivers are encouraged to use this one... */
 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
+
+	/* can live without rtnl locking? */
+	int no_locking;
 };
 
 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
--- wireless-dev.orig/net/wireless/wext-common.c	2007-04-13 23:20:56.785356880 +0200
+++ wireless-dev/net/wireless/wext-common.c	2007-04-13 23:36:48.635356880 +0200
@@ -631,15 +631,9 @@ int wext_ioctl(unsigned int cmd, struct 
 #ifdef CONFIG_WIRELESS_EXT
 	dev_load(ifr->ifr_name);
 
-	/* we could change the code to not hold the rtnl but
-	 * some callees might require it held */
-	rtnl_lock();
-
 	/* Follow me in wext-old.c */
 	ret = wireless_process_ioctl(ifr, cmd);
 
-	rtnl_unlock();
-
 	/* haha, I cheat here by allowing a driver or stack to have both WE and
 	 * CFG80211-WE for a little while during conversion... wext returns
 	 * -EOPNOTSUPP if a handler is not assigned, so we can in that case try
--- wireless-dev.orig/net/wireless/wext-old.c	2007-04-13 23:20:56.925356880 +0200
+++ wireless-dev/net/wireless/wext-old.c	2007-04-17 17:45:57.752028444 +0200
@@ -516,74 +516,85 @@ static inline int ioctl_private_call(str
 	return ret;
 }
 
-/* ---------------------------------------------------------------- */
+static int ioctl_call(struct net_device *dev, struct ifreq *ifr,
+		      unsigned int cmd, iw_handler handler)
+{
+	/* Standard and private are not the same */
+	if (cmd >= SIOCIWFIRSTPRIV)
+		return ioctl_private_call(dev, ifr, cmd, handler);
+
+	return ioctl_standard_call(dev, ifr, cmd, handler);
+}
+
+static int dev_process_ioctl(struct net_device *dev, struct ifreq *ifr,
+			     unsigned int cmd)
+{
+	iw_handler handler;
+
+	if (cmd == SIOCGIWSTATS) {
+		/* Get Wireless Stats */
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_iwstats);
+	}
+
+	if (cmd == SIOCGIWPRIV && dev->wireless_handlers) {
+		/* We export to user space the definition of
+		 * the private handler ourselves */
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_private);
+	}
+
+	/* Basic check */
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	/* New driver API : try to find the handler */
+	handler = get_handler(dev, cmd);
+	if (handler)
+		return ioctl_call(dev, ifr, cmd, handler);
+
+	/* Old driver API : call driver ioctl handler */
+	if (dev->do_ioctl)
+		return dev->do_ioctl(dev, ifr, cmd);
+
+	return -EOPNOTSUPP;
+}
+
 /*
- * Main IOCTl dispatcher. Called from the main networking code
- * (dev_ioctl() in net/core/dev.c).
- * Check the type of IOCTL and call the appropriate wrapper...
+ * Main ioctl dispatcher. Called from the common wireless code
+ * in net/wireless/wext-common.c.
  */
 int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
 {
 	struct net_device *dev;
-	iw_handler	handler;
+	int err;
 
-	/* Permissions are already checked in dev_ioctl() before calling us.
-	 * The copy_to/from_user() of ifr is also dealt with in there */
+	/* Get device reference so it doesn't go away */
+	dev = dev_get_by_name(ifr->ifr_name);
 
-	/* Make sure the device exist */
-	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+	if (!dev)
 		return -ENODEV;
 
-	/* A bunch of special cases, then the generic case...
-	 * Note that 'cmd' is already filtered in dev_ioctl() with
-	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
-	switch(cmd) {
-		case SIOCGIWSTATS:
-			/* Get Wireless Stats */
-			return ioctl_standard_call(dev,
-						   ifr,
-						   cmd,
-						   &iw_handler_get_iwstats);
-
-		case SIOCGIWPRIV:
-			/* Check if we have some wireless handlers defined */
-			if(dev->wireless_handlers != NULL) {
-				/* We export to user space the definition of
-				 * the private handler ourselves */
-				return ioctl_standard_call(dev,
-							   ifr,
-							   cmd,
-							   &iw_handler_get_private);
-			}
-			// ## Fall-through for old API ##
-		default:
-			/* Generic IOCTL */
-			/* Basic check */
-			if (!netif_device_present(dev))
-				return -ENODEV;
-			/* New driver API : try to find the handler */
-			handler = get_handler(dev, cmd);
-			if(handler != NULL) {
-				/* Standard and private are not the same */
-				if(cmd < SIOCIWFIRSTPRIV)
-					return ioctl_standard_call(dev,
-								   ifr,
-								   cmd,
-								   handler);
-				else
-					return ioctl_private_call(dev,
-								  ifr,
-								  cmd,
-								  handler);
-			}
-			/* Old driver API : call driver ioctl handler */
-			if (dev->do_ioctl) {
-				return dev->do_ioctl(dev, ifr, cmd);
-			}
-			return -EOPNOTSUPP;
+	/*
+	 * Check for the new no_locking API and if no locking is wanted then
+	 * call the handler without ever touching rtnl.
+	 * It needs to be this way to avoid ABBA type deadlocks.
+	 */
+	if (dev->wireless_handlers && dev->wireless_handlers->no_locking) {
+		err = dev_process_ioctl(dev, ifr, cmd);
+		dev_put(dev);
+	} else {
+		rtnl_lock();
+		/*
+		 * put device before calling handler, it might expect a
+		 * device with no held references in its own call path.
+		 */
+		dev_put(dev);
+		err = dev_process_ioctl(dev, ifr, cmd);
+		rtnl_unlock();
 	}
-	/* Not reached */
-	return -EINVAL;
+
+	return err;
 }
 
 /********************** ENHANCED IWSPY SUPPORT **********************/


-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux