All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing
@ 2009-02-20  5:42 Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 01/15] cfg80211: rename cfg80211_registered_device's idx to wiphy_idx Luis R. Rodriguez
                   ` (15 more replies)
  0 siblings, 16 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

This series has a few cleanups and minor fixes but mainly
adds a workqueue for cfg80211 to use to process all regulatory
hints. This v5 addresses one last comment from Johannes to remove
an unlikely() as a WARN_ON() already has it and most importantly
we do not call a spin_lock() before the cfg80211_mutex.

Luis R. Rodriguez (15):
  cfg80211: rename cfg80211_registered_device's idx to wiphy_idx
  cfg80211: add wiphy_idx_valid to check for wiphy_idx sanity
  cfg80211: rename cfg80211_drv_mutex to cfg80211_mutex
  nl80211: disallow user requests prior to regulatory_init()
  cfg80211: add regulatory_hint_core() to separate the core reg hint
  cfg80211: propagate -ENOMEM during regulatory_init()
  cfg80211: add assert_cfg80211_lock() to ensure proper protection
  cfg80211: make regulatory_request use wiphy_idx instead of wiphy
  cfg80211: protect first access of last_request on 11d hint under
    mutex
  cfg80211: remove likely from an 11d hint case
  cfg80211: free rd on unlikely event on 11d hint
  cfg80211: move all regulatory hints to workqueue
  cfg80211: comments style cleanup
  cfg80211: allow drivers that agree on regulatory to agree
  cfg80211: rename regdom_changed to regdom_changes() and use it

 drivers/net/wireless/ath9k/main.c      |    8 +-
 drivers/net/wireless/zd1211rw/zd_mac.c |    6 +-
 include/net/cfg80211.h                 |    8 +-
 include/net/wireless.h                 |    9 +-
 net/wireless/core.c                    |  102 ++++--
 net/wireless/core.h                    |   33 ++-
 net/wireless/nl80211.c                 |   47 ++-
 net/wireless/reg.c                     |  665 +++++++++++++++++++++++--------
 net/wireless/reg.h                     |    2 +
 net/wireless/sysfs.c                   |    2 +-
 10 files changed, 644 insertions(+), 238 deletions(-)


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v5 01/15] cfg80211: rename cfg80211_registered_device's idx to wiphy_idx
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 02/15] cfg80211: add wiphy_idx_valid to check for wiphy_idx sanity Luis R. Rodriguez
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

Makes it clearer to read when comparing to ifidx

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/core.c    |   35 ++++++++++++++++++-----------------
 net/wireless/core.h    |    2 +-
 net/wireless/nl80211.c |    4 ++--
 net/wireless/sysfs.c   |    2 +-
 4 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 0668b2b..2b3e786 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -37,12 +37,13 @@ DEFINE_MUTEX(cfg80211_drv_mutex);
 static struct dentry *ieee80211_debugfs_dir;
 
 /* requires cfg80211_drv_mutex to be held! */
-static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)
+static struct cfg80211_registered_device *
+cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 {
 	struct cfg80211_registered_device *result = NULL, *drv;
 
 	list_for_each_entry(drv, &cfg80211_drv_list, list) {
-		if (drv->idx == wiphy) {
+		if (drv->wiphy_idx == wiphy_idx) {
 			result = drv;
 			break;
 		}
@@ -56,12 +57,12 @@ static struct cfg80211_registered_device *
 __cfg80211_drv_from_info(struct genl_info *info)
 {
 	int ifindex;
-	struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;
+	struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
 	struct net_device *dev;
 	int err = -EINVAL;
 
 	if (info->attrs[NL80211_ATTR_WIPHY]) {
-		bywiphy = cfg80211_drv_by_wiphy(
+		bywiphyidx = cfg80211_drv_by_wiphy_idx(
 				nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
 		err = -ENODEV;
 	}
@@ -78,14 +79,14 @@ __cfg80211_drv_from_info(struct genl_info *info)
 		err = -ENODEV;
 	}
 
-	if (bywiphy && byifidx) {
-		if (bywiphy != byifidx)
+	if (bywiphyidx && byifidx) {
+		if (bywiphyidx != byifidx)
 			return ERR_PTR(-EINVAL);
 		else
-			return bywiphy; /* == byifidx */
+			return bywiphyidx; /* == byifidx */
 	}
-	if (bywiphy)
-		return bywiphy;
+	if (bywiphyidx)
+		return bywiphyidx;
 
 	if (byifidx)
 		return byifidx;
@@ -143,16 +144,16 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 			char *newname)
 {
 	struct cfg80211_registered_device *drv;
-	int idx, taken = -1, result, digits;
+	int wiphy_idx, taken = -1, result, digits;
 
 	mutex_lock(&cfg80211_drv_mutex);
 
 	/* prohibit calling the thing phy%d when %d is not its number */
-	sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
-	if (taken == strlen(newname) && idx != rdev->idx) {
-		/* count number of places needed to print idx */
+	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 (idx /= 10)
+		while (wiphy_idx /= 10)
 			digits++;
 		/*
 		 * deny the name if it is phy<idx> where <idx> is printed
@@ -222,9 +223,9 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 
 	mutex_lock(&cfg80211_drv_mutex);
 
-	drv->idx = wiphy_counter++;
+	drv->wiphy_idx = wiphy_counter++;
 
-	if (unlikely(drv->idx < 0)) {
+	if (unlikely(drv->wiphy_idx < 0)) {
 		wiphy_counter--;
 		mutex_unlock(&cfg80211_drv_mutex);
 		/* ugh, wrapped! */
@@ -235,7 +236,7 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 	mutex_unlock(&cfg80211_drv_mutex);
 
 	/* give it a proper name */
-	dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx);
+	dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
 
 	mutex_init(&drv->mtx);
 	mutex_init(&drv->devlist_mtx);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5d0c682..1783781 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -37,7 +37,7 @@ struct cfg80211_registered_device {
 	enum environment_cap env;
 
 	/* wiphy index, internal only */
-	int idx;
+	int wiphy_idx;
 
 	/* associate netdev list */
 	struct mutex devlist_mtx;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c157d60..7bc4d16 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -163,7 +163,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 	if (!hdr)
 		return -1;
 
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 	NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
 		   dev->wiphy.max_scan_ssids);
@@ -2729,7 +2729,7 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
 	if (!hdr)
 		return -1;
 
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 
 	/* XXX: we should probably bounce back the request? */
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 15feaeb..efe3c5c 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -31,7 +31,7 @@ static ssize_t name ## _show(struct device *dev,			\
 	return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);	\
 }
 
-SHOW_FMT(index, "%d", idx);
+SHOW_FMT(index, "%d", wiphy_idx);
 SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
 
 static struct device_attribute ieee80211_dev_attrs[] = {
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 02/15] cfg80211: add wiphy_idx_valid to check for wiphy_idx sanity
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 01/15] cfg80211: rename cfg80211_registered_device's idx to wiphy_idx Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 03/15] cfg80211: rename cfg80211_drv_mutex to cfg80211_mutex Luis R. Rodriguez
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

This will later be used by others, for now make use of it in
cfg80211_drv_by_wiphy_idx() to return early if an invalid
wiphy_idx has been provided.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/core.c |    5 ++++-
 net/wireless/core.h |    7 +++++++
 2 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 2b3e786..35d457b 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -42,6 +42,9 @@ cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 {
 	struct cfg80211_registered_device *result = NULL, *drv;
 
+	if (!wiphy_idx_valid(wiphy_idx))
+		return NULL;
+
 	list_for_each_entry(drv, &cfg80211_drv_list, list) {
 		if (drv->wiphy_idx == wiphy_idx) {
 			result = drv;
@@ -225,7 +228,7 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 
 	drv->wiphy_idx = wiphy_counter++;
 
-	if (unlikely(drv->wiphy_idx < 0)) {
+	if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
 		wiphy_counter--;
 		mutex_unlock(&cfg80211_drv_mutex);
 		/* ugh, wrapped! */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 1783781..4f2e0fe 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -63,6 +63,13 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
 	return container_of(wiphy, struct cfg80211_registered_device, wiphy);
 }
 
+/* Note 0 is valid, hence phy0 */
+static inline
+bool wiphy_idx_valid(int wiphy_idx)
+{
+	return (wiphy_idx >= 0);
+}
+
 extern struct mutex cfg80211_drv_mutex;
 extern struct list_head cfg80211_drv_list;
 
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 03/15] cfg80211: rename cfg80211_drv_mutex to cfg80211_mutex
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 01/15] cfg80211: rename cfg80211_registered_device's idx to wiphy_idx Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 02/15] cfg80211: add wiphy_idx_valid to check for wiphy_idx sanity Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 04/15] nl80211: disallow user requests prior to regulatory_init() Luis R. Rodriguez
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

cfg80211_drv_mutex is protecting more than the driver list,
this renames it and documents what its currently supposed to
protect.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/core.c    |   35 ++++++++++++++++++++---------------
 net/wireless/core.h    |    6 +++---
 net/wireless/nl80211.c |   20 ++++++++++----------
 net/wireless/reg.c     |   18 +++++++++---------
 4 files changed, 42 insertions(+), 37 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 35d457b..39d40d1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -31,7 +31,12 @@ MODULE_DESCRIPTION("wireless configuration support");
  * only read the list, and that can happen quite
  * often because we need to do it for each command */
 LIST_HEAD(cfg80211_drv_list);
-DEFINE_MUTEX(cfg80211_drv_mutex);
+
+/*
+ * This is used to protect the cfg80211_drv_list, cfg80211_regdomain, and
+ * the last reguluatory request receipt in regd.c
+ */
+DEFINE_MUTEX(cfg80211_mutex);
 
 /* for debugfs */
 static struct dentry *ieee80211_debugfs_dir;
@@ -55,7 +60,7 @@ cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 	return result;
 }
 
-/* requires cfg80211_drv_mutex to be held! */
+/* requires cfg80211_mutex to be held! */
 static struct cfg80211_registered_device *
 __cfg80211_drv_from_info(struct genl_info *info)
 {
@@ -102,7 +107,7 @@ cfg80211_get_dev_from_info(struct genl_info *info)
 {
 	struct cfg80211_registered_device *drv;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	drv = __cfg80211_drv_from_info(info);
 
 	/* if it is not an error we grab the lock on
@@ -111,7 +116,7 @@ cfg80211_get_dev_from_info(struct genl_info *info)
 	if (!IS_ERR(drv))
 		mutex_lock(&drv->mtx);
 
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 
 	return drv;
 }
@@ -122,7 +127,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
 	struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
 	struct net_device *dev;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	dev = dev_get_by_index(&init_net, ifindex);
 	if (!dev)
 		goto out;
@@ -133,7 +138,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
 		drv = ERR_PTR(-ENODEV);
 	dev_put(dev);
  out:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	return drv;
 }
 
@@ -149,7 +154,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 	struct cfg80211_registered_device *drv;
 	int wiphy_idx, taken = -1, result, digits;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	/* prohibit calling the thing phy%d when %d is not its number */
 	sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
@@ -197,7 +202,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 
 	result = 0;
 out_unlock:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	if (result == 0)
 		nl80211_notify_dev_rename(rdev);
 
@@ -224,19 +229,19 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 
 	drv->ops = ops;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	drv->wiphy_idx = wiphy_counter++;
 
 	if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
 		wiphy_counter--;
-		mutex_unlock(&cfg80211_drv_mutex);
+		mutex_unlock(&cfg80211_mutex);
 		/* ugh, wrapped! */
 		kfree(drv);
 		return NULL;
 	}
 
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 
 	/* give it a proper name */
 	dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
@@ -314,7 +319,7 @@ int wiphy_register(struct wiphy *wiphy)
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
@@ -334,7 +339,7 @@ int wiphy_register(struct wiphy *wiphy)
 
 	res = 0;
 out_unlock:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	return res;
 }
 EXPORT_SYMBOL(wiphy_register);
@@ -344,7 +349,7 @@ void wiphy_unregister(struct wiphy *wiphy)
 	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 
 	/* protect the device list */
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	BUG_ON(!list_empty(&drv->netdev_list));
 
@@ -370,7 +375,7 @@ void wiphy_unregister(struct wiphy *wiphy)
 	device_del(&drv->wiphy.dev);
 	debugfs_remove(drv->wiphy.debugfsdir);
 
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(wiphy_unregister);
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 4f2e0fe..f3ab00c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -70,7 +70,7 @@ bool wiphy_idx_valid(int wiphy_idx)
 	return (wiphy_idx >= 0);
 }
 
-extern struct mutex cfg80211_drv_mutex;
+extern struct mutex cfg80211_mutex;
 extern struct list_head cfg80211_drv_list;
 
 struct cfg80211_internal_bss {
@@ -89,13 +89,13 @@ struct cfg80211_internal_bss {
  * the driver's mutex!
  *
  * This means that you need to call cfg80211_put_dev()
- * before being allowed to acquire &cfg80211_drv_mutex!
+ * before being allowed to acquire &cfg80211_mutex!
  *
  * This is necessary because we need to lock the global
  * mutex to get an item off the list safely, and then
  * we lock the drv mutex so it doesn't go away under us.
  *
- * We don't want to keep cfg80211_drv_mutex locked
+ * We don't want to keep cfg80211_mutex locked
  * for all the time in order to allow requests on
  * other interfaces to go through at the same time.
  *
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7bc4d16..8d38609 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -277,7 +277,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 	int start = cb->args[0];
 	struct cfg80211_registered_device *dev;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	list_for_each_entry(dev, &cfg80211_drv_list, list) {
 		if (++idx <= start)
 			continue;
@@ -288,7 +288,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 			break;
 		}
 	}
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 
 	cb->args[0] = idx;
 
@@ -491,7 +491,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 	struct cfg80211_registered_device *dev;
 	struct wireless_dev *wdev;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	list_for_each_entry(dev, &cfg80211_drv_list, list) {
 		if (wp_idx < wp_start) {
 			wp_idx++;
@@ -518,7 +518,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 		wp_idx++;
 	}
  out:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 
 	cb->args[0] = wp_idx;
 	cb->args[1] = if_idx;
@@ -1892,9 +1892,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 	if (is_world_regdom(data))
 		return -EINVAL;
 #endif
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	/* This means the regulatory domain was already set, however
 	 * we don't want to confuse userspace with a "successful error"
 	 * message so lets just treat it as a success */
@@ -2084,7 +2084,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
 	unsigned int i;
 	int err = -EINVAL;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	if (!cfg80211_regdomain)
 		goto out;
@@ -2147,7 +2147,7 @@ nla_put_failure:
 	genlmsg_cancel(msg, hdr);
 	err = -EMSGSIZE;
 out:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	return err;
 }
 
@@ -2206,9 +2206,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 
 	BUG_ON(rule_idx != num_rules);
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	r = set_regdom(rd);
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 	return r;
 
  bad_reg:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2323644..ba82312 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1116,7 +1116,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 	return -EINVAL;
 }
 
-/* Caller must hold &cfg80211_drv_mutex */
+/* Caller must hold &cfg80211_mutex */
 int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
 			const char *alpha2,
 			u32 country_ie_checksum,
@@ -1188,13 +1188,13 @@ void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 	int r;
 	BUG_ON(!alpha2);
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 	r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,
 		alpha2, 0, ENVIRON_ANY);
 	/* This is required so that the orig_* parameters are saved */
 	if (r == -EALREADY && wiphy->strict_regulatory)
 		wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(regulatory_hint);
 
@@ -1225,7 +1225,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	if (!last_request)
 		return;
 
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	/* IE len must be evenly divisible by 2 */
 	if (country_ie_len & 0x01)
@@ -1307,7 +1307,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 		country_ie_regdomain->alpha2, checksum, env);
 
 out:
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(regulatory_hint_11d);
 
@@ -1562,7 +1562,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 
 /* Use this call to set the current regulatory domain. Conflicts with
  * multiple drivers can be ironed out later. Caller must've already
- * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */
+ * kmalloc'd the rd structure. Caller must hold cfg80211_mutex */
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
 	int r;
@@ -1586,7 +1586,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 	return r;
 }
 
-/* Caller must hold cfg80211_drv_mutex */
+/* Caller must hold cfg80211_mutex */
 void reg_device_remove(struct wiphy *wiphy)
 {
 	kfree(wiphy->regd);
@@ -1633,7 +1633,7 @@ int regulatory_init(void)
 
 void regulatory_exit(void)
 {
-	mutex_lock(&cfg80211_drv_mutex);
+	mutex_lock(&cfg80211_mutex);
 
 	reset_regdomains();
 
@@ -1644,5 +1644,5 @@ void regulatory_exit(void)
 
 	platform_device_unregister(reg_pdev);
 
-	mutex_unlock(&cfg80211_drv_mutex);
+	mutex_unlock(&cfg80211_mutex);
 }
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 04/15] nl80211: disallow user requests prior to regulatory_init()
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (2 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 03/15] cfg80211: rename cfg80211_drv_mutex to cfg80211_mutex Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 05/15] cfg80211: add regulatory_hint_core() to separate the core reg hint Luis R. Rodriguez
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

If cfg80211 is built into the kernel there is perhaps a small
time window betwen nl80211_init() and regulatory_init() where
cfg80211_regdomain hasn't yet been initialized to let the
wireless core do its work. During that rare case and time
frame (if its even possible) we don't allow user regulatory
changes as cfg80211 is working on enabling its first regulatory
domain.

To check for cfg80211_regdomain we now contend the entire operation
using the cfg80211_mutex.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/nl80211.c |   34 ++++++++++++++++++++++++++--------
 1 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8d38609..c99f0be 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1882,24 +1882,42 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 	int r;
 	char *data = NULL;
 
-	if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
-		return -EINVAL;
+	/*
+	 * You should only get this when cfg80211 hasn't yet initialized
+	 * completely when built-in to the kernel right between the time
+	 * window between nl80211_init() and regulatory_init(), if that is
+	 * even possible.
+	 */
+	mutex_lock(&cfg80211_mutex);
+	if (unlikely(!cfg80211_regdomain)) {
+		r = -EINPROGRESS;
+		goto out;
+	}
+
+	if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) {
+		r = -EINVAL;
+		goto out;
+	}
 
 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 
 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
 	/* We ignore world regdom requests with the old regdom setup */
-	if (is_world_regdom(data))
-		return -EINVAL;
+	if (is_world_regdom(data)) {
+		r = -EINVAL;
+		goto out;
+	}
 #endif
-	mutex_lock(&cfg80211_mutex);
 	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
-	mutex_unlock(&cfg80211_mutex);
-	/* This means the regulatory domain was already set, however
+	/*
+	 * This means the regulatory domain was already set, however
 	 * we don't want to confuse userspace with a "successful error"
-	 * message so lets just treat it as a success */
+	 * message so lets just treat it as a success
+	 */
 	if (r == -EALREADY)
 		r = 0;
+out:
+	mutex_unlock(&cfg80211_mutex);
 	return r;
 }
 
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 05/15] cfg80211: add regulatory_hint_core() to separate the core reg hint
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (3 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 04/15] nl80211: disallow user requests prior to regulatory_init() Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 06/15] cfg80211: propagate -ENOMEM during regulatory_init() Luis R. Rodriguez
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

This makes the core hint path more readable and allows for us to
later make it obvious under what circumstances we need locking or not.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |   34 +++++++++++++++++++++++++---------
 1 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index ba82312..6373a78 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1050,11 +1050,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 	case REGDOM_SET_BY_INIT:
 		return -EINVAL;
 	case REGDOM_SET_BY_CORE:
-		/*
-		 * Always respect new wireless core hints, should only happen
-		 * when updating the world regulatory domain at init.
-		 */
-		return 0;
+		return -EINVAL;
 	case REGDOM_SET_BY_COUNTRY_IE:
 		if (unlikely(!is_an_alpha2(alpha2)))
 			return -EINVAL;
@@ -1183,6 +1179,26 @@ new_request:
 	return call_crda(alpha2);
 }
 
+static int regulatory_hint_core(const char *alpha2)
+{
+	struct regulatory_request *request;
+
+	BUG_ON(last_request);
+
+	request = kzalloc(sizeof(struct regulatory_request),
+			  GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
+	request->initiator = REGDOM_SET_BY_CORE;
+
+	last_request = request;
+
+	return call_crda(alpha2);
+}
+
 void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
 {
 	int r;
@@ -1616,16 +1632,16 @@ int regulatory_init(void)
 	 * stuck with the static values. We ignore "EU" code as
 	 * that is not a valid ISO / IEC 3166 alpha2 */
 	if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
-		err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
-					ieee80211_regdom, 0, ENVIRON_ANY);
+		err = regulatory_hint_core(ieee80211_regdom);
 #else
 	cfg80211_regdomain = cfg80211_world_regdom;
 
-	err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
-	if (err)
+	err = regulatory_hint_core("00");
+	if (err) {
 		printk(KERN_ERR "cfg80211: calling CRDA failed - "
 		       "unable to update world regulatory domain, "
 		       "using static definition\n");
+	}
 #endif
 
 	return 0;
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 06/15] cfg80211: propagate -ENOMEM during regulatory_init()
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (4 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 05/15] cfg80211: add regulatory_hint_core() to separate the core reg hint Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 07/15] cfg80211: add assert_cfg80211_lock() to ensure proper protection Luis R. Rodriguez
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez, Greg KH

Calling kobject_uevent_env() can fail mainly due to out of
memory conditions. We do not want to continue during such
conditions so propagate that as well instead of letting
cfg80211 load as if everything is peachy.

Additionally lets clarify that when CRDA is not called during
cfg80211's initialization _and_ if the error is not an -ENOMEM
its because kobject_uevent_env() failed to call CRDA, not because
CRDA failed. For those who want to find out why we also let you
do so by enabling the kernel config CONFIG_CFG80211_REG_DEBUG --
you'll get an actual stack trace.

So for now we'll treat non -ENOMEM kobject_uevent_env() failures as
non fatal during cfg80211's initialization.

CC: Greg KH <greg@kroah.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6373a78..47d5056 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1616,7 +1616,7 @@ void reg_device_remove(struct wiphy *wiphy)
 
 int regulatory_init(void)
 {
-	int err;
+	int err = 0;
 
 	reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
 	if (IS_ERR(reg_pdev))
@@ -1637,12 +1637,24 @@ int regulatory_init(void)
 	cfg80211_regdomain = cfg80211_world_regdom;
 
 	err = regulatory_hint_core("00");
+#endif
 	if (err) {
-		printk(KERN_ERR "cfg80211: calling CRDA failed - "
-		       "unable to update world regulatory domain, "
-		       "using static definition\n");
-	}
+		if (err == -ENOMEM)
+			return err;
+		/*
+		 * N.B. kobject_uevent_env() can fail mainly for when we're out
+		 * memory which is handled and propagated appropriately above
+		 * but it can also fail during a netlink_broadcast() or during
+		 * early boot for call_usermodehelper(). For now treat these
+		 * errors as non-fatal.
+		 */
+		printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable "
+			"to call CRDA during init");
+#ifdef CONFIG_CFG80211_REG_DEBUG
+		/* We want to find out exactly why when debugging */
+		WARN_ON(err);
 #endif
+	}
 
 	return 0;
 }
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 07/15] cfg80211: add assert_cfg80211_lock() to ensure proper protection
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (5 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 06/15] cfg80211: propagate -ENOMEM during regulatory_init() Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 08/15] cfg80211: make regulatory_request use wiphy_idx instead of wiphy Luis R. Rodriguez
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/core.c    |    5 ++++-
 net/wireless/core.h    |    6 ++++++
 net/wireless/nl80211.c |    3 ++-
 net/wireless/reg.c     |   15 +++++++++++++++
 4 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 39d40d1..e347093 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -7,7 +7,6 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/nl80211.h>
 #include <linux/debugfs.h>
@@ -50,6 +49,8 @@ cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 	if (!wiphy_idx_valid(wiphy_idx))
 		return NULL;
 
+	assert_cfg80211_lock();
+
 	list_for_each_entry(drv, &cfg80211_drv_list, list) {
 		if (drv->wiphy_idx == wiphy_idx) {
 			result = drv;
@@ -69,6 +70,8 @@ __cfg80211_drv_from_info(struct genl_info *info)
 	struct net_device *dev;
 	int err = -EINVAL;
 
+	assert_cfg80211_lock();
+
 	if (info->attrs[NL80211_ATTR_WIPHY]) {
 		bywiphyidx = cfg80211_drv_by_wiphy_idx(
 				nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f3ab00c..982cc6b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -10,6 +10,7 @@
 #include <linux/netdevice.h>
 #include <linux/kref.h>
 #include <linux/rbtree.h>
+#include <linux/mutex.h>
 #include <net/genetlink.h>
 #include <net/wireless.h>
 #include <net/cfg80211.h>
@@ -73,6 +74,11 @@ bool wiphy_idx_valid(int wiphy_idx)
 extern struct mutex cfg80211_mutex;
 extern struct list_head cfg80211_drv_list;
 
+static inline void assert_cfg80211_lock(void)
+{
+	BUG_ON(!mutex_is_locked(&cfg80211_mutex));
+}
+
 struct cfg80211_internal_bss {
 	struct list_head list;
 	struct rb_node rbn;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c99f0be..0b8f811 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7,7 +7,6 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/if_ether.h>
 #include <linux/ieee80211.h>
@@ -159,6 +158,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 	int i;
 	u16 ifmodes = dev->wiphy.interface_modes;
 
+	assert_cfg80211_lock();
+
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
 		return -1;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 47d5056..e49ac9b 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -276,6 +276,8 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
 
 static bool regdom_changed(const char *alpha2)
 {
+	assert_cfg80211_lock();
+
 	if (!cfg80211_regdomain)
 		return true;
 	if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
@@ -830,6 +832,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
 
+	assert_cfg80211_lock();
+
 	sband = wiphy->bands[band];
 	BUG_ON(chan_idx >= sband->n_channels);
 	chan = &sband->channels[chan_idx];
@@ -1042,6 +1046,9 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
 static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 			  const char *alpha2)
 {
+
+	assert_cfg80211_lock();
+
 	/* All initial requests are respected */
 	if (!last_request)
 		return 0;
@@ -1122,6 +1129,8 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
 	bool intersect = false;
 	int r = 0;
 
+	assert_cfg80211_lock();
+
 	r = ignore_request(wiphy, set_by, alpha2);
 
 	if (r == REG_INTERSECT) {
@@ -1217,6 +1226,8 @@ EXPORT_SYMBOL(regulatory_hint);
 static bool reg_same_country_ie_hint(struct wiphy *wiphy,
 			u32 country_ie_checksum)
 {
+	assert_cfg80211_lock();
+
 	if (!last_request->wiphy)
 		return false;
 	if (likely(last_request->wiphy != wiphy))
@@ -1583,6 +1594,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 {
 	int r;
 
+	assert_cfg80211_lock();
+
 	/* Note that this doesn't update the wiphys, this is done below */
 	r = __set_regdom(rd);
 	if (r) {
@@ -1605,6 +1618,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 /* Caller must hold cfg80211_mutex */
 void reg_device_remove(struct wiphy *wiphy)
 {
+	assert_cfg80211_lock();
+
 	kfree(wiphy->regd);
 	if (!last_request || !last_request->wiphy)
 		return;
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 08/15] cfg80211: make regulatory_request use wiphy_idx instead of wiphy
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (6 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 07/15] cfg80211: add assert_cfg80211_lock() to ensure proper protection Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 09/15] cfg80211: protect first access of last_request on 11d hint under mutex Luis R. Rodriguez
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

We do this so later on we can move the pending requests onto a
workqueue. By using the wiphy_idx instead of the wiphy we can
later easily check if the wiphy has disappeared or not.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 include/net/cfg80211.h |    6 ++--
 net/wireless/core.c    |   30 ++++++++++++++++++++--
 net/wireless/core.h    |   12 +++++++++
 net/wireless/reg.c     |   64 ++++++++++++++++++++++++++++++------------------
 4 files changed, 82 insertions(+), 30 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 43ac90d..bb9129f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -383,9 +383,9 @@ enum environment_cap {
 };
 
 /**
- * struct regulatory_request - receipt of last regulatory request
+ * struct regulatory_request - used to keep track of regulatory requests
  *
- * @wiphy: this is set if this request's initiator is
+ * @wiphy_idx: this is set if this request's initiator is
  * 	%REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
  * 	can be used by the wireless core to deal with conflicts
  * 	and potentially inform users of which devices specifically
@@ -406,7 +406,7 @@ enum environment_cap {
  * 	indoor, or if it doesn't matter
  */
 struct regulatory_request {
-	struct wiphy *wiphy;
+	int wiphy_idx;
 	enum reg_set_by initiator;
 	char alpha2[2];
 	bool intersect;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index e347093..b1a354b 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -40,9 +40,8 @@ DEFINE_MUTEX(cfg80211_mutex);
 /* for debugfs */
 static struct dentry *ieee80211_debugfs_dir;
 
-/* requires cfg80211_drv_mutex to be held! */
-static struct cfg80211_registered_device *
-cfg80211_drv_by_wiphy_idx(int wiphy_idx)
+/* requires cfg80211_mutex to be held! */
+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 {
 	struct cfg80211_registered_device *result = NULL, *drv;
 
@@ -61,6 +60,31 @@ cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 	return result;
 }
 
+int get_wiphy_idx(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_device *drv;
+	if (!wiphy)
+		return WIPHY_IDX_STALE;
+	drv = wiphy_to_dev(wiphy);
+	return drv->wiphy_idx;
+}
+
+/* requires cfg80211_drv_mutex to be held! */
+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
+{
+	struct cfg80211_registered_device *drv;
+
+	if (!wiphy_idx_valid(wiphy_idx))
+		return NULL;
+
+	assert_cfg80211_lock();
+
+	drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);
+	if (!drv)
+		return NULL;
+	return &drv->wiphy;
+}
+
 /* requires cfg80211_mutex to be held! */
 static struct cfg80211_registered_device *
 __cfg80211_drv_from_info(struct genl_info *info)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 982cc6b..cd8e6e3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -79,6 +79,12 @@ static inline void assert_cfg80211_lock(void)
 	BUG_ON(!mutex_is_locked(&cfg80211_mutex));
 }
 
+/*
+ * You can use this to mark a wiphy_idx as not having an associated wiphy.
+ * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL
+ */
+#define WIPHY_IDX_STALE -1
+
 struct cfg80211_internal_bss {
 	struct list_head list;
 	struct rb_node rbn;
@@ -88,6 +94,9 @@ struct cfg80211_internal_bss {
 	struct cfg80211_bss pub;
 };
 
+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
+int get_wiphy_idx(struct wiphy *wiphy);
+
 /*
  * This function returns a pointer to the driver
  * that the genl_info item that is passed refers to.
@@ -111,6 +120,9 @@ struct cfg80211_internal_bss {
 extern struct cfg80211_registered_device *
 cfg80211_get_dev_from_info(struct genl_info *info);
 
+/* requires cfg80211_drv_mutex to be held! */
+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
+
 /* identical to cfg80211_get_dev_from_info but only operate on ifindex */
 extern struct cfg80211_registered_device *
 cfg80211_get_dev_from_ifindex(int ifindex);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e49ac9b..d44f3b5 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -831,9 +831,12 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 	const struct ieee80211_power_rule *power_rule = NULL;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
+	struct wiphy *request_wiphy;
 
 	assert_cfg80211_lock();
 
+	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
 	sband = wiphy->bands[band];
 	BUG_ON(chan_idx >= sband->n_channels);
 	chan = &sband->channels[chan_idx];
@@ -881,8 +884,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 	power_rule = &reg_rule->power_rule;
 
 	if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
-	    last_request->wiphy && last_request->wiphy == wiphy &&
-	    last_request->wiphy->strict_regulatory) {
+	    request_wiphy && request_wiphy == wiphy &&
+	    request_wiphy->strict_regulatory) {
 		/* This gaurantees the driver's requested regulatory domain
 		 * will always be used as a base for further regulatory
 		 * settings */
@@ -1046,6 +1049,7 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
 static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 			  const char *alpha2)
 {
+	struct wiphy *last_wiphy = NULL;
 
 	assert_cfg80211_lock();
 
@@ -1059,10 +1063,13 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 	case REGDOM_SET_BY_CORE:
 		return -EINVAL;
 	case REGDOM_SET_BY_COUNTRY_IE:
+
+		last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
 		if (unlikely(!is_an_alpha2(alpha2)))
 			return -EINVAL;
 		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
-			if (last_request->wiphy != wiphy) {
+			if (last_wiphy != wiphy) {
 				/*
 				 * Two cards with two APs claiming different
 				 * different Country IE alpha2s. We could
@@ -1163,7 +1170,7 @@ new_request:
 	request->alpha2[0] = alpha2[0];
 	request->alpha2[1] = alpha2[1];
 	request->initiator = set_by;
-	request->wiphy = wiphy;
+	request->wiphy_idx = get_wiphy_idx(wiphy);
 	request->intersect = intersect;
 	request->country_ie_checksum = country_ie_checksum;
 	request->country_ie_env = env;
@@ -1226,11 +1233,16 @@ EXPORT_SYMBOL(regulatory_hint);
 static bool reg_same_country_ie_hint(struct wiphy *wiphy,
 			u32 country_ie_checksum)
 {
+	struct wiphy *request_wiphy;
+
 	assert_cfg80211_lock();
 
-	if (!last_request->wiphy)
+	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
+	if (!request_wiphy)
 		return false;
-	if (likely(last_request->wiphy != wiphy))
+
+	if (likely(request_wiphy != wiphy))
 		return !country_ie_integrity_changes(country_ie_checksum);
 	/* We should not have let these through at this point, they
 	 * should have been picked up earlier by the first alpha2 check
@@ -1278,14 +1290,15 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	/* We will run this for *every* beacon processed for the BSSID, so
 	 * we optimize an early check to exit out early if we don't have to
 	 * do anything */
-	if (likely(last_request->wiphy)) {
+	if (likely(wiphy_idx_valid(last_request->wiphy_idx))) {
 		struct cfg80211_registered_device *drv_last_ie;
 
-		drv_last_ie = wiphy_to_dev(last_request->wiphy);
+		drv_last_ie =
+			cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
 
 		/* Lets keep this simple -- we trust the first AP
 		 * after we intersect with CRDA */
-		if (likely(last_request->wiphy == wiphy)) {
+		if (likely(&drv_last_ie->wiphy == wiphy)) {
 			/* Ignore IEs coming in on this wiphy with
 			 * the same alpha2 and environment cap */
 			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
@@ -1377,13 +1390,12 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
 
 	if (is_intersected_alpha2(rd->alpha2)) {
-		struct wiphy *wiphy = NULL;
-		struct cfg80211_registered_device *drv;
 
 		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
-			if (last_request->wiphy) {
-				wiphy = last_request->wiphy;
-				drv = wiphy_to_dev(wiphy);
+			struct cfg80211_registered_device *drv;
+			drv = cfg80211_drv_by_wiphy_idx(
+				last_request->wiphy_idx);
+			if (drv) {
 				printk(KERN_INFO "cfg80211: Current regulatory "
 					"domain updated by AP to: %c%c\n",
 					drv->country_ie_alpha2[0],
@@ -1449,7 +1461,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
 	const struct ieee80211_regdomain *intersected_rd = NULL;
 	struct cfg80211_registered_device *drv = NULL;
-	struct wiphy *wiphy = NULL;
+	struct wiphy *request_wiphy;
 	/* Some basic sanity checks first */
 
 	if (is_world_regdom(rd->alpha2)) {
@@ -1477,8 +1489,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 			return -EINVAL;
 	}
 
-	wiphy = last_request->wiphy;
-
 	/* Now lets set the regulatory domain, update all driver channels
 	 * and finally inform them of what we have done, in case they want
 	 * to review or adjust their own settings based on their own
@@ -1494,6 +1504,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		return -EINVAL;
 	}
 
+	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
 	if (!last_request->intersect) {
 		int r;
 
@@ -1506,9 +1518,9 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		/* For a driver hint, lets copy the regulatory domain the
 		 * driver wanted to the wiphy to deal with conflicts */
 
-		BUG_ON(last_request->wiphy->regd);
+		BUG_ON(request_wiphy->regd);
 
-		r = reg_copy_regd(&last_request->wiphy->regd, rd);
+		r = reg_copy_regd(&request_wiphy->regd, rd);
 		if (r)
 			return r;
 
@@ -1529,7 +1541,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		 * However if a driver requested this specific regulatory
 		 * domain we keep it for its private use */
 		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
-			last_request->wiphy->regd = rd;
+			request_wiphy->regd = rd;
 		else
 			kfree(rd);
 
@@ -1569,7 +1581,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 	if (!intersected_rd)
 		return -EINVAL;
 
-	drv = wiphy_to_dev(wiphy);
+	drv = wiphy_to_dev(request_wiphy);
 
 	drv->country_ie_alpha2[0] = rd->alpha2[0];
 	drv->country_ie_alpha2[1] = rd->alpha2[1];
@@ -1618,14 +1630,18 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 /* Caller must hold cfg80211_mutex */
 void reg_device_remove(struct wiphy *wiphy)
 {
+	struct wiphy *request_wiphy;
+
 	assert_cfg80211_lock();
 
+	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
 	kfree(wiphy->regd);
-	if (!last_request || !last_request->wiphy)
+	if (!last_request || !request_wiphy)
 		return;
-	if (last_request->wiphy != wiphy)
+	if (request_wiphy != wiphy)
 		return;
-	last_request->wiphy = NULL;
+	last_request->wiphy_idx = WIPHY_IDX_STALE;
 	last_request->country_ie_env = ENVIRON_ANY;
 }
 
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 09/15] cfg80211: protect first access of last_request on 11d hint under mutex
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (7 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 08/15] cfg80211: make regulatory_request use wiphy_idx instead of wiphy Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 10/15] cfg80211: remove likely from an 11d hint case Luis R. Rodriguez
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

We were not protecting last_request there is a small possible race
between an 11d hint and another routine which calls reset_regdomains()
which can prevent a valid country IE from being processed. This is
not critical as it will still be procesed soon after but locking prior
to it is correct.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index d44f3b5..b474452 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1261,11 +1261,13 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	u32 checksum = 0;
 	enum environment_cap env = ENVIRON_ANY;
 
-	if (!last_request)
-		return;
-
 	mutex_lock(&cfg80211_mutex);
 
+	if (unlikely(!last_request)) {
+		mutex_unlock(&cfg80211_mutex);
+		return;
+	}
+
 	/* IE len must be evenly divisible by 2 */
 	if (country_ie_len & 0x01)
 		goto out;
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 10/15] cfg80211: remove likely from an 11d hint case
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (8 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 09/15] cfg80211: protect first access of last_request on 11d hint under mutex Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 11/15] cfg80211: free rd on unlikely event on 11d hint Luis R. Rodriguez
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

Truth of the matter this was confusing people so mark it as
unlikely as that is the case now.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b474452..baf50ca 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1331,14 +1331,16 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	if (!rd)
 		goto out;
 
-	/* This will not happen right now but we leave it here for the
+	/*
+	 * This will not happen right now but we leave it here for the
 	 * the future when we want to add suspend/resume support and having
 	 * the user move to another country after doing so, or having the user
-	 * move to another AP. Right now we just trust the first AP. This is why
-	 * this is marked as likley(). If we hit this before we add this support
-	 * we want to be informed of it as it would indicate a mistake in the
-	 * current design  */
-	if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
+	 * move to another AP. Right now we just trust the first AP.
+	 *
+	 * If we hit this before we add this support we want to be informed of
+	 * it as it would indicate a mistake in the current design
+	 */
+	if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
 		goto out;
 
 	/* We keep this around for when CRDA comes back with a response so
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 11/15] cfg80211: free rd on unlikely event on 11d hint
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (9 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 10/15] cfg80211: remove likely from an 11d hint case Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 12/15] cfg80211: move all regulatory hints to workqueue Luis R. Rodriguez
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

This was never happening but it was still wrong, so correct it.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index baf50ca..af762be 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1341,7 +1341,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	 * it as it would indicate a mistake in the current design
 	 */
 	if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
-		goto out;
+		goto free_rd_out;
 
 	/* We keep this around for when CRDA comes back with a response so
 	 * we can intersect with that */
@@ -1350,6 +1350,10 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	__regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
 		country_ie_regdomain->alpha2, checksum, env);
 
+	goto out;
+
+free_rd_out:
+	kfree(rd);
 out:
 	mutex_unlock(&cfg80211_mutex);
 }
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 12/15] cfg80211: move all regulatory hints to workqueue
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (10 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 11/15] cfg80211: free rd on unlikely event on 11d hint Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 13/15] cfg80211: comments style cleanup Luis R. Rodriguez
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

All regulatory hints (core, driver, userspace and 11d) are now processed in
a workqueue.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath9k/main.c      |    8 +-
 drivers/net/wireless/zd1211rw/zd_mac.c |    6 +-
 include/net/cfg80211.h                 |    2 +
 include/net/wireless.h                 |    9 ++-
 net/wireless/nl80211.c                 |   30 ++----
 net/wireless/reg.c                     |  178 +++++++++++++++++++++++++++++---
 net/wireless/reg.h                     |    2 +
 7 files changed, 194 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 7264c4c..9079d32 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1659,8 +1659,12 @@ int ath_attach(u16 devid, struct ath_softc *sc)
 
 	error = ieee80211_register_hw(hw);
 
-	if (!ath9k_is_world_regd(sc->sc_ah))
-		regulatory_hint(hw->wiphy, sc->sc_ah->regulatory.alpha2);
+	if (!ath9k_is_world_regd(sc->sc_ah)) {
+		error = regulatory_hint(hw->wiphy,
+			sc->sc_ah->regulatory.alpha2);
+		if (error)
+			goto error_attach;
+	}
 
 	/* Initialize LED control */
 	ath_init_leds(sc);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 7579af2..da9214e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -170,10 +170,10 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
 		goto disable_int;
 
 	r = zd_reg2alpha2(mac->regdomain, alpha2);
-	if (!r)
-		regulatory_hint(hw->wiphy, alpha2);
+	if (r)
+		goto disable_int;
 
-	r = 0;
+	r = regulatory_hint(hw->wiphy, alpha2);
 disable_int:
 	zd_chip_disable_int(chip);
 out:
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bb9129f..75fa556 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -404,6 +404,7 @@ enum environment_cap {
  * 	country IE
  * @country_ie_env: lets us know if the AP is telling us we are outdoor,
  * 	indoor, or if it doesn't matter
+ * @list: used to insert into the reg_requests_list linked list
  */
 struct regulatory_request {
 	int wiphy_idx;
@@ -412,6 +413,7 @@ struct regulatory_request {
 	bool intersect;
 	u32 country_ie_checksum;
 	enum environment_cap country_ie_env;
+	struct list_head list;
 };
 
 struct ieee80211_freq_range {
diff --git a/include/net/wireless.h b/include/net/wireless.h
index d815aa8..1f4707d 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -401,8 +401,15 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
  * domain should be in or by providing a completely build regulatory domain.
  * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
  * for a regulatory domain structure for the respective country.
+ *
+ * The wiphy must have been registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM.
  */
-extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
 /**
  * regulatory_hint_11d - hints a country IE as a regulatory domain
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0b8f811..737927b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1891,34 +1891,24 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 	 */
 	mutex_lock(&cfg80211_mutex);
 	if (unlikely(!cfg80211_regdomain)) {
-		r = -EINPROGRESS;
-		goto out;
+		mutex_unlock(&cfg80211_mutex);
+		return -EINPROGRESS;
 	}
+	mutex_unlock(&cfg80211_mutex);
 
-	if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) {
-		r = -EINVAL;
-		goto out;
-	}
+	if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+		return -EINVAL;
 
 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 
 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
 	/* We ignore world regdom requests with the old regdom setup */
-	if (is_world_regdom(data)) {
-		r = -EINVAL;
-		goto out;
-	}
+	if (is_world_regdom(data))
+		return -EINVAL;
 #endif
-	r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
-	/*
-	 * This means the regulatory domain was already set, however
-	 * we don't want to confuse userspace with a "successful error"
-	 * message so lets just treat it as a success
-	 */
-	if (r == -EALREADY)
-		r = 0;
-out:
-	mutex_unlock(&cfg80211_mutex);
+
+	r = regulatory_hint_user(data);
+
 	return r;
 }
 
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index af762be..0e0eb6a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -64,6 +64,9 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
  * what it thinks should apply for the same country */
 static const struct ieee80211_regdomain *country_ie_regdomain;
 
+static LIST_HEAD(reg_requests_list);
+static spinlock_t reg_requests_lock;
+
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
 	.n_reg_rules = 1,
@@ -831,7 +834,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 	const struct ieee80211_power_rule *power_rule = NULL;
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
-	struct wiphy *request_wiphy;
+	struct wiphy *request_wiphy = NULL;
 
 	assert_cfg80211_lock();
 
@@ -1195,6 +1198,89 @@ new_request:
 	return call_crda(alpha2);
 }
 
+/* This currently only processes user and driver regulatory hints */
+static int reg_process_hint(struct regulatory_request *reg_request)
+{
+	int r = 0;
+	struct wiphy *wiphy = NULL;
+
+	BUG_ON(!reg_request->alpha2);
+
+	mutex_lock(&cfg80211_mutex);
+
+	if (wiphy_idx_valid(reg_request->wiphy_idx))
+		wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
+
+	if (reg_request->initiator == REGDOM_SET_BY_DRIVER &&
+	    !wiphy) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	r = __regulatory_hint(wiphy,
+			      reg_request->initiator,
+			      reg_request->alpha2,
+			      reg_request->country_ie_checksum,
+			      reg_request->country_ie_env);
+	/* This is required so that the orig_* parameters are saved */
+	if (r == -EALREADY && wiphy->strict_regulatory)
+		wiphy_update_regulatory(wiphy, reg_request->initiator);
+out:
+	mutex_unlock(&cfg80211_mutex);
+
+	if (r == -EALREADY)
+		r = 0;
+
+	return r;
+}
+
+static void reg_process_pending_hints(void)
+	{
+	struct regulatory_request *reg_request;
+	int r;
+
+	spin_lock(&reg_requests_lock);
+	while (!list_empty(&reg_requests_list)) {
+		reg_request = list_first_entry(&reg_requests_list,
+					       struct regulatory_request,
+					       list);
+		list_del_init(&reg_request->list);
+		spin_unlock(&reg_requests_lock);
+
+		r = reg_process_hint(reg_request);
+#ifdef CONFIG_CFG80211_REG_DEBUG
+		if (r && (reg_request->initiator == REGDOM_SET_BY_DRIVER ||
+		    reg_request->initiator == REGDOM_SET_BY_COUNTRY_IE))
+			printk(KERN_ERR "cfg80211: wiphy_idx %d sent a "
+				"regulatory hint for %c%c but now has "
+				"gone fishing, ignoring request\n",
+				reg_request->wiphy_idx,
+				reg_request->alpha2[0],
+				reg_request->alpha2[1]);
+#endif
+		kfree(reg_request);
+		spin_lock(&reg_requests_lock);
+	}
+	spin_unlock(&reg_requests_lock);
+}
+
+static void reg_todo(struct work_struct *work)
+{
+	reg_process_pending_hints();
+}
+
+static DECLARE_WORK(reg_work, reg_todo);
+
+static void queue_regulatory_request(struct regulatory_request *request)
+{
+	spin_lock(&reg_requests_lock);
+	list_add_tail(&request->list, &reg_requests_list);
+	spin_unlock(&reg_requests_lock);
+
+	schedule_work(&reg_work);
+}
+
+/* Core regulatory hint -- happens once during cfg80211_init() */
 static int regulatory_hint_core(const char *alpha2)
 {
 	struct regulatory_request *request;
@@ -1210,23 +1296,56 @@ static int regulatory_hint_core(const char *alpha2)
 	request->alpha2[1] = alpha2[1];
 	request->initiator = REGDOM_SET_BY_CORE;
 
-	last_request = request;
+	queue_regulatory_request(request);
 
-	return call_crda(alpha2);
+	return 0;
 }
 
-void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
+/* User hints */
+int regulatory_hint_user(const char *alpha2)
 {
-	int r;
+	struct regulatory_request *request;
+
 	BUG_ON(!alpha2);
 
-	mutex_lock(&cfg80211_mutex);
-	r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,
-		alpha2, 0, ENVIRON_ANY);
-	/* This is required so that the orig_* parameters are saved */
-	if (r == -EALREADY && wiphy->strict_regulatory)
-		wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);
-	mutex_unlock(&cfg80211_mutex);
+	request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	request->wiphy_idx = WIPHY_IDX_STALE;
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
+	request->initiator = REGDOM_SET_BY_USER,
+
+	queue_regulatory_request(request);
+
+	return 0;
+}
+
+/* Driver hints */
+int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
+{
+	struct regulatory_request *request;
+
+	BUG_ON(!alpha2);
+	BUG_ON(!wiphy);
+
+	request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+
+	request->wiphy_idx = get_wiphy_idx(wiphy);
+
+	/* Must have registered wiphy first */
+	BUG_ON(!wiphy_idx_valid(request->wiphy_idx));
+
+	request->alpha2[0] = alpha2[0];
+	request->alpha2[1] = alpha2[1];
+	request->initiator = REGDOM_SET_BY_DRIVER;
+
+	queue_regulatory_request(request);
+
+	return 0;
 }
 EXPORT_SYMBOL(regulatory_hint);
 
@@ -1260,6 +1379,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	char alpha2[2];
 	u32 checksum = 0;
 	enum environment_cap env = ENVIRON_ANY;
+	struct regulatory_request *request;
 
 	mutex_lock(&cfg80211_mutex);
 
@@ -1343,14 +1463,26 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
 		goto free_rd_out;
 
+	request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+	if (!request)
+		goto free_rd_out;
+
 	/* We keep this around for when CRDA comes back with a response so
 	 * we can intersect with that */
 	country_ie_regdomain = rd;
 
-	__regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
-		country_ie_regdomain->alpha2, checksum, env);
+	request->wiphy_idx = get_wiphy_idx(wiphy);
+	request->alpha2[0] = rd->alpha2[0];
+	request->alpha2[1] = rd->alpha2[1];
+	request->initiator = REGDOM_SET_BY_COUNTRY_IE;
+	request->country_ie_checksum = checksum;
+	request->country_ie_env = env;
+
+	mutex_unlock(&cfg80211_mutex);
+
+	queue_regulatory_request(request);
 
-	goto out;
+	return;
 
 free_rd_out:
 	kfree(rd);
@@ -1661,6 +1793,8 @@ int regulatory_init(void)
 	if (IS_ERR(reg_pdev))
 		return PTR_ERR(reg_pdev);
 
+	spin_lock_init(&reg_requests_lock);
+
 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
 	cfg80211_regdomain = static_regdom(ieee80211_regdom);
 
@@ -1700,6 +1834,10 @@ int regulatory_init(void)
 
 void regulatory_exit(void)
 {
+	struct regulatory_request *reg_request, *tmp;
+
+	cancel_work_sync(&reg_work);
+
 	mutex_lock(&cfg80211_mutex);
 
 	reset_regdomains();
@@ -1711,5 +1849,15 @@ void regulatory_exit(void)
 
 	platform_device_unregister(reg_pdev);
 
+	spin_lock(&reg_requests_lock);
+	if (!list_empty(&reg_requests_list)) {
+		list_for_each_entry_safe(reg_request, tmp,
+					 &reg_requests_list, list) {
+			list_del(&reg_request->list);
+			kfree(reg_request);
+		}
+	}
+	spin_unlock(&reg_requests_lock);
+
 	mutex_unlock(&cfg80211_mutex);
 }
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index fe8c83f..4730def 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain;
 bool is_world_regdom(const char *alpha2);
 bool reg_is_valid_request(const char *alpha2);
 
+int regulatory_hint_user(const char *alpha2);
+
 void reg_device_remove(struct wiphy *wiphy);
 
 int regulatory_init(void);
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 13/15] cfg80211: comments style cleanup
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (11 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 12/15] cfg80211: move all regulatory hints to workqueue Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 14/15] cfg80211: allow drivers that agree on regulatory to agree Luis R. Rodriguez
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |  299 ++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 199 insertions(+), 100 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 0e0eb6a..efa3ecd 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -54,14 +54,18 @@ static u32 supported_bandwidths[] = {
 	MHZ_TO_KHZ(20),
 };
 
-/* Central wireless core regulatory domains, we only need two,
+/*
+ * Central wireless core regulatory domains, we only need two,
  * the current one and a world regulatory domain in case we have no
- * information to give us an alpha2 */
+ * information to give us an alpha2
+ */
 const struct ieee80211_regdomain *cfg80211_regdomain;
 
-/* We use this as a place for the rd structure built from the
+/*
+ * We use this as a place for the rd structure built from the
  * last parsed country IE to rest until CRDA gets back to us with
- * what it thinks should apply for the same country */
+ * what it thinks should apply for the same country
+ */
 static const struct ieee80211_regdomain *country_ie_regdomain;
 
 static LIST_HEAD(reg_requests_list);
@@ -86,9 +90,11 @@ static char *ieee80211_regdom = "US";
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-/* We assume 40 MHz bandwidth for the old regulatory work.
+/*
+ * We assume 40 MHz bandwidth for the old regulatory work.
  * We make emphasis we are using the exact same frequencies
- * as before */
+ * as before
+ */
 
 static const struct ieee80211_regdomain us_regdom = {
 	.n_reg_rules = 6,
@@ -127,8 +133,10 @@ static const struct ieee80211_regdomain jp_regdom = {
 
 static const struct ieee80211_regdomain eu_regdom = {
 	.n_reg_rules = 6,
-	/* This alpha2 is bogus, we leave it here just for stupid
-	 * backward compatibility */
+	/*
+	 * This alpha2 is bogus, we leave it here just for stupid
+	 * backward compatibility
+	 */
 	.alpha2 =  "EU",
 	.reg_rules = {
 		/* IEEE 802.11b/g, channels 1..13 */
@@ -197,8 +205,10 @@ static void reset_regdomains(void)
 	cfg80211_regdomain = NULL;
 }
 
-/* Dynamic world regulatory domain requested by the wireless
- * core upon initialization */
+/*
+ * Dynamic world regulatory domain requested by the wireless
+ * core upon initialization
+ */
 static void update_world_regdomain(const struct ieee80211_regdomain *rd)
 {
 	BUG_ON(!last_request);
@@ -239,8 +249,10 @@ static bool is_unknown_alpha2(const char *alpha2)
 {
 	if (!alpha2)
 		return false;
-	/* Special case where regulatory domain was built by driver
-	 * but a specific alpha2 cannot be determined */
+	/*
+	 * Special case where regulatory domain was built by driver
+	 * but a specific alpha2 cannot be determined
+	 */
 	if (alpha2[0] == '9' && alpha2[1] == '9')
 		return true;
 	return false;
@@ -250,9 +262,11 @@ static bool is_intersected_alpha2(const char *alpha2)
 {
 	if (!alpha2)
 		return false;
-	/* Special case where regulatory domain is the
+	/*
+	 * Special case where regulatory domain is the
 	 * result of an intersection between two regulatory domain
-	 * structures */
+	 * structures
+	 */
 	if (alpha2[0] == '9' && alpha2[1] == '8')
 		return true;
 	return false;
@@ -307,8 +321,10 @@ static bool country_ie_integrity_changes(u32 checksum)
 	return false;
 }
 
-/* This lets us keep regulatory code which is updated on a regulatory
- * basis in userspace. */
+/*
+ * This lets us keep regulatory code which is updated on a regulatory
+ * basis in userspace.
+ */
 static int call_crda(const char *alpha2)
 {
 	char country_env[9 + 2] = "COUNTRY=";
@@ -419,10 +435,12 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
-/* Converts a country IE to a regulatory domain. A regulatory domain
+/*
+ * Converts a country IE to a regulatory domain. A regulatory domain
  * structure has a lot of information which the IE doesn't yet have,
  * so for the other values we use upper max values as we will intersect
- * with our userspace regulatory agent to get lower bounds. */
+ * with our userspace regulatory agent to get lower bounds.
+ */
 static struct ieee80211_regdomain *country_ie_2_rd(
 				u8 *country_ie,
 				u8 country_ie_len,
@@ -467,9 +485,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 
 	*checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
 
-	/* We need to build a reg rule for each triplet, but first we must
+	/*
+	 * We need to build a reg rule for each triplet, but first we must
 	 * calculate the number of reg rules we will need. We will need one
-	 * for each channel subband */
+	 * for each channel subband
+	 */
 	while (country_ie_len >= 3) {
 		int end_channel = 0;
 		struct ieee80211_country_ie_triplet *triplet =
@@ -507,9 +527,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 		if (cur_sub_max_channel < cur_channel)
 			return NULL;
 
-		/* Do not allow overlapping channels. Also channels
+		/*
+		 * Do not allow overlapping channels. Also channels
 		 * passed in each subband must be monotonically
-		 * increasing */
+		 * increasing
+		 */
 		if (last_sub_max_channel) {
 			if (cur_channel <= last_sub_max_channel)
 				return NULL;
@@ -517,10 +539,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 				return NULL;
 		}
 
-		/* When dot11RegulatoryClassesRequired is supported
+		/*
+		 * When dot11RegulatoryClassesRequired is supported
 		 * we can throw ext triplets as part of this soup,
 		 * for now we don't care when those change as we
-		 * don't support them */
+		 * don't support them
+		 */
 		*checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
 		  ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
 		  ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
@@ -531,8 +555,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 		country_ie_len -= 3;
 		num_rules++;
 
-		/* Note: this is not a IEEE requirement but
-		 * simply a memory requirement */
+		/*
+		 * Note: this is not a IEEE requirement but
+		 * simply a memory requirement
+		 */
 		if (num_rules > NL80211_MAX_SUPP_REG_RULES)
 			return NULL;
 	}
@@ -560,8 +586,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 		struct ieee80211_freq_range *freq_range = NULL;
 		struct ieee80211_power_rule *power_rule = NULL;
 
-		/* Must parse if dot11RegulatoryClassesRequired is true,
-		 * we don't support this yet */
+		/*
+		 * Must parse if dot11RegulatoryClassesRequired is true,
+		 * we don't support this yet
+		 */
 		if (triplet->ext.reg_extension_id >=
 				IEEE80211_COUNTRY_EXTENSION_ID) {
 			country_ie += 3;
@@ -583,10 +611,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 			end_channel =  triplet->chans.first_channel +
 				(4 * (triplet->chans.num_channels - 1));
 
-		/* The +10 is since the regulatory domain expects
+		/*
+		 * The +10 is since the regulatory domain expects
 		 * the actual band edge, not the center of freq for
 		 * its start and end freqs, assuming 20 MHz bandwidth on
-		 * the channels passed */
+		 * the channels passed
+		 */
 		freq_range->start_freq_khz =
 			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
 				triplet->chans.first_channel) - 10);
@@ -594,9 +624,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 			MHZ_TO_KHZ(ieee80211_channel_to_frequency(
 				end_channel) + 10);
 
-		/* Large arbitrary values, we intersect later */
-		/* Increment this if we ever support >= 40 MHz channels
-		 * in IEEE 802.11 */
+		/*
+		 * These are large arbitrary values we use to intersect later.
+		 * Increment this if we ever support >= 40 MHz channels
+		 * in IEEE 802.11
+		 */
 		freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
 		power_rule->max_antenna_gain = DBI_TO_MBI(100);
 		power_rule->max_eirp = DBM_TO_MBM(100);
@@ -612,8 +644,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 }
 
 
-/* Helper for regdom_intersect(), this does the real
- * mathematical intersection fun */
+/*
+ * Helper for regdom_intersect(), this does the real
+ * mathematical intersection fun
+ */
 static int reg_rules_intersect(
 	const struct ieee80211_reg_rule *rule1,
 	const struct ieee80211_reg_rule *rule2,
@@ -691,11 +725,13 @@ static struct ieee80211_regdomain *regdom_intersect(
 	if (!rd1 || !rd2)
 		return NULL;
 
-	/* First we get a count of the rules we'll need, then we actually
+	/*
+	 * First we get a count of the rules we'll need, then we actually
 	 * build them. This is to so we can malloc() and free() a
 	 * regdomain once. The reason we use reg_rules_intersect() here
 	 * is it will return -EINVAL if the rule computed makes no sense.
-	 * All rules that do check out OK are valid. */
+	 * All rules that do check out OK are valid.
+	 */
 
 	for (x = 0; x < rd1->n_reg_rules; x++) {
 		rule1 = &rd1->reg_rules[x];
@@ -723,14 +759,18 @@ static struct ieee80211_regdomain *regdom_intersect(
 		rule1 = &rd1->reg_rules[x];
 		for (y = 0; y < rd2->n_reg_rules; y++) {
 			rule2 = &rd2->reg_rules[y];
-			/* This time around instead of using the stack lets
+			/*
+			 * This time around instead of using the stack lets
 			 * write to the target rule directly saving ourselves
-			 * a memcpy() */
+			 * a memcpy()
+			 */
 			intersected_rule = &rd->reg_rules[rule_idx];
 			r = reg_rules_intersect(rule1, rule2,
 				intersected_rule);
-			/* No need to memset here the intersected rule here as
-			 * we're not using the stack anymore */
+			/*
+			 * No need to memset here the intersected rule here as
+			 * we're not using the stack anymore
+			 */
 			if (r)
 				continue;
 			rule_idx++;
@@ -749,8 +789,10 @@ static struct ieee80211_regdomain *regdom_intersect(
 	return rd;
 }
 
-/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
- * want to just have the channel structure use these */
+/*
+ * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
+ * want to just have the channel structure use these
+ */
 static u32 map_regdom_flags(u32 rd_flags)
 {
 	u32 channel_flags = 0;
@@ -776,8 +818,10 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
 
 	regd = custom_regd ? custom_regd : cfg80211_regdomain;
 
-	/* Follow the driver's regulatory domain, if present, unless a country
-	 * IE has been processed or a user wants to help complaince further */
+	/*
+	 * Follow the driver's regulatory domain, if present, unless a country
+	 * IE has been processed or a user wants to help complaince further
+	 */
 	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
 	    last_request->initiator != REGDOM_SET_BY_USER &&
 	    wiphy->regd)
@@ -795,9 +839,11 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
 		fr = &rr->freq_range;
 		pr = &rr->power_rule;
 
-		/* We only need to know if one frequency rule was
+		/*
+		 * We only need to know if one frequency rule was
 		 * was in center_freq's band, that's enough, so lets
-		 * not overwrite it once found */
+		 * not overwrite it once found
+		 */
 		if (!band_rule_found)
 			band_rule_found = freq_in_rule_band(fr, center_freq);
 
@@ -850,7 +896,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 		&max_bandwidth, &reg_rule);
 
 	if (r) {
-		/* This means no regulatory rule was found in the country IE
+		/*
+		 * This means no regulatory rule was found in the country IE
 		 * with a frequency range on the center_freq's band, since
 		 * IEEE-802.11 allows for a country IE to have a subset of the
 		 * regulatory information provided in a country we ignore
@@ -869,8 +916,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 				chan->center_freq, wiphy_name(wiphy));
 #endif
 		} else {
-		/* In this case we know the country IE has at least one reg rule
-		 * for the band so we respect its band definitions */
+		/*
+		 * In this case we know the country IE has at least one reg rule
+		 * for the band so we respect its band definitions
+		 */
 #ifdef CONFIG_CFG80211_REG_DEBUG
 			if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
 				printk(KERN_DEBUG "cfg80211: Disabling "
@@ -889,9 +938,11 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 	if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
 	    request_wiphy && request_wiphy == wiphy &&
 	    request_wiphy->strict_regulatory) {
-		/* This gaurantees the driver's requested regulatory domain
+		/*
+		 * This gaurantees the driver's requested regulatory domain
 		 * will always be used as a base for further regulatory
-		 * settings */
+		 * settings
+		 */
 		chan->flags = chan->orig_flags =
 			map_regdom_flags(reg_rule->flags);
 		chan->max_antenna_gain = chan->orig_mag =
@@ -932,8 +983,10 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
 	if (setby == REGDOM_SET_BY_CORE &&
 		  wiphy->custom_regulatory)
 		return true;
-	/* wiphy->regd will be set once the device has its own
-	 * desired regulatory domain set */
+	/*
+	 * wiphy->regd will be set once the device has its own
+	 * desired regulatory domain set
+	 */
 	if (wiphy->strict_regulatory && !wiphy->regd &&
 	    !is_world_regdom(last_request->alpha2))
 		return true;
@@ -1043,8 +1096,10 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
 	return 0;
 }
 
-/* Return value which can be used by ignore_request() to indicate
- * it has been determined we should intersect two regulatory domains */
+/*
+ * Return value which can be used by ignore_request() to indicate
+ * it has been determined we should intersect two regulatory domains
+ */
 #define REG_INTERSECT	1
 
 /* This has the logic which determines when a new request
@@ -1084,8 +1139,10 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 					return -EOPNOTSUPP;
 				return -EALREADY;
 			}
-			/* Two consecutive Country IE hints on the same wiphy.
-			 * This should be picked up early by the driver/stack */
+			/*
+			 * Two consecutive Country IE hints on the same wiphy.
+			 * This should be picked up early by the driver/stack
+			 */
 			if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
 				  alpha2)))
 				return 0;
@@ -1104,13 +1161,17 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 	case REGDOM_SET_BY_USER:
 		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
 			return REG_INTERSECT;
-		/* If the user knows better the user should set the regdom
-		 * to their country before the IE is picked up */
+		/*
+		 * If the user knows better the user should set the regdom
+		 * to their country before the IE is picked up
+		 */
 		if (last_request->initiator == REGDOM_SET_BY_USER &&
 			  last_request->intersect)
 			return -EOPNOTSUPP;
-		/* Process user requests only after previous user/driver/core
-		 * requests have been processed */
+		/*
+		 * Process user requests only after previous user/driver/core
+		 * requests have been processed
+		 */
 		if (last_request->initiator == REGDOM_SET_BY_CORE ||
 		    last_request->initiator == REGDOM_SET_BY_DRIVER ||
 		    last_request->initiator == REGDOM_SET_BY_USER) {
@@ -1151,9 +1212,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
 		}
 		intersect = true;
 	} else if (r) {
-		/* If the regulatory domain being requested by the
+		/*
+		 * If the regulatory domain being requested by the
 		 * driver has already been set just copy it to the
-		 * wiphy */
+		 * wiphy
+		 */
 		if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
 			r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
 			if (r)
@@ -1363,9 +1426,11 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
 
 	if (likely(request_wiphy != wiphy))
 		return !country_ie_integrity_changes(country_ie_checksum);
-	/* We should not have let these through at this point, they
+	/*
+	 * We should not have let these through at this point, they
 	 * should have been picked up earlier by the first alpha2 check
-	 * on the device */
+	 * on the device
+	 */
 	if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
 		return true;
 	return false;
@@ -1395,9 +1460,11 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
 		goto out;
 
-	/* Pending country IE processing, this can happen after we
+	/*
+	 * Pending country IE processing, this can happen after we
 	 * call CRDA and wait for a response if a beacon was received before
-	 * we were able to process the last regulatory_hint_11d() call */
+	 * we were able to process the last regulatory_hint_11d() call
+	 */
 	if (country_ie_regdomain)
 		goto out;
 
@@ -1409,34 +1476,44 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	else if (country_ie[2] == 'O')
 		env = ENVIRON_OUTDOOR;
 
-	/* We will run this for *every* beacon processed for the BSSID, so
+	/*
+	 * We will run this for *every* beacon processed for the BSSID, so
 	 * we optimize an early check to exit out early if we don't have to
-	 * do anything */
+	 * do anything
+	 */
 	if (likely(wiphy_idx_valid(last_request->wiphy_idx))) {
 		struct cfg80211_registered_device *drv_last_ie;
 
 		drv_last_ie =
 			cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
 
-		/* Lets keep this simple -- we trust the first AP
-		 * after we intersect with CRDA */
+		/*
+		 * Lets keep this simple -- we trust the first AP
+		 * after we intersect with CRDA
+		 */
 		if (likely(&drv_last_ie->wiphy == wiphy)) {
-			/* Ignore IEs coming in on this wiphy with
-			 * the same alpha2 and environment cap */
+			/*
+			 * Ignore IEs coming in on this wiphy with
+			 * the same alpha2 and environment cap
+			 */
 			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
 				  alpha2) &&
 				  env == drv_last_ie->env)) {
 				goto out;
 			}
-			/* the wiphy moved on to another BSSID or the AP
+			/*
+			 * the wiphy moved on to another BSSID or the AP
 			 * was reconfigured. XXX: We need to deal with the
 			 * case where the user suspends and goes to goes
 			 * to another country, and then gets IEs from an
-			 * AP with different settings */
+			 * AP with different settings
+			 */
 			goto out;
 		} else {
-			/* Ignore IEs coming in on two separate wiphys with
-			 * the same alpha2 and environment cap */
+			/*
+			 * Ignore IEs coming in on two separate wiphys with
+			 * the same alpha2 and environment cap
+			 */
 			if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
 				  alpha2) &&
 				  env == drv_last_ie->env)) {
@@ -1467,8 +1544,10 @@ void regulatory_hint_11d(struct wiphy *wiphy,
 	if (!request)
 		goto free_rd_out;
 
-	/* We keep this around for when CRDA comes back with a response so
-	 * we can intersect with that */
+	/*
+	 * We keep this around for when CRDA comes back with a response so
+	 * we can intersect with that
+	 */
 	country_ie_regdomain = rd;
 
 	request->wiphy_idx = get_wiphy_idx(wiphy);
@@ -1506,8 +1585,10 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
 		freq_range = &reg_rule->freq_range;
 		power_rule = &reg_rule->power_rule;
 
-		/* There may not be documentation for max antenna gain
-		 * in certain regions */
+		/*
+		 * There may not be documentation for max antenna gain
+		 * in certain regions
+		 */
 		if (power_rule->max_antenna_gain)
 			printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
 				"(%d mBi, %d mBm)\n",
@@ -1618,21 +1699,27 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 	if (!last_request)
 		return -EINVAL;
 
-	/* Lets only bother proceeding on the same alpha2 if the current
+	/*
+	 * Lets only bother proceeding on the same alpha2 if the current
 	 * rd is non static (it means CRDA was present and was used last)
-	 * and the pending request came in from a country IE */
+	 * and the pending request came in from a country IE
+	 */
 	if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
-		/* If someone else asked us to change the rd lets only bother
-		 * checking if the alpha2 changes if CRDA was already called */
+		/*
+		 * If someone else asked us to change the rd lets only bother
+		 * checking if the alpha2 changes if CRDA was already called
+		 */
 		if (!is_old_static_regdom(cfg80211_regdomain) &&
 		    !regdom_changed(rd->alpha2))
 			return -EINVAL;
 	}
 
-	/* Now lets set the regulatory domain, update all driver channels
+	/*
+	 * Now lets set the regulatory domain, update all driver channels
 	 * and finally inform them of what we have done, in case they want
 	 * to review or adjust their own settings based on their own
-	 * internal EEPROM data */
+	 * internal EEPROM data
+	 */
 
 	if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
 		return -EINVAL;
@@ -1655,8 +1742,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 			return 0;
 		}
 
-		/* For a driver hint, lets copy the regulatory domain the
-		 * driver wanted to the wiphy to deal with conflicts */
+		/*
+		 * For a driver hint, lets copy the regulatory domain the
+		 * driver wanted to the wiphy to deal with conflicts
+		 */
 
 		BUG_ON(request_wiphy->regd);
 
@@ -1677,9 +1766,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		if (!intersected_rd)
 			return -EINVAL;
 
-		/* We can trash what CRDA provided now.
+		/*
+		 * We can trash what CRDA provided now.
 		 * However if a driver requested this specific regulatory
-		 * domain we keep it for its private use */
+		 * domain we keep it for its private use
+		 */
 		if (last_request->initiator == REGDOM_SET_BY_DRIVER)
 			request_wiphy->regd = rd;
 		else
@@ -1701,8 +1792,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 	BUG_ON(!country_ie_regdomain);
 
 	if (rd != country_ie_regdomain) {
-		/* Intersect what CRDA returned and our what we
-		 * had built from the Country IE received */
+		/*
+		 * Intersect what CRDA returned and our what we
+		 * had built from the Country IE received
+		 */
 
 		intersected_rd = regdom_intersect(rd, country_ie_regdomain);
 
@@ -1712,9 +1805,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		kfree(country_ie_regdomain);
 		country_ie_regdomain = NULL;
 	} else {
-		/* This would happen when CRDA was not present and
+		/*
+		 * This would happen when CRDA was not present and
 		 * OLD_REGULATORY was enabled. We intersect our Country
-		 * IE rd and what was set on cfg80211 originally */
+		 * IE rd and what was set on cfg80211 originally
+		 */
 		intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
 	}
 
@@ -1739,9 +1834,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 }
 
 
-/* Use this call to set the current regulatory domain. Conflicts with
+/*
+ * Use this call to set the current regulatory domain. Conflicts with
  * multiple drivers can be ironed out later. Caller must've already
- * kmalloc'd the rd structure. Caller must hold cfg80211_mutex */
+ * kmalloc'd the rd structure. Caller must hold cfg80211_mutex
+ */
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
 	int r;
@@ -1800,10 +1897,12 @@ int regulatory_init(void)
 
 	printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
 	print_regdomain_info(cfg80211_regdomain);
-	/* The old code still requests for a new regdomain and if
+	/*
+	 * The old code still requests for a new regdomain and if
 	 * you have CRDA you get it updated, otherwise you get
 	 * stuck with the static values. We ignore "EU" code as
-	 * that is not a valid ISO / IEC 3166 alpha2 */
+	 * that is not a valid ISO / IEC 3166 alpha2
+	 */
 	if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
 		err = regulatory_hint_core(ieee80211_regdom);
 #else
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 14/15] cfg80211: allow drivers that agree on regulatory to agree
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (12 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 13/15] cfg80211: comments style cleanup Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20  5:42 ` [PATCH v5 15/15] cfg80211: rename regdom_changed to regdom_changes() and use it Luis R. Rodriguez
  2009-02-20 17:03 ` [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Johannes Berg
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

This allows drivers that agree on regulatory to share their
regulatory domain.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index efa3ecd..0a8244e 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1157,6 +1157,16 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 				return 0;
 			return -EALREADY;
 		}
+
+		/*
+		 * This would happen if you unplug and plug your card
+		 * back in or if you add a new device for which the previously
+		 * loaded card also agrees on the regulatory domain.
+		 */
+		if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
+		    alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+			return -EALREADY;
+
 		return REG_INTERSECT;
 	case REGDOM_SET_BY_USER:
 		if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v5 15/15] cfg80211: rename regdom_changed to regdom_changes() and use it
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (13 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 14/15] cfg80211: allow drivers that agree on regulatory to agree Luis R. Rodriguez
@ 2009-02-20  5:42 ` Luis R. Rodriguez
  2009-02-20 17:03 ` [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Johannes Berg
  15 siblings, 0 replies; 17+ messages in thread
From: Luis R. Rodriguez @ 2009-02-20  5:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/wireless/reg.c |   19 ++++++++-----------
 1 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 0a8244e..605299f 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -291,7 +291,7 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
 	return false;
 }
 
-static bool regdom_changed(const char *alpha2)
+static bool regdom_changes(const char *alpha2)
 {
 	assert_cfg80211_lock();
 
@@ -1134,8 +1134,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 				 * intersect them, but that seems unlikely
 				 * to be correct. Reject second one for now.
 				 */
-				if (!alpha2_equal(alpha2,
-						  cfg80211_regdomain->alpha2))
+				if (regdom_changes(alpha2))
 					return -EOPNOTSUPP;
 				return -EALREADY;
 			}
@@ -1143,8 +1142,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 			 * Two consecutive Country IE hints on the same wiphy.
 			 * This should be picked up early by the driver/stack
 			 */
-			if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
-				  alpha2)))
+			if (WARN_ON(regdom_changes(alpha2)))
 				return 0;
 			return -EALREADY;
 		}
@@ -1153,7 +1151,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 		if (last_request->initiator == REGDOM_SET_BY_CORE) {
 			if (is_old_static_regdom(cfg80211_regdomain))
 				return 0;
-			if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+			if (regdom_changes(alpha2))
 				return 0;
 			return -EALREADY;
 		}
@@ -1164,7 +1162,7 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 		 * loaded card also agrees on the regulatory domain.
 		 */
 		if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
-		    alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+		    !regdom_changes(alpha2))
 			return -EALREADY;
 
 		return REG_INTERSECT;
@@ -1185,13 +1183,12 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
 		if (last_request->initiator == REGDOM_SET_BY_CORE ||
 		    last_request->initiator == REGDOM_SET_BY_DRIVER ||
 		    last_request->initiator == REGDOM_SET_BY_USER) {
-			if (!alpha2_equal(last_request->alpha2,
-			    cfg80211_regdomain->alpha2))
+			if (regdom_changes(last_request->alpha2))
 				return -EAGAIN;
 		}
 
 		if (!is_old_static_regdom(cfg80211_regdomain) &&
-		    alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+		    !regdom_changes(alpha2))
 			return -EALREADY;
 
 		return 0;
@@ -1720,7 +1717,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 		 * checking if the alpha2 changes if CRDA was already called
 		 */
 		if (!is_old_static_regdom(cfg80211_regdomain) &&
-		    !regdom_changed(rd->alpha2))
+		    !regdom_changes(rd->alpha2))
 			return -EINVAL;
 	}
 
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing
  2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
                   ` (14 preceding siblings ...)
  2009-02-20  5:42 ` [PATCH v5 15/15] cfg80211: rename regdom_changed to regdom_changes() and use it Luis R. Rodriguez
@ 2009-02-20 17:03 ` Johannes Berg
  15 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2009-02-20 17:03 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linville, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 407 bytes --]

On Fri, 2009-02-20 at 00:42 -0500, Luis R. Rodriguez wrote:
> This series has a few cleanups and minor fixes but mainly
> adds a workqueue for cfg80211 to use to process all regulatory
> hints. This v5 addresses one last comment from Johannes to remove
> an unlikely() as a WARN_ON() already has it and most importantly
> we do not call a spin_lock() before the cfg80211_mutex.

Thanks.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2009-02-20 17:04 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-20  5:42 [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 01/15] cfg80211: rename cfg80211_registered_device's idx to wiphy_idx Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 02/15] cfg80211: add wiphy_idx_valid to check for wiphy_idx sanity Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 03/15] cfg80211: rename cfg80211_drv_mutex to cfg80211_mutex Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 04/15] nl80211: disallow user requests prior to regulatory_init() Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 05/15] cfg80211: add regulatory_hint_core() to separate the core reg hint Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 06/15] cfg80211: propagate -ENOMEM during regulatory_init() Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 07/15] cfg80211: add assert_cfg80211_lock() to ensure proper protection Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 08/15] cfg80211: make regulatory_request use wiphy_idx instead of wiphy Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 09/15] cfg80211: protect first access of last_request on 11d hint under mutex Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 10/15] cfg80211: remove likely from an 11d hint case Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 11/15] cfg80211: free rd on unlikely event on 11d hint Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 12/15] cfg80211: move all regulatory hints to workqueue Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 13/15] cfg80211: comments style cleanup Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 14/15] cfg80211: allow drivers that agree on regulatory to agree Luis R. Rodriguez
2009-02-20  5:42 ` [PATCH v5 15/15] cfg80211: rename regdom_changed to regdom_changes() and use it Luis R. Rodriguez
2009-02-20 17:03 ` [PATCH v5 00/15] cfg80211: add a workqueue for regulatory processing Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.