diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 169 |
1 files changed, 74 insertions, 95 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 75a406d33619..f256dfffbf46 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; | |||
62 | */ | 62 | */ |
63 | static const struct ieee80211_regdomain *country_ie_regdomain; | 63 | static const struct ieee80211_regdomain *country_ie_regdomain; |
64 | 64 | ||
65 | /* | ||
66 | * Protects static reg.c components: | ||
67 | * - cfg80211_world_regdom | ||
68 | * - cfg80211_regdom | ||
69 | * - country_ie_regdomain | ||
70 | * - last_request | ||
71 | */ | ||
72 | DEFINE_MUTEX(reg_mutex); | ||
73 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | ||
74 | |||
65 | /* Used to queue up regulatory hints */ | 75 | /* Used to queue up regulatory hints */ |
66 | static LIST_HEAD(reg_requests_list); | 76 | static LIST_HEAD(reg_requests_list); |
67 | static spinlock_t reg_requests_lock; | 77 | static spinlock_t reg_requests_lock; |
@@ -113,11 +123,7 @@ static const struct ieee80211_regdomain world_regdom = { | |||
113 | static const struct ieee80211_regdomain *cfg80211_world_regdom = | 123 | static const struct ieee80211_regdomain *cfg80211_world_regdom = |
114 | &world_regdom; | 124 | &world_regdom; |
115 | 125 | ||
116 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
117 | static char *ieee80211_regdom = "US"; | ||
118 | #else | ||
119 | static char *ieee80211_regdom = "00"; | 126 | static char *ieee80211_regdom = "00"; |
120 | #endif | ||
121 | 127 | ||
122 | module_param(ieee80211_regdom, charp, 0444); | 128 | module_param(ieee80211_regdom, charp, 0444); |
123 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 129 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
@@ -1012,7 +1018,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1012 | map_regdom_flags(reg_rule->flags) | bw_flags; | 1018 | map_regdom_flags(reg_rule->flags) | bw_flags; |
1013 | chan->max_antenna_gain = chan->orig_mag = | 1019 | chan->max_antenna_gain = chan->orig_mag = |
1014 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1015 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1016 | chan->max_power = chan->orig_mpwr = | 1021 | chan->max_power = chan->orig_mpwr = |
1017 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1022 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1018 | return; | 1023 | return; |
@@ -1021,7 +1026,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1021 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 1026 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
1022 | chan->max_antenna_gain = min(chan->orig_mag, | 1027 | chan->max_antenna_gain = min(chan->orig_mag, |
1023 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 1028 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
1024 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1025 | if (chan->orig_mpwr) | 1029 | if (chan->orig_mpwr) |
1026 | chan->max_power = min(chan->orig_mpwr, | 1030 | chan->max_power = min(chan->orig_mpwr, |
1027 | (int) MBM_TO_DBM(power_rule->max_eirp)); | 1031 | (int) MBM_TO_DBM(power_rule->max_eirp)); |
@@ -1061,10 +1065,10 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
1061 | 1065 | ||
1062 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | 1066 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) |
1063 | { | 1067 | { |
1064 | struct cfg80211_registered_device *drv; | 1068 | struct cfg80211_registered_device *rdev; |
1065 | 1069 | ||
1066 | list_for_each_entry(drv, &cfg80211_drv_list, list) | 1070 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) |
1067 | wiphy_update_regulatory(&drv->wiphy, initiator); | 1071 | wiphy_update_regulatory(&rdev->wiphy, initiator); |
1068 | } | 1072 | } |
1069 | 1073 | ||
1070 | static void handle_reg_beacon(struct wiphy *wiphy, | 1074 | static void handle_reg_beacon(struct wiphy *wiphy, |
@@ -1298,7 +1302,7 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1298 | struct ieee80211_supported_band *sband; | 1302 | struct ieee80211_supported_band *sband; |
1299 | struct ieee80211_channel *chan; | 1303 | struct ieee80211_channel *chan; |
1300 | 1304 | ||
1301 | assert_cfg80211_lock(); | 1305 | assert_reg_lock(); |
1302 | 1306 | ||
1303 | sband = wiphy->bands[band]; | 1307 | sband = wiphy->bands[band]; |
1304 | BUG_ON(chan_idx >= sband->n_channels); | 1308 | BUG_ON(chan_idx >= sband->n_channels); |
@@ -1323,7 +1327,6 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1323 | 1327 | ||
1324 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1328 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1325 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1329 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1326 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1327 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 1330 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
1328 | } | 1331 | } |
1329 | 1332 | ||
@@ -1347,14 +1350,14 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1347 | enum ieee80211_band band; | 1350 | enum ieee80211_band band; |
1348 | unsigned int bands_set = 0; | 1351 | unsigned int bands_set = 0; |
1349 | 1352 | ||
1350 | mutex_lock(&cfg80211_mutex); | 1353 | mutex_lock(®_mutex); |
1351 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1354 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1352 | if (!wiphy->bands[band]) | 1355 | if (!wiphy->bands[band]) |
1353 | continue; | 1356 | continue; |
1354 | handle_band_custom(wiphy, band, regd); | 1357 | handle_band_custom(wiphy, band, regd); |
1355 | bands_set++; | 1358 | bands_set++; |
1356 | } | 1359 | } |
1357 | mutex_unlock(&cfg80211_mutex); | 1360 | mutex_unlock(®_mutex); |
1358 | 1361 | ||
1359 | /* | 1362 | /* |
1360 | * no point in calling this if it won't have any effect | 1363 | * no point in calling this if it won't have any effect |
@@ -1421,7 +1424,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1421 | if (last_wiphy != wiphy) { | 1424 | if (last_wiphy != wiphy) { |
1422 | /* | 1425 | /* |
1423 | * Two cards with two APs claiming different | 1426 | * Two cards with two APs claiming different |
1424 | * different Country IE alpha2s. We could | 1427 | * Country IE alpha2s. We could |
1425 | * intersect them, but that seems unlikely | 1428 | * intersect them, but that seems unlikely |
1426 | * to be correct. Reject second one for now. | 1429 | * to be correct. Reject second one for now. |
1427 | */ | 1430 | */ |
@@ -1500,7 +1503,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1500 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | 1503 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had |
1501 | * already been set or other standard error codes. | 1504 | * already been set or other standard error codes. |
1502 | * | 1505 | * |
1503 | * Caller must hold &cfg80211_mutex | 1506 | * Caller must hold &cfg80211_mutex and ®_mutex |
1504 | */ | 1507 | */ |
1505 | static int __regulatory_hint(struct wiphy *wiphy, | 1508 | static int __regulatory_hint(struct wiphy *wiphy, |
1506 | struct regulatory_request *pending_request) | 1509 | struct regulatory_request *pending_request) |
@@ -1575,6 +1578,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1575 | BUG_ON(!reg_request->alpha2); | 1578 | BUG_ON(!reg_request->alpha2); |
1576 | 1579 | ||
1577 | mutex_lock(&cfg80211_mutex); | 1580 | mutex_lock(&cfg80211_mutex); |
1581 | mutex_lock(®_mutex); | ||
1578 | 1582 | ||
1579 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | 1583 | if (wiphy_idx_valid(reg_request->wiphy_idx)) |
1580 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1584 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
@@ -1590,6 +1594,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1590 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) | 1594 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) |
1591 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1595 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1592 | out: | 1596 | out: |
1597 | mutex_unlock(®_mutex); | ||
1593 | mutex_unlock(&cfg80211_mutex); | 1598 | mutex_unlock(&cfg80211_mutex); |
1594 | } | 1599 | } |
1595 | 1600 | ||
@@ -1615,9 +1620,13 @@ static void reg_process_pending_hints(void) | |||
1615 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 1620 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
1616 | static void reg_process_pending_beacon_hints(void) | 1621 | static void reg_process_pending_beacon_hints(void) |
1617 | { | 1622 | { |
1618 | struct cfg80211_registered_device *drv; | 1623 | struct cfg80211_registered_device *rdev; |
1619 | struct reg_beacon *pending_beacon, *tmp; | 1624 | struct reg_beacon *pending_beacon, *tmp; |
1620 | 1625 | ||
1626 | /* | ||
1627 | * No need to hold the reg_mutex here as we just touch wiphys | ||
1628 | * and do not read or access regulatory variables. | ||
1629 | */ | ||
1621 | mutex_lock(&cfg80211_mutex); | 1630 | mutex_lock(&cfg80211_mutex); |
1622 | 1631 | ||
1623 | /* This goes through the _pending_ beacon list */ | 1632 | /* This goes through the _pending_ beacon list */ |
@@ -1634,8 +1643,8 @@ static void reg_process_pending_beacon_hints(void) | |||
1634 | list_del_init(&pending_beacon->list); | 1643 | list_del_init(&pending_beacon->list); |
1635 | 1644 | ||
1636 | /* Applies the beacon hint to current wiphys */ | 1645 | /* Applies the beacon hint to current wiphys */ |
1637 | list_for_each_entry(drv, &cfg80211_drv_list, list) | 1646 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) |
1638 | wiphy_update_new_beacon(&drv->wiphy, pending_beacon); | 1647 | wiphy_update_new_beacon(&rdev->wiphy, pending_beacon); |
1639 | 1648 | ||
1640 | /* Remembers the beacon hint for new wiphys or reg changes */ | 1649 | /* Remembers the beacon hint for new wiphys or reg changes */ |
1641 | list_add_tail(&pending_beacon->list, ®_beacon_list); | 1650 | list_add_tail(&pending_beacon->list, ®_beacon_list); |
@@ -1739,12 +1748,13 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
1739 | } | 1748 | } |
1740 | EXPORT_SYMBOL(regulatory_hint); | 1749 | EXPORT_SYMBOL(regulatory_hint); |
1741 | 1750 | ||
1751 | /* Caller must hold reg_mutex */ | ||
1742 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1752 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
1743 | u32 country_ie_checksum) | 1753 | u32 country_ie_checksum) |
1744 | { | 1754 | { |
1745 | struct wiphy *request_wiphy; | 1755 | struct wiphy *request_wiphy; |
1746 | 1756 | ||
1747 | assert_cfg80211_lock(); | 1757 | assert_reg_lock(); |
1748 | 1758 | ||
1749 | if (unlikely(last_request->initiator != | 1759 | if (unlikely(last_request->initiator != |
1750 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | 1760 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) |
@@ -1767,6 +1777,10 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1767 | return false; | 1777 | return false; |
1768 | } | 1778 | } |
1769 | 1779 | ||
1780 | /* | ||
1781 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and | ||
1782 | * therefore cannot iterate over the rdev list here. | ||
1783 | */ | ||
1770 | void regulatory_hint_11d(struct wiphy *wiphy, | 1784 | void regulatory_hint_11d(struct wiphy *wiphy, |
1771 | u8 *country_ie, | 1785 | u8 *country_ie, |
1772 | u8 country_ie_len) | 1786 | u8 country_ie_len) |
@@ -1777,12 +1791,10 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1777 | enum environment_cap env = ENVIRON_ANY; | 1791 | enum environment_cap env = ENVIRON_ANY; |
1778 | struct regulatory_request *request; | 1792 | struct regulatory_request *request; |
1779 | 1793 | ||
1780 | mutex_lock(&cfg80211_mutex); | 1794 | mutex_lock(®_mutex); |
1781 | 1795 | ||
1782 | if (unlikely(!last_request)) { | 1796 | if (unlikely(!last_request)) |
1783 | mutex_unlock(&cfg80211_mutex); | 1797 | goto out; |
1784 | return; | ||
1785 | } | ||
1786 | 1798 | ||
1787 | /* IE len must be evenly divisible by 2 */ | 1799 | /* IE len must be evenly divisible by 2 */ |
1788 | if (country_ie_len & 0x01) | 1800 | if (country_ie_len & 0x01) |
@@ -1808,54 +1820,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1808 | env = ENVIRON_OUTDOOR; | 1820 | env = ENVIRON_OUTDOOR; |
1809 | 1821 | ||
1810 | /* | 1822 | /* |
1811 | * We will run this for *every* beacon processed for the BSSID, so | 1823 | * We will run this only upon a successful connection on cfg80211. |
1812 | * we optimize an early check to exit out early if we don't have to | 1824 | * We leave conflict resolution to the workqueue, where can hold |
1813 | * do anything | 1825 | * cfg80211_mutex. |
1814 | */ | 1826 | */ |
1815 | if (likely(last_request->initiator == | 1827 | if (likely(last_request->initiator == |
1816 | NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1828 | NL80211_REGDOM_SET_BY_COUNTRY_IE && |
1817 | wiphy_idx_valid(last_request->wiphy_idx))) { | 1829 | wiphy_idx_valid(last_request->wiphy_idx))) |
1818 | struct cfg80211_registered_device *drv_last_ie; | 1830 | goto out; |
1819 | |||
1820 | drv_last_ie = | ||
1821 | cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx); | ||
1822 | |||
1823 | /* | ||
1824 | * Lets keep this simple -- we trust the first AP | ||
1825 | * after we intersect with CRDA | ||
1826 | */ | ||
1827 | if (likely(&drv_last_ie->wiphy == wiphy)) { | ||
1828 | /* | ||
1829 | * Ignore IEs coming in on this wiphy with | ||
1830 | * the same alpha2 and environment cap | ||
1831 | */ | ||
1832 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | ||
1833 | alpha2) && | ||
1834 | env == drv_last_ie->env)) { | ||
1835 | goto out; | ||
1836 | } | ||
1837 | /* | ||
1838 | * the wiphy moved on to another BSSID or the AP | ||
1839 | * was reconfigured. XXX: We need to deal with the | ||
1840 | * case where the user suspends and goes to goes | ||
1841 | * to another country, and then gets IEs from an | ||
1842 | * AP with different settings | ||
1843 | */ | ||
1844 | goto out; | ||
1845 | } else { | ||
1846 | /* | ||
1847 | * Ignore IEs coming in on two separate wiphys with | ||
1848 | * the same alpha2 and environment cap | ||
1849 | */ | ||
1850 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | ||
1851 | alpha2) && | ||
1852 | env == drv_last_ie->env)) { | ||
1853 | goto out; | ||
1854 | } | ||
1855 | /* We could potentially intersect though */ | ||
1856 | goto out; | ||
1857 | } | ||
1858 | } | ||
1859 | 1831 | ||
1860 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 1832 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); |
1861 | if (!rd) | 1833 | if (!rd) |
@@ -1890,7 +1862,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1890 | request->country_ie_checksum = checksum; | 1862 | request->country_ie_checksum = checksum; |
1891 | request->country_ie_env = env; | 1863 | request->country_ie_env = env; |
1892 | 1864 | ||
1893 | mutex_unlock(&cfg80211_mutex); | 1865 | mutex_unlock(®_mutex); |
1894 | 1866 | ||
1895 | queue_regulatory_request(request); | 1867 | queue_regulatory_request(request); |
1896 | 1868 | ||
@@ -1899,9 +1871,8 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1899 | free_rd_out: | 1871 | free_rd_out: |
1900 | kfree(rd); | 1872 | kfree(rd); |
1901 | out: | 1873 | out: |
1902 | mutex_unlock(&cfg80211_mutex); | 1874 | mutex_unlock(®_mutex); |
1903 | } | 1875 | } |
1904 | EXPORT_SYMBOL(regulatory_hint_11d); | ||
1905 | 1876 | ||
1906 | static bool freq_is_chan_12_13_14(u16 freq) | 1877 | static bool freq_is_chan_12_13_14(u16 freq) |
1907 | { | 1878 | { |
@@ -1996,14 +1967,14 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1996 | 1967 | ||
1997 | if (last_request->initiator == | 1968 | if (last_request->initiator == |
1998 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1969 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { |
1999 | struct cfg80211_registered_device *drv; | 1970 | struct cfg80211_registered_device *rdev; |
2000 | drv = cfg80211_drv_by_wiphy_idx( | 1971 | rdev = cfg80211_rdev_by_wiphy_idx( |
2001 | last_request->wiphy_idx); | 1972 | last_request->wiphy_idx); |
2002 | if (drv) { | 1973 | if (rdev) { |
2003 | printk(KERN_INFO "cfg80211: Current regulatory " | 1974 | printk(KERN_INFO "cfg80211: Current regulatory " |
2004 | "domain updated by AP to: %c%c\n", | 1975 | "domain updated by AP to: %c%c\n", |
2005 | drv->country_ie_alpha2[0], | 1976 | rdev->country_ie_alpha2[0], |
2006 | drv->country_ie_alpha2[1]); | 1977 | rdev->country_ie_alpha2[1]); |
2007 | } else | 1978 | } else |
2008 | printk(KERN_INFO "cfg80211: Current regulatory " | 1979 | printk(KERN_INFO "cfg80211: Current regulatory " |
2009 | "domain intersected: \n"); | 1980 | "domain intersected: \n"); |
@@ -2064,7 +2035,7 @@ static inline void reg_country_ie_process_debug( | |||
2064 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 2035 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
2065 | { | 2036 | { |
2066 | const struct ieee80211_regdomain *intersected_rd = NULL; | 2037 | const struct ieee80211_regdomain *intersected_rd = NULL; |
2067 | struct cfg80211_registered_device *drv = NULL; | 2038 | struct cfg80211_registered_device *rdev = NULL; |
2068 | struct wiphy *request_wiphy; | 2039 | struct wiphy *request_wiphy; |
2069 | /* Some basic sanity checks first */ | 2040 | /* Some basic sanity checks first */ |
2070 | 2041 | ||
@@ -2203,11 +2174,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2203 | if (!intersected_rd) | 2174 | if (!intersected_rd) |
2204 | return -EINVAL; | 2175 | return -EINVAL; |
2205 | 2176 | ||
2206 | drv = wiphy_to_dev(request_wiphy); | 2177 | rdev = wiphy_to_dev(request_wiphy); |
2207 | 2178 | ||
2208 | drv->country_ie_alpha2[0] = rd->alpha2[0]; | 2179 | rdev->country_ie_alpha2[0] = rd->alpha2[0]; |
2209 | drv->country_ie_alpha2[1] = rd->alpha2[1]; | 2180 | rdev->country_ie_alpha2[1] = rd->alpha2[1]; |
2210 | drv->env = last_request->country_ie_env; | 2181 | rdev->env = last_request->country_ie_env; |
2211 | 2182 | ||
2212 | BUG_ON(intersected_rd == rd); | 2183 | BUG_ON(intersected_rd == rd); |
2213 | 2184 | ||
@@ -2232,10 +2203,13 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2232 | 2203 | ||
2233 | assert_cfg80211_lock(); | 2204 | assert_cfg80211_lock(); |
2234 | 2205 | ||
2206 | mutex_lock(®_mutex); | ||
2207 | |||
2235 | /* Note that this doesn't update the wiphys, this is done below */ | 2208 | /* Note that this doesn't update the wiphys, this is done below */ |
2236 | r = __set_regdom(rd); | 2209 | r = __set_regdom(rd); |
2237 | if (r) { | 2210 | if (r) { |
2238 | kfree(rd); | 2211 | kfree(rd); |
2212 | mutex_unlock(®_mutex); | ||
2239 | return r; | 2213 | return r; |
2240 | } | 2214 | } |
2241 | 2215 | ||
@@ -2250,6 +2224,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2250 | 2224 | ||
2251 | nl80211_send_reg_change_event(last_request); | 2225 | nl80211_send_reg_change_event(last_request); |
2252 | 2226 | ||
2227 | mutex_unlock(®_mutex); | ||
2228 | |||
2253 | return r; | 2229 | return r; |
2254 | } | 2230 | } |
2255 | 2231 | ||
@@ -2260,16 +2236,20 @@ void reg_device_remove(struct wiphy *wiphy) | |||
2260 | 2236 | ||
2261 | assert_cfg80211_lock(); | 2237 | assert_cfg80211_lock(); |
2262 | 2238 | ||
2239 | mutex_lock(®_mutex); | ||
2240 | |||
2263 | kfree(wiphy->regd); | 2241 | kfree(wiphy->regd); |
2264 | 2242 | ||
2265 | if (last_request) | 2243 | if (last_request) |
2266 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2244 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
2267 | 2245 | ||
2268 | if (!request_wiphy || request_wiphy != wiphy) | 2246 | if (!request_wiphy || request_wiphy != wiphy) |
2269 | return; | 2247 | goto out; |
2270 | 2248 | ||
2271 | last_request->wiphy_idx = WIPHY_IDX_STALE; | 2249 | last_request->wiphy_idx = WIPHY_IDX_STALE; |
2272 | last_request->country_ie_env = ENVIRON_ANY; | 2250 | last_request->country_ie_env = ENVIRON_ANY; |
2251 | out: | ||
2252 | mutex_unlock(®_mutex); | ||
2273 | } | 2253 | } |
2274 | 2254 | ||
2275 | int regulatory_init(void) | 2255 | int regulatory_init(void) |
@@ -2288,22 +2268,12 @@ int regulatory_init(void) | |||
2288 | 2268 | ||
2289 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); | 2269 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); |
2290 | print_regdomain_info(cfg80211_regdomain); | 2270 | print_regdomain_info(cfg80211_regdomain); |
2291 | /* | ||
2292 | * The old code still requests for a new regdomain and if | ||
2293 | * you have CRDA you get it updated, otherwise you get | ||
2294 | * stuck with the static values. Since "EU" is not a valid | ||
2295 | * ISO / IEC 3166 alpha2 code we can't expect userpace to | ||
2296 | * give us a regulatory domain for it. We need last_request | ||
2297 | * iniitalized though so lets just send a request which we | ||
2298 | * know will be ignored... this crap will be removed once | ||
2299 | * OLD_REG dies. | ||
2300 | */ | ||
2301 | err = regulatory_hint_core(ieee80211_regdom); | ||
2302 | #else | 2271 | #else |
2303 | cfg80211_regdomain = cfg80211_world_regdom; | 2272 | cfg80211_regdomain = cfg80211_world_regdom; |
2304 | 2273 | ||
2305 | err = regulatory_hint_core(ieee80211_regdom); | ||
2306 | #endif | 2274 | #endif |
2275 | /* We always try to get an update for the static regdomain */ | ||
2276 | err = regulatory_hint_core(cfg80211_regdomain->alpha2); | ||
2307 | if (err) { | 2277 | if (err) { |
2308 | if (err == -ENOMEM) | 2278 | if (err == -ENOMEM) |
2309 | return err; | 2279 | return err; |
@@ -2322,6 +2292,13 @@ int regulatory_init(void) | |||
2322 | #endif | 2292 | #endif |
2323 | } | 2293 | } |
2324 | 2294 | ||
2295 | /* | ||
2296 | * Finally, if the user set the module parameter treat it | ||
2297 | * as a user hint. | ||
2298 | */ | ||
2299 | if (!is_world_regdom(ieee80211_regdom)) | ||
2300 | regulatory_hint_user(ieee80211_regdom); | ||
2301 | |||
2325 | return 0; | 2302 | return 0; |
2326 | } | 2303 | } |
2327 | 2304 | ||
@@ -2333,6 +2310,7 @@ void regulatory_exit(void) | |||
2333 | cancel_work_sync(®_work); | 2310 | cancel_work_sync(®_work); |
2334 | 2311 | ||
2335 | mutex_lock(&cfg80211_mutex); | 2312 | mutex_lock(&cfg80211_mutex); |
2313 | mutex_lock(®_mutex); | ||
2336 | 2314 | ||
2337 | reset_regdomains(); | 2315 | reset_regdomains(); |
2338 | 2316 | ||
@@ -2371,5 +2349,6 @@ void regulatory_exit(void) | |||
2371 | } | 2349 | } |
2372 | spin_unlock(®_requests_lock); | 2350 | spin_unlock(®_requests_lock); |
2373 | 2351 | ||
2352 | mutex_unlock(®_mutex); | ||
2374 | mutex_unlock(&cfg80211_mutex); | 2353 | mutex_unlock(&cfg80211_mutex); |
2375 | } | 2354 | } |