diff options
| -rw-r--r-- | package/mac80211/patches/310-pending_work.patch | 178 | 
1 files changed, 178 insertions, 0 deletions
diff --git a/package/mac80211/patches/310-pending_work.patch b/package/mac80211/patches/310-pending_work.patch index b693b0a6d..ea02fcbc1 100644 --- a/package/mac80211/patches/310-pending_work.patch +++ b/package/mac80211/patches/310-pending_work.patch @@ -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;  | 
