cfg80211: support creating wiphy with suggested name
authorBen Greear <greearb@candelatech.com>
Wed, 22 Oct 2014 19:23:00 +0000 (12:23 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 Oct 2014 07:48:18 +0000 (08:48 +0100)
Kernel will attempt to use the name if it is supplied,
but if name cannot be used for some reason, the default
phyX name will be used instead.

Signed-off-by: Ben Greear <greearb@candelatech.com>
[while at it, use wiphy_name() instead of dev_name(),
 fix format string issue reported by Kees Cook]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/wireless/core.c

index 77aa805d7e7c6cd3a0779d5ca2d4890ee3078f8d..39d7996b060901b0c23ad0743a756556d96c158d 100644 (file)
@@ -3184,6 +3184,23 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
        return dev_name(&wiphy->dev);
 }
 
+/**
+ * wiphy_new_nm - create a new wiphy for use with cfg80211
+ *
+ * @ops: The configuration operations for this device
+ * @sizeof_priv: The size of the private area to allocate
+ * @requested_name: Request a particular name.
+ *     NULL is valid value, and means use the default phy%d naming.
+ *
+ * Create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * Return: A pointer to the new wiphy. This pointer must be
+ * assigned to each netdev's ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+                          const char *requested_name);
+
 /**
  * wiphy_new - create a new wiphy for use with cfg80211
  *
@@ -3196,7 +3213,11 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
  * Return: A pointer to the new wiphy. This pointer must be
  * assigned to each netdev's ieee80211_ptr for proper operation.
  */
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
+static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
+                                     int sizeof_priv)
+{
+       return wiphy_new_nm(ops, sizeof_priv, NULL);
+}
 
 /**
  * wiphy_register - register a wiphy with cfg80211
index f52a4cd7017c855c1c64f9ee2bbe2b0b44b625cc..87bb502bc8deff94128d1782d101874342c18e77 100644 (file)
@@ -86,11 +86,11 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
        return &rdev->wiphy;
 }
 
-int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
-                       char *newname)
+static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev,
+                                  const char *newname)
 {
        struct cfg80211_registered_device *rdev2;
-       int wiphy_idx, taken = -1, result, digits;
+       int wiphy_idx, taken = -1, digits;
 
        ASSERT_RTNL();
 
@@ -109,15 +109,28 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        return -EINVAL;
        }
 
+       /* Ensure another device does not already have this name. */
+       list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+               if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0)
+                       return -EINVAL;
+
+       return 0;
+}
+
+int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
+                       char *newname)
+{
+       int result;
+
+       ASSERT_RTNL();
 
        /* Ignore nop renames */
-       if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+       if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0)
                return 0;
 
-       /* 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 -EINVAL;
+       result = cfg80211_dev_check_name(rdev, newname);
+       if (result < 0)
+               return result;
 
        result = device_rename(&rdev->wiphy.dev, newname);
        if (result)
@@ -309,7 +322,8 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
 
 /* exported functions */
 
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+                          const char *requested_name)
 {
        static atomic_t wiphy_counter = ATOMIC_INIT(0);
 
@@ -346,7 +360,31 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy_idx--;
 
        /* give it a proper name */
-       dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       if (requested_name && requested_name[0]) {
+               int rv;
+
+               rtnl_lock();
+               rv = cfg80211_dev_check_name(rdev, requested_name);
+
+               if (rv < 0) {
+                       rtnl_unlock();
+                       goto use_default_name;
+               }
+
+               rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name);
+               rtnl_unlock();
+               if (rv)
+                       goto use_default_name;
+       } else {
+use_default_name:
+               /* NOTE:  This is *probably* safe w/out holding rtnl because of
+                * the restrictions on phy names.  Probably this call could
+                * fail if some other part of the kernel (re)named a device
+                * phyX.  But, might should add some locking and check return
+                * value, and use a different name if this one exists?
+                */
+               dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       }
 
        INIT_LIST_HEAD(&rdev->wdev_list);
        INIT_LIST_HEAD(&rdev->beacon_registrations);
@@ -406,7 +444,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        return &rdev->wiphy;
 }
-EXPORT_SYMBOL(wiphy_new);
+EXPORT_SYMBOL(wiphy_new_nm);
 
 static int wiphy_verify_combinations(struct wiphy *wiphy)
 {