summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/310-pending_cfg80211_fixes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/310-pending_cfg80211_fixes.patch')
-rw-r--r--package/mac80211/patches/310-pending_cfg80211_fixes.patch178
1 files changed, 178 insertions, 0 deletions
diff --git a/package/mac80211/patches/310-pending_cfg80211_fixes.patch b/package/mac80211/patches/310-pending_cfg80211_fixes.patch
new file mode 100644
index 000000000..f8334b447
--- /dev/null
+++ b/package/mac80211/patches/310-pending_cfg80211_fixes.patch
@@ -0,0 +1,178 @@
+--- 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(&reg_requests_lock);
++ if (!list_empty(&reg_requests_list))
++ need_more_processing = true;
++ spin_unlock(&reg_requests_lock);
++
++ if (need_more_processing)
++ schedule_work(&reg_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(&reg_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(&reg_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(&reg_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(&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);
+
++ if (list_empty(&reg_requests_list)) {
+ spin_unlock(&reg_requests_lock);
+- reg_process_hint(reg_request);
+- spin_lock(&reg_requests_lock);
++ goto out;
+ }
++
++ reg_request = list_first_entry(&reg_requests_list,
++ struct regulatory_request,
++ list);
++ list_del_init(&reg_request->list);
++
+ spin_unlock(&reg_requests_lock);
++
++ reg_process_hint(reg_request);
++
++out:
++ mutex_unlock(&reg_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(&reg_mutex);
+
+ return r;