1 --- a/include/net/regulatory.h
2 +++ b/include/net/regulatory.h
3 @@ -43,6 +43,12 @@ enum environment_cap {
4 * @intersect: indicates whether the wireless core should intersect
5 * the requested regulatory domain with the presently set regulatory
7 + * @processed: indicates whether or not this requests has already been
8 + * processed. When the last request is processed it means that the
9 + * currently regulatory domain set on cfg80211 is updated from
10 + * CRDA and can be used by other regulatory requests. When a
11 + * the last request is not yet processed we must yield until it
12 + * is processed before processing any new requests.
13 * @country_ie_checksum: checksum of the last processed and accepted
15 * @country_ie_env: lets us know if the AP is telling us we are outdoor,
16 @@ -54,6 +60,7 @@ struct regulatory_request {
17 enum nl80211_reg_initiator initiator;
21 enum environment_cap country_ie_env;
22 struct list_head list;
24 --- a/net/wireless/reg.c
25 +++ b/net/wireless/reg.c
26 @@ -96,6 +96,9 @@ struct reg_beacon {
27 struct ieee80211_channel chan;
30 +static void reg_todo(struct work_struct *work);
31 +static DECLARE_WORK(reg_work, reg_todo);
33 /* We keep a static world regulatory domain in case of the absence of CRDA */
34 static const struct ieee80211_regdomain world_regdom = {
36 @@ -1317,6 +1320,21 @@ static int ignore_request(struct wiphy *
40 +static void reg_set_request_processed(void)
42 + bool need_more_processing = false;
44 + last_request->processed = true;
46 + spin_lock(®_requests_lock);
47 + if (!list_empty(®_requests_list))
48 + need_more_processing = true;
49 + spin_unlock(®_requests_lock);
51 + if (need_more_processing)
52 + schedule_work(®_work);
56 * __regulatory_hint - hint to the wireless core a regulatory domain
57 * @wiphy: if the hint comes from country information from an AP, this
58 @@ -1392,8 +1410,10 @@ new_request:
59 * have applied the requested regulatory domain before we just
60 * inform userspace we have processed the request
63 + if (r == -EALREADY) {
64 nl80211_send_reg_change_event(last_request);
65 + reg_set_request_processed();
70 @@ -1409,16 +1429,13 @@ static void reg_process_hint(struct regu
72 BUG_ON(!reg_request->alpha2);
74 - mutex_lock(&cfg80211_mutex);
75 - mutex_lock(®_mutex);
77 if (wiphy_idx_valid(reg_request->wiphy_idx))
78 wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
80 if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
87 r = __regulatory_hint(wiphy, reg_request);
88 @@ -1426,28 +1443,46 @@ static void reg_process_hint(struct regu
89 if (r == -EALREADY && wiphy &&
90 wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
91 wiphy_update_regulatory(wiphy, initiator);
93 - mutex_unlock(®_mutex);
94 - mutex_unlock(&cfg80211_mutex);
97 -/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */
99 + * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_*
100 + * Regulatory hints come on a first come first serve basis and we
101 + * must process each one atomically.
103 static void reg_process_pending_hints(void)
106 struct regulatory_request *reg_request;
108 + mutex_lock(&cfg80211_mutex);
109 + mutex_lock(®_mutex);
111 + /* When last_request->processed becomes true this will be rescheduled */
112 + if (last_request && !last_request->processed) {
113 + REG_DBG_PRINT("Pending regulatory request, waiting "
114 + "for it to be processed...");
118 spin_lock(®_requests_lock);
119 - while (!list_empty(®_requests_list)) {
120 - reg_request = list_first_entry(®_requests_list,
121 - struct regulatory_request,
123 - list_del_init(®_request->list);
125 + if (list_empty(®_requests_list)) {
126 spin_unlock(®_requests_lock);
127 - reg_process_hint(reg_request);
128 - spin_lock(®_requests_lock);
132 + reg_request = list_first_entry(®_requests_list,
133 + struct regulatory_request,
135 + list_del_init(®_request->list);
137 spin_unlock(®_requests_lock);
139 + reg_process_hint(reg_request);
142 + mutex_unlock(®_mutex);
143 + mutex_unlock(&cfg80211_mutex);
146 /* Processes beacon hints -- this has nothing to do with country IEs */
147 @@ -1494,8 +1529,6 @@ static void reg_todo(struct work_struct
148 reg_process_pending_beacon_hints();
151 -static DECLARE_WORK(reg_work, reg_todo);
153 static void queue_regulatory_request(struct regulatory_request *request)
155 if (isalpha(request->alpha2[0]))
156 @@ -1530,12 +1563,7 @@ static int regulatory_hint_core(const ch
157 request->alpha2[1] = alpha2[1];
158 request->initiator = NL80211_REGDOM_SET_BY_CORE;
161 - * This ensures last_request is populated once modules
162 - * come swinging in and calling regulatory hints and
163 - * wiphy_apply_custom_regulatory().
165 - reg_process_hint(request);
166 + queue_regulatory_request(request);
170 @@ -2061,6 +2089,8 @@ int set_regdom(const struct ieee80211_re
172 nl80211_send_reg_change_event(last_request);
174 + reg_set_request_processed();
176 mutex_unlock(®_mutex);