mac80211: merge pending cfg80211 patches to fix a race condition with setting the regdomain for multiple cards
SVN-Revision: 24028
This commit is contained in:
parent
ba5296268c
commit
f9d20beed7
1 changed files with 178 additions and 0 deletions
|
@ -112,3 +112,181 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
--- a/include/net/regulatory.h
|
||||
+++ b/include/net/regulatory.h
|
||||
@@ -43,6 +43,12 @@ enum environment_cap {
|
||||
* @intersect: indicates whether the wireless core should intersect
|
||||
* the requested regulatory domain with the presently set regulatory
|
||||
* domain.
|
||||
+ * @processed: indicates whether or not this requests has already been
|
||||
+ * processed. When the last request is processed it means that the
|
||||
+ * currently regulatory domain set on cfg80211 is updated from
|
||||
+ * CRDA and can be used by other regulatory requests. When a
|
||||
+ * the last request is not yet processed we must yield until it
|
||||
+ * is processed before processing any new requests.
|
||||
* @country_ie_checksum: checksum of the last processed and accepted
|
||||
* country IE
|
||||
* @country_ie_env: lets us know if the AP is telling us we are outdoor,
|
||||
@@ -54,6 +60,7 @@ struct regulatory_request {
|
||||
enum nl80211_reg_initiator initiator;
|
||||
char alpha2[2];
|
||||
bool intersect;
|
||||
+ bool processed;
|
||||
enum environment_cap country_ie_env;
|
||||
struct list_head list;
|
||||
};
|
||||
--- a/net/wireless/reg.c
|
||||
+++ b/net/wireless/reg.c
|
||||
@@ -96,6 +96,9 @@ struct reg_beacon {
|
||||
struct ieee80211_channel chan;
|
||||
};
|
||||
|
||||
+static void reg_todo(struct work_struct *work);
|
||||
+static DECLARE_WORK(reg_work, reg_todo);
|
||||
+
|
||||
/* We keep a static world regulatory domain in case of the absence of CRDA */
|
||||
static const struct ieee80211_regdomain world_regdom = {
|
||||
.n_reg_rules = 5,
|
||||
@@ -1317,6 +1320,21 @@ static int ignore_request(struct wiphy *
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static void reg_set_request_processed(void)
|
||||
+{
|
||||
+ bool need_more_processing = false;
|
||||
+
|
||||
+ last_request->processed = true;
|
||||
+
|
||||
+ spin_lock(®_requests_lock);
|
||||
+ if (!list_empty(®_requests_list))
|
||||
+ need_more_processing = true;
|
||||
+ spin_unlock(®_requests_lock);
|
||||
+
|
||||
+ if (need_more_processing)
|
||||
+ schedule_work(®_work);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* __regulatory_hint - hint to the wireless core a regulatory domain
|
||||
* @wiphy: if the hint comes from country information from an AP, this
|
||||
@@ -1392,8 +1410,10 @@ new_request:
|
||||
* have applied the requested regulatory domain before we just
|
||||
* inform userspace we have processed the request
|
||||
*/
|
||||
- if (r == -EALREADY)
|
||||
+ if (r == -EALREADY) {
|
||||
nl80211_send_reg_change_event(last_request);
|
||||
+ reg_set_request_processed();
|
||||
+ }
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1409,16 +1429,13 @@ static void reg_process_hint(struct regu
|
||||
|
||||
BUG_ON(!reg_request->alpha2);
|
||||
|
||||
- mutex_lock(&cfg80211_mutex);
|
||||
- mutex_lock(®_mutex);
|
||||
-
|
||||
if (wiphy_idx_valid(reg_request->wiphy_idx))
|
||||
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
|
||||
|
||||
if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
!wiphy) {
|
||||
kfree(reg_request);
|
||||
- goto out;
|
||||
+ return;
|
||||
}
|
||||
|
||||
r = __regulatory_hint(wiphy, reg_request);
|
||||
@@ -1426,28 +1443,46 @@ static void reg_process_hint(struct regu
|
||||
if (r == -EALREADY && wiphy &&
|
||||
wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
|
||||
wiphy_update_regulatory(wiphy, initiator);
|
||||
-out:
|
||||
- mutex_unlock(®_mutex);
|
||||
- mutex_unlock(&cfg80211_mutex);
|
||||
}
|
||||
|
||||
-/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */
|
||||
+/*
|
||||
+ * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_*
|
||||
+ * Regulatory hints come on a first come first serve basis and we
|
||||
+ * must process each one atomically.
|
||||
+ */
|
||||
static void reg_process_pending_hints(void)
|
||||
- {
|
||||
+{
|
||||
struct regulatory_request *reg_request;
|
||||
|
||||
+ mutex_lock(&cfg80211_mutex);
|
||||
+ mutex_lock(®_mutex);
|
||||
+
|
||||
+ /* When last_request->processed becomes true this will be rescheduled */
|
||||
+ if (last_request && !last_request->processed) {
|
||||
+ REG_DBG_PRINT("Pending regulatory request, waiting "
|
||||
+ "for it to be processed...");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
spin_lock(®_requests_lock);
|
||||
- while (!list_empty(®_requests_list)) {
|
||||
- reg_request = list_first_entry(®_requests_list,
|
||||
- struct regulatory_request,
|
||||
- list);
|
||||
- list_del_init(®_request->list);
|
||||
|
||||
+ if (list_empty(®_requests_list)) {
|
||||
spin_unlock(®_requests_lock);
|
||||
- reg_process_hint(reg_request);
|
||||
- spin_lock(®_requests_lock);
|
||||
+ goto out;
|
||||
}
|
||||
+
|
||||
+ reg_request = list_first_entry(®_requests_list,
|
||||
+ struct regulatory_request,
|
||||
+ list);
|
||||
+ list_del_init(®_request->list);
|
||||
+
|
||||
spin_unlock(®_requests_lock);
|
||||
+
|
||||
+ reg_process_hint(reg_request);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(®_mutex);
|
||||
+ mutex_unlock(&cfg80211_mutex);
|
||||
}
|
||||
|
||||
/* Processes beacon hints -- this has nothing to do with country IEs */
|
||||
@@ -1494,8 +1529,6 @@ static void reg_todo(struct work_struct
|
||||
reg_process_pending_beacon_hints();
|
||||
}
|
||||
|
||||
-static DECLARE_WORK(reg_work, reg_todo);
|
||||
-
|
||||
static void queue_regulatory_request(struct regulatory_request *request)
|
||||
{
|
||||
if (isalpha(request->alpha2[0]))
|
||||
@@ -1530,12 +1563,7 @@ static int regulatory_hint_core(const ch
|
||||
request->alpha2[1] = alpha2[1];
|
||||
request->initiator = NL80211_REGDOM_SET_BY_CORE;
|
||||
|
||||
- /*
|
||||
- * This ensures last_request is populated once modules
|
||||
- * come swinging in and calling regulatory hints and
|
||||
- * wiphy_apply_custom_regulatory().
|
||||
- */
|
||||
- reg_process_hint(request);
|
||||
+ queue_regulatory_request(request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2061,6 +2089,8 @@ int set_regdom(const struct ieee80211_re
|
||||
|
||||
nl80211_send_reg_change_event(last_request);
|
||||
|
||||
+ reg_set_request_processed();
|
||||
+
|
||||
mutex_unlock(®_mutex);
|
||||
|
||||
return r;
|
||||
|
|
Loading…
Reference in a new issue