diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ab801a1097b2..58d69959ab28 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -106,6 +106,9 @@ struct reg_beacon { | |||
106 | static void reg_todo(struct work_struct *work); | 106 | static void reg_todo(struct work_struct *work); |
107 | static DECLARE_WORK(reg_work, reg_todo); | 107 | static DECLARE_WORK(reg_work, reg_todo); |
108 | 108 | ||
109 | static void reg_timeout_work(struct work_struct *work); | ||
110 | static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | ||
111 | |||
109 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 112 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
110 | static const struct ieee80211_regdomain world_regdom = { | 113 | static const struct ieee80211_regdomain world_regdom = { |
111 | .n_reg_rules = 5, | 114 | .n_reg_rules = 5, |
@@ -1330,6 +1333,9 @@ static void reg_set_request_processed(void) | |||
1330 | need_more_processing = true; | 1333 | need_more_processing = true; |
1331 | spin_unlock(®_requests_lock); | 1334 | spin_unlock(®_requests_lock); |
1332 | 1335 | ||
1336 | if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) | ||
1337 | cancel_delayed_work_sync(®_timeout); | ||
1338 | |||
1333 | if (need_more_processing) | 1339 | if (need_more_processing) |
1334 | schedule_work(®_work); | 1340 | schedule_work(®_work); |
1335 | } | 1341 | } |
@@ -1440,8 +1446,17 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1440 | r = __regulatory_hint(wiphy, reg_request); | 1446 | r = __regulatory_hint(wiphy, reg_request); |
1441 | /* This is required so that the orig_* parameters are saved */ | 1447 | /* This is required so that the orig_* parameters are saved */ |
1442 | if (r == -EALREADY && wiphy && | 1448 | if (r == -EALREADY && wiphy && |
1443 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1449 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { |
1444 | wiphy_update_regulatory(wiphy, initiator); | 1450 | wiphy_update_regulatory(wiphy, initiator); |
1451 | return; | ||
1452 | } | ||
1453 | |||
1454 | /* | ||
1455 | * We only time out user hints, given that they should be the only | ||
1456 | * source of bogus requests. | ||
1457 | */ | ||
1458 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) | ||
1459 | schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); | ||
1445 | } | 1460 | } |
1446 | 1461 | ||
1447 | /* | 1462 | /* |
@@ -1744,6 +1759,8 @@ static void restore_regulatory_settings(bool reset_user) | |||
1744 | { | 1759 | { |
1745 | char alpha2[2]; | 1760 | char alpha2[2]; |
1746 | struct reg_beacon *reg_beacon, *btmp; | 1761 | struct reg_beacon *reg_beacon, *btmp; |
1762 | struct regulatory_request *reg_request, *tmp; | ||
1763 | LIST_HEAD(tmp_reg_req_list); | ||
1747 | 1764 | ||
1748 | mutex_lock(&cfg80211_mutex); | 1765 | mutex_lock(&cfg80211_mutex); |
1749 | mutex_lock(®_mutex); | 1766 | mutex_lock(®_mutex); |
@@ -1751,6 +1768,25 @@ static void restore_regulatory_settings(bool reset_user) | |||
1751 | reset_regdomains(); | 1768 | reset_regdomains(); |
1752 | restore_alpha2(alpha2, reset_user); | 1769 | restore_alpha2(alpha2, reset_user); |
1753 | 1770 | ||
1771 | /* | ||
1772 | * If there's any pending requests we simply | ||
1773 | * stash them to a temporary pending queue and | ||
1774 | * add then after we've restored regulatory | ||
1775 | * settings. | ||
1776 | */ | ||
1777 | spin_lock(®_requests_lock); | ||
1778 | if (!list_empty(®_requests_list)) { | ||
1779 | list_for_each_entry_safe(reg_request, tmp, | ||
1780 | ®_requests_list, list) { | ||
1781 | if (reg_request->initiator != | ||
1782 | NL80211_REGDOM_SET_BY_USER) | ||
1783 | continue; | ||
1784 | list_del(®_request->list); | ||
1785 | list_add_tail(®_request->list, &tmp_reg_req_list); | ||
1786 | } | ||
1787 | } | ||
1788 | spin_unlock(®_requests_lock); | ||
1789 | |||
1754 | /* Clear beacon hints */ | 1790 | /* Clear beacon hints */ |
1755 | spin_lock_bh(®_pending_beacons_lock); | 1791 | spin_lock_bh(®_pending_beacons_lock); |
1756 | if (!list_empty(®_pending_beacons)) { | 1792 | if (!list_empty(®_pending_beacons)) { |
@@ -1785,8 +1821,31 @@ static void restore_regulatory_settings(bool reset_user) | |||
1785 | */ | 1821 | */ |
1786 | if (is_an_alpha2(alpha2)) | 1822 | if (is_an_alpha2(alpha2)) |
1787 | regulatory_hint_user(user_alpha2); | 1823 | regulatory_hint_user(user_alpha2); |
1788 | } | ||
1789 | 1824 | ||
1825 | if (list_empty(&tmp_reg_req_list)) | ||
1826 | return; | ||
1827 | |||
1828 | mutex_lock(&cfg80211_mutex); | ||
1829 | mutex_lock(®_mutex); | ||
1830 | |||
1831 | spin_lock(®_requests_lock); | ||
1832 | list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { | ||
1833 | REG_DBG_PRINT("Adding request for country %c%c back " | ||
1834 | "into the queue\n", | ||
1835 | reg_request->alpha2[0], | ||
1836 | reg_request->alpha2[1]); | ||
1837 | list_del(®_request->list); | ||
1838 | list_add_tail(®_request->list, ®_requests_list); | ||
1839 | } | ||
1840 | spin_unlock(®_requests_lock); | ||
1841 | |||
1842 | mutex_unlock(®_mutex); | ||
1843 | mutex_unlock(&cfg80211_mutex); | ||
1844 | |||
1845 | REG_DBG_PRINT("Kicking the queue\n"); | ||
1846 | |||
1847 | schedule_work(®_work); | ||
1848 | } | ||
1790 | 1849 | ||
1791 | void regulatory_hint_disconnect(void) | 1850 | void regulatory_hint_disconnect(void) |
1792 | { | 1851 | { |
@@ -2125,6 +2184,13 @@ out: | |||
2125 | mutex_unlock(®_mutex); | 2184 | mutex_unlock(®_mutex); |
2126 | } | 2185 | } |
2127 | 2186 | ||
2187 | static void reg_timeout_work(struct work_struct *work) | ||
2188 | { | ||
2189 | REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " | ||
2190 | "restoring regulatory settings"); | ||
2191 | restore_regulatory_settings(true); | ||
2192 | } | ||
2193 | |||
2128 | int __init regulatory_init(void) | 2194 | int __init regulatory_init(void) |
2129 | { | 2195 | { |
2130 | int err = 0; | 2196 | int err = 0; |
@@ -2178,6 +2244,7 @@ void /* __init_or_exit */ regulatory_exit(void) | |||
2178 | struct reg_beacon *reg_beacon, *btmp; | 2244 | struct reg_beacon *reg_beacon, *btmp; |
2179 | 2245 | ||
2180 | cancel_work_sync(®_work); | 2246 | cancel_work_sync(®_work); |
2247 | cancel_delayed_work_sync(®_timeout); | ||
2181 | 2248 | ||
2182 | mutex_lock(&cfg80211_mutex); | 2249 | mutex_lock(&cfg80211_mutex); |
2183 | mutex_lock(®_mutex); | 2250 | mutex_lock(®_mutex); |