linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] cfg80211: Make NL80211_CMD_SET_REG synchronous
@ 2010-12-07  9:45 Helmut Schaa
  2010-12-07  9:53 ` Johannes Berg
  0 siblings, 1 reply; 3+ messages in thread
From: Helmut Schaa @ 2010-12-07  9:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: Helmut Schaa, Johannes Berg, Luis R. Rodriguez

A user space caller of NL80211_CMD_SET_REG previously had no chance to
verify if the regulatory domain change it requested already happened.
Listening to NL80211_CMD_REG_CHANGE is not enough since it won't be
triggered when the regulatory domain didn't change (for example because
it was already the same before).

Fix this by making NL80211_CMD_SET_REG synchronous by adding a
completion struct to the regulatory_hint_user function and wait for the
completion of the regulatory request before returning.

This fixes a problem with hostapd setting the regulatory domain but
reading the channel list directly after NL80211_CMD_SET_REG returned
which resulted in an incorrect channel list and thus prohibited the use
of channels allowed within the new regulatory domain. This applies at
least to drivers not enforcing their own regulatory domain (for example
rt2x00).

Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: "Luis R. Rodriguez" <lrodriguez@atheros.com> 
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
---

Based on a user report in the rt2x00 forums.

Any better ideas? Any objections?

Thanks,
Helmut

 include/net/regulatory.h |    1 +
 net/wireless/nl80211.c   |    5 ++++-
 net/wireless/reg.c       |   15 +++++++++++----
 net/wireless/reg.h       |    2 +-
 4 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 356d6e3..e58a744 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -62,6 +62,7 @@ struct regulatory_request {
 	bool intersect;
 	bool processed;
 	enum environment_cap country_ie_env;
+	struct completion *completion;
 	struct list_head list;
 };
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 56508d4..8e76a63 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2535,6 +2535,7 @@ static int parse_reg_rule(struct nlattr *tb[],
 
 static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
+	DECLARE_COMPLETION_ONSTACK(completion);
 	int r;
 	char *data = NULL;
 
@@ -2556,7 +2557,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 
 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 
-	r = regulatory_hint_user(data);
+	r = regulatory_hint_user(data, &completion);
+
+	wait_for_completion_interruptible(&completion);
 
 	return r;
 }
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 5ed615f..84787e3 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1428,6 +1428,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 	int r = 0;
 	struct wiphy *wiphy = NULL;
 	enum nl80211_reg_initiator initiator = reg_request->initiator;
+	struct completion *completion = reg_request->completion;
 
 	BUG_ON(!reg_request->alpha2);
 
@@ -1437,7 +1438,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 	if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
 	    !wiphy) {
 		kfree(reg_request);
-		return;
+		goto out;
 	}
 
 	r = __regulatory_hint(wiphy, reg_request);
@@ -1445,6 +1446,11 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 	if (r == -EALREADY && wiphy &&
 	    wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
 		wiphy_update_regulatory(wiphy, initiator);
+
+out:
+	/* Mark this reg request done */
+	if (completion)
+		complete_all(completion);
 }
 
 /*
@@ -1571,7 +1577,7 @@ static int regulatory_hint_core(const char *alpha2)
 }
 
 /* User hints */
-int regulatory_hint_user(const char *alpha2)
+int regulatory_hint_user(const char *alpha2, struct completion *completion)
 {
 	struct regulatory_request *request;
 
@@ -1585,6 +1591,7 @@ int regulatory_hint_user(const char *alpha2)
 	request->alpha2[0] = alpha2[0];
 	request->alpha2[1] = alpha2[1];
 	request->initiator = NL80211_REGDOM_SET_BY_USER;
+	request->completion = completion;
 
 	queue_regulatory_request(request);
 
@@ -1787,7 +1794,7 @@ static void restore_regulatory_settings(bool reset_user)
 	 * settings, user regulatory settings takes precedence.
 	 */
 	if (is_an_alpha2(alpha2))
-		regulatory_hint_user(user_alpha2);
+		regulatory_hint_user(user_alpha2, NULL);
 }
 
 
@@ -2149,7 +2156,7 @@ int __init regulatory_init(void)
 	 * as a user hint.
 	 */
 	if (!is_world_regdom(ieee80211_regdom))
-		regulatory_hint_user(ieee80211_regdom);
+		regulatory_hint_user(ieee80211_regdom, NULL);
 
 	return 0;
 }
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index c4695d0..8be4d42 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -6,7 +6,7 @@ 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);
+int regulatory_hint_user(const char *alpha2, struct completion *completion);
 
 void reg_device_remove(struct wiphy *wiphy);
 
-- 
1.7.1


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

end of thread, other threads:[~2010-12-07 10:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-07  9:45 [RFC] cfg80211: Make NL80211_CMD_SET_REG synchronous Helmut Schaa
2010-12-07  9:53 ` Johannes Berg
2010-12-07 10:27   ` Helmut Schaa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).