summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-10-11 14:46:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-11 14:46:52 -0400
commit7623225f905263424c7254dc6a07bff083a498dd (patch)
tree804b483a7aa2c2ad373fbe2e9b30844dea5c886c /net
parentd86a4f2dd4ec554cf3346f4cab763925761c4095 (diff)
downloadlinux-7623225f905263424c7254dc6a07bff083a498dd.tar.gz
linux-7623225f905263424c7254dc6a07bff083a498dd.tar.bz2
linux-7623225f905263424c7254dc6a07bff083a498dd.zip
Revert "wireless: Use first phyX name available when registering phy devices."
This reverts commit 5a254ffe3ffdfa84fe076009bd8e88da412180d2. The commit failed to take into account that allocated wireless devices (wiphys) are not added into the device list upon allocation, but only when they are registered. Therefore, it opened up a race between allocating and registering a name, so that if two processes allocate and register concurrently ("alloc, alloc, register, register" rather than "alloc, register, alloc, register") the code will attempt to use the same name twice. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.c54
1 files changed, 24 insertions, 30 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 1684ad91763c..9c21ebf9780e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -178,10 +178,26 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
struct cfg80211_registered_device *rdev2;
- int result;
+ int wiphy_idx, taken = -1, result, digits;
assert_cfg80211_lock();
+ /* prohibit calling the thing phy%d when %d is not its number */
+ sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
+ if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
+ /* count number of places needed to print wiphy_idx */
+ digits = 1;
+ while (wiphy_idx /= 10)
+ digits++;
+ /*
+ * deny the name if it is phy<idx> where <idx> is printed
+ * without leading zeroes. taken == strlen(newname) here
+ */
+ if (taken == strlen(PHY_NAME) + digits)
+ return -EINVAL;
+ }
+
+
/* Ignore nop renames */
if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
return 0;
@@ -189,7 +205,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
/* Ensure another device does not already have this name. */
list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
- return -EEXIST;
+ return -EINVAL;
result = device_rename(&rdev->wiphy.dev, newname);
if (result)
@@ -304,11 +320,9 @@ static void cfg80211_event_work(struct work_struct *work)
struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
{
static int wiphy_counter;
- int i;
- struct cfg80211_registered_device *rdev, *rdev2;
+
+ struct cfg80211_registered_device *rdev;
int alloc_size;
- char nname[IFNAMSIZ + 1];
- bool found = false;
WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
@@ -332,37 +346,17 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) {
wiphy_counter--;
- goto too_many_devs;
- }
-
- /* 64k wiphy devices is enough for anyone! */
- for (i = 0; i < 0xFFFF; i++) {
- found = false;
- snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i);
- nname[sizeof(nname)-1] = 0;
- list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
- if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) {
- found = true;
- break;
- }
-
- if (!found)
- break;
- }
-
- if (unlikely(found)) {
-too_many_devs:
mutex_unlock(&cfg80211_mutex);
- /* ugh, too many devices already! */
+ /* ugh, wrapped! */
kfree(rdev);
return NULL;
}
- /* give it a proper name */
- dev_set_name(&rdev->wiphy.dev, "%s", nname);
-
mutex_unlock(&cfg80211_mutex);
+ /* give it a proper name */
+ dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+
mutex_init(&rdev->mtx);
mutex_init(&rdev->devlist_mtx);
INIT_LIST_HEAD(&rdev->netdev_list);