X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=net%2Fwireless%2Freg.c;h=02751dbc5a97fab55abdefb9936dfc24c2d4ef22;hp=ab801a1097b2aa924c935805ce8e8a1656e39254;hb=e5036c2575b244851637a81efc4104c076c4fa21;hpb=b73077eb03f510a84b102fb97640e595a958403c diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ab801a1097b2..02751dbc5a97 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -106,6 +106,9 @@ struct reg_beacon { static void reg_todo(struct work_struct *work); static DECLARE_WORK(reg_work, reg_todo); +static void reg_timeout_work(struct work_struct *work); +static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); + /* 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, @@ -669,11 +672,9 @@ static int freq_reg_info_regd(struct wiphy *wiphy, for (i = 0; i < regd->n_reg_rules; i++) { const struct ieee80211_reg_rule *rr; const struct ieee80211_freq_range *fr = NULL; - const struct ieee80211_power_rule *pr = NULL; rr = ®d->reg_rules[i]; fr = &rr->freq_range; - pr = &rr->power_rule; /* * We only need to know if one frequency rule was @@ -902,7 +903,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && !is_world_regdom(last_request->alpha2)) { REG_DBG_PRINT("Ignoring regulatory request %s " - "since the driver requires its own regulaotry " + "since the driver requires its own regulatory " "domain to be set first", reg_initiator_name(initiator)); return true; @@ -1124,12 +1125,13 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum ieee80211_band band; if (ignore_reg_update(wiphy, initiator)) - goto out; + return; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (wiphy->bands[band]) handle_band(wiphy, band, initiator); } -out: + reg_process_beacons(wiphy); reg_process_ht_flags(wiphy); if (wiphy->reg_notifier) @@ -1330,6 +1332,9 @@ static void reg_set_request_processed(void) need_more_processing = true; spin_unlock(®_requests_lock); + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) + cancel_delayed_work_sync(®_timeout); + if (need_more_processing) schedule_work(®_work); } @@ -1440,8 +1445,18 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ if (r == -EALREADY && wiphy && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { wiphy_update_regulatory(wiphy, initiator); + return; + } + + /* + * We only time out user hints, given that they should be the only + * source of bogus requests. + */ + if (r != -EALREADY && + reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); } /* @@ -1744,6 +1759,8 @@ static void restore_regulatory_settings(bool reset_user) { char alpha2[2]; struct reg_beacon *reg_beacon, *btmp; + struct regulatory_request *reg_request, *tmp; + LIST_HEAD(tmp_reg_req_list); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); @@ -1751,6 +1768,25 @@ static void restore_regulatory_settings(bool reset_user) reset_regdomains(); restore_alpha2(alpha2, reset_user); + /* + * If there's any pending requests we simply + * stash them to a temporary pending queue and + * add then after we've restored regulatory + * settings. + */ + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) { + list_for_each_entry_safe(reg_request, tmp, + ®_requests_list, list) { + if (reg_request->initiator != + NL80211_REGDOM_SET_BY_USER) + continue; + list_del(®_request->list); + list_add_tail(®_request->list, &tmp_reg_req_list); + } + } + spin_unlock(®_requests_lock); + /* Clear beacon hints */ spin_lock_bh(®_pending_beacons_lock); if (!list_empty(®_pending_beacons)) { @@ -1785,8 +1821,31 @@ static void restore_regulatory_settings(bool reset_user) */ if (is_an_alpha2(alpha2)) regulatory_hint_user(user_alpha2); -} + if (list_empty(&tmp_reg_req_list)) + return; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + spin_lock(®_requests_lock); + list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { + REG_DBG_PRINT("Adding request for country %c%c back " + "into the queue\n", + reg_request->alpha2[0], + reg_request->alpha2[1]); + list_del(®_request->list); + list_add_tail(®_request->list, ®_requests_list); + } + spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + REG_DBG_PRINT("Kicking the queue\n"); + + schedule_work(®_work); +} void regulatory_hint_disconnect(void) { @@ -2125,6 +2184,13 @@ out: mutex_unlock(®_mutex); } +static void reg_timeout_work(struct work_struct *work) +{ + REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " + "restoring regulatory settings"); + restore_regulatory_settings(true); +} + int __init regulatory_init(void) { int err = 0; @@ -2178,6 +2244,7 @@ void /* __init_or_exit */ regulatory_exit(void) struct reg_beacon *reg_beacon, *btmp; cancel_work_sync(®_work); + cancel_delayed_work_sync(®_timeout); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex);