aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/wireless.h5
-rw-r--r--net/wireless/core.c5
-rw-r--r--net/wireless/reg.c224
-rw-r--r--net/wireless/reg.h21
-rw-r--r--net/wireless/scan.c3
5 files changed, 254 insertions, 4 deletions
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 1f4707d18adb..64a76208580c 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -69,6 +69,9 @@ enum ieee80211_channel_flags {
69 * @band: band this channel belongs to. 69 * @band: band this channel belongs to.
70 * @max_antenna_gain: maximum antenna gain in dBi 70 * @max_antenna_gain: maximum antenna gain in dBi
71 * @max_power: maximum transmission power (in dBm) 71 * @max_power: maximum transmission power (in dBm)
72 * @beacon_found: helper to regulatory code to indicate when a beacon
73 * has been found on this channel. Use regulatory_hint_found_beacon()
74 * to enable this, this is is useful only on 5 GHz band.
72 * @orig_mag: internal use 75 * @orig_mag: internal use
73 * @orig_mpwr: internal use 76 * @orig_mpwr: internal use
74 */ 77 */
@@ -80,6 +83,7 @@ struct ieee80211_channel {
80 u32 flags; 83 u32 flags;
81 int max_antenna_gain; 84 int max_antenna_gain;
82 int max_power; 85 int max_power;
86 bool beacon_found;
83 u32 orig_flags; 87 u32 orig_flags;
84 int orig_mag, orig_mpwr; 88 int orig_mag, orig_mpwr;
85}; 89};
@@ -425,7 +429,6 @@ extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
425extern void regulatory_hint_11d(struct wiphy *wiphy, 429extern void regulatory_hint_11d(struct wiphy *wiphy,
426 u8 *country_ie, 430 u8 *country_ie,
427 u8 country_ie_len); 431 u8 country_ie_len);
428
429/** 432/**
430 * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain 433 * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
431 * @wiphy: the wireless device we want to process the regulatory domain on 434 * @wiphy: the wireless device we want to process the regulatory domain on
diff --git a/net/wireless/core.c b/net/wireless/core.c
index b1a354b7fc06..dd7f222919fe 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -32,8 +32,9 @@ MODULE_DESCRIPTION("wireless configuration support");
32LIST_HEAD(cfg80211_drv_list); 32LIST_HEAD(cfg80211_drv_list);
33 33
34/* 34/*
35 * This is used to protect the cfg80211_drv_list, cfg80211_regdomain, and 35 * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
36 * the last reguluatory request receipt in regd.c 36 * country_ie_regdomain, the reg_beacon_list and the the last regulatory
37 * request receipt (last_request).
37 */ 38 */
38DEFINE_MUTEX(cfg80211_mutex); 39DEFINE_MUTEX(cfg80211_mutex);
39 40
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index da2a8aca4280..e5e432d6af34 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -68,9 +68,22 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
68 */ 68 */
69static const struct ieee80211_regdomain *country_ie_regdomain; 69static const struct ieee80211_regdomain *country_ie_regdomain;
70 70
71/* Used to queue up regulatory hints */
71static LIST_HEAD(reg_requests_list); 72static LIST_HEAD(reg_requests_list);
72static spinlock_t reg_requests_lock; 73static spinlock_t reg_requests_lock;
73 74
75/* Used to queue up beacon hints for review */
76static LIST_HEAD(reg_pending_beacons);
77static spinlock_t reg_pending_beacons_lock;
78
79/* Used to keep track of processed beacon hints */
80static LIST_HEAD(reg_beacon_list);
81
82struct reg_beacon {
83 struct list_head list;
84 struct ieee80211_channel chan;
85};
86
74/* We keep a static world regulatory domain in case of the absence of CRDA */ 87/* We keep a static world regulatory domain in case of the absence of CRDA */
75static const struct ieee80211_regdomain world_regdom = { 88static const struct ieee80211_regdomain world_regdom = {
76 .n_reg_rules = 3, 89 .n_reg_rules = 3,
@@ -1011,16 +1024,120 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby)
1011 wiphy_update_regulatory(&drv->wiphy, setby); 1024 wiphy_update_regulatory(&drv->wiphy, setby);
1012} 1025}
1013 1026
1027static void handle_reg_beacon(struct wiphy *wiphy,
1028 unsigned int chan_idx,
1029 struct reg_beacon *reg_beacon)
1030{
1031#ifdef CONFIG_CFG80211_REG_DEBUG
1032#define REG_DEBUG_BEACON_FLAG(desc) \
1033 printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \
1034 "frequency: %d MHz (Ch %d) on %s\n", \
1035 reg_beacon->chan.center_freq, \
1036 ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \
1037 wiphy_name(wiphy));
1038#else
1039#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0)
1040#endif
1041 struct ieee80211_supported_band *sband;
1042 struct ieee80211_channel *chan;
1043
1044 assert_cfg80211_lock();
1045
1046 sband = wiphy->bands[reg_beacon->chan.band];
1047 chan = &sband->channels[chan_idx];
1048
1049 if (likely(chan->center_freq != reg_beacon->chan.center_freq))
1050 return;
1051
1052 if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
1053 chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
1054 REG_DEBUG_BEACON_FLAG("active scanning");
1055 }
1056
1057 if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
1058 chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
1059 REG_DEBUG_BEACON_FLAG("beaconing");
1060 }
1061
1062 chan->beacon_found = true;
1063#undef REG_DEBUG_BEACON_FLAG
1064}
1065
1066/*
1067 * Called when a scan on a wiphy finds a beacon on
1068 * new channel
1069 */
1070static void wiphy_update_new_beacon(struct wiphy *wiphy,
1071 struct reg_beacon *reg_beacon)
1072{
1073 unsigned int i;
1074 struct ieee80211_supported_band *sband;
1075
1076 assert_cfg80211_lock();
1077
1078 if (!wiphy->bands[reg_beacon->chan.band])
1079 return;
1080
1081 sband = wiphy->bands[reg_beacon->chan.band];
1082
1083 for (i = 0; i < sband->n_channels; i++)
1084 handle_reg_beacon(wiphy, i, reg_beacon);
1085}
1086
1087/*
1088 * Called upon reg changes or a new wiphy is added
1089 */
1090static void wiphy_update_beacon_reg(struct wiphy *wiphy)
1091{
1092 unsigned int i;
1093 struct ieee80211_supported_band *sband;
1094 struct reg_beacon *reg_beacon;
1095
1096 assert_cfg80211_lock();
1097
1098 if (list_empty(&reg_beacon_list))
1099 return;
1100
1101 list_for_each_entry(reg_beacon, &reg_beacon_list, list) {
1102 if (!wiphy->bands[reg_beacon->chan.band])
1103 continue;
1104 sband = wiphy->bands[reg_beacon->chan.band];
1105 for (i = 0; i < sband->n_channels; i++)
1106 handle_reg_beacon(wiphy, i, reg_beacon);
1107 }
1108}
1109
1110static bool reg_is_world_roaming(struct wiphy *wiphy)
1111{
1112 if (is_world_regdom(cfg80211_regdomain->alpha2) ||
1113 (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
1114 return true;
1115 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
1116 wiphy->custom_regulatory)
1117 return true;
1118 return false;
1119}
1120
1121/* Reap the advantages of previously found beacons */
1122static void reg_process_beacons(struct wiphy *wiphy)
1123{
1124 if (!reg_is_world_roaming(wiphy))
1125 return;
1126 wiphy_update_beacon_reg(wiphy);
1127}
1128
1014void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) 1129void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
1015{ 1130{
1016 enum ieee80211_band band; 1131 enum ieee80211_band band;
1017 1132
1018 if (ignore_reg_update(wiphy, setby)) 1133 if (ignore_reg_update(wiphy, setby))
1019 return; 1134 goto out;
1020 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 1135 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1021 if (wiphy->bands[band]) 1136 if (wiphy->bands[band])
1022 handle_band(wiphy, band); 1137 handle_band(wiphy, band);
1023 } 1138 }
1139out:
1140 reg_process_beacons(wiphy);
1024 if (wiphy->reg_notifier) 1141 if (wiphy->reg_notifier)
1025 wiphy->reg_notifier(wiphy, last_request); 1142 wiphy->reg_notifier(wiphy, last_request);
1026} 1143}
@@ -1314,6 +1431,7 @@ out:
1314 return r; 1431 return r;
1315} 1432}
1316 1433
1434/* Processes regulatory hints, this is all the REGDOM_SET_BY_* */
1317static void reg_process_pending_hints(void) 1435static void reg_process_pending_hints(void)
1318 { 1436 {
1319 struct regulatory_request *reg_request; 1437 struct regulatory_request *reg_request;
@@ -1344,9 +1462,44 @@ static void reg_process_pending_hints(void)
1344 spin_unlock(&reg_requests_lock); 1462 spin_unlock(&reg_requests_lock);
1345} 1463}
1346 1464
1465/* Processes beacon hints -- this has nothing to do with country IEs */
1466static void reg_process_pending_beacon_hints(void)
1467{
1468 struct cfg80211_registered_device *drv;
1469 struct reg_beacon *pending_beacon, *tmp;
1470
1471 mutex_lock(&cfg80211_mutex);
1472
1473 /* This goes through the _pending_ beacon list */
1474 spin_lock_bh(&reg_pending_beacons_lock);
1475
1476 if (list_empty(&reg_pending_beacons)) {
1477 spin_unlock_bh(&reg_pending_beacons_lock);
1478 goto out;
1479 }
1480
1481 list_for_each_entry_safe(pending_beacon, tmp,
1482 &reg_pending_beacons, list) {
1483
1484 list_del_init(&pending_beacon->list);
1485
1486 /* Applies the beacon hint to current wiphys */
1487 list_for_each_entry(drv, &cfg80211_drv_list, list)
1488 wiphy_update_new_beacon(&drv->wiphy, pending_beacon);
1489
1490 /* Remembers the beacon hint for new wiphys or reg changes */
1491 list_add_tail(&pending_beacon->list, &reg_beacon_list);
1492 }
1493
1494 spin_unlock_bh(&reg_pending_beacons_lock);
1495out:
1496 mutex_unlock(&cfg80211_mutex);
1497}
1498
1347static void reg_todo(struct work_struct *work) 1499static void reg_todo(struct work_struct *work)
1348{ 1500{
1349 reg_process_pending_hints(); 1501 reg_process_pending_hints();
1502 reg_process_pending_beacon_hints();
1350} 1503}
1351 1504
1352static DECLARE_WORK(reg_work, reg_todo); 1505static DECLARE_WORK(reg_work, reg_todo);
@@ -1587,6 +1740,55 @@ out:
1587} 1740}
1588EXPORT_SYMBOL(regulatory_hint_11d); 1741EXPORT_SYMBOL(regulatory_hint_11d);
1589 1742
1743static bool freq_is_chan_12_13_14(u16 freq)
1744{
1745 if (freq == ieee80211_channel_to_frequency(12) ||
1746 freq == ieee80211_channel_to_frequency(13) ||
1747 freq == ieee80211_channel_to_frequency(14))
1748 return true;
1749 return false;
1750}
1751
1752int regulatory_hint_found_beacon(struct wiphy *wiphy,
1753 struct ieee80211_channel *beacon_chan,
1754 gfp_t gfp)
1755{
1756 struct reg_beacon *reg_beacon;
1757
1758 if (likely((beacon_chan->beacon_found ||
1759 (beacon_chan->flags & IEEE80211_CHAN_RADAR) ||
1760 (beacon_chan->band == IEEE80211_BAND_2GHZ &&
1761 !freq_is_chan_12_13_14(beacon_chan->center_freq)))))
1762 return 0;
1763
1764 reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp);
1765 if (!reg_beacon)
1766 return -ENOMEM;
1767
1768#ifdef CONFIG_CFG80211_REG_DEBUG
1769 printk(KERN_DEBUG "cfg80211: Found new beacon on "
1770 "frequency: %d MHz (Ch %d) on %s\n",
1771 beacon_chan->center_freq,
1772 ieee80211_frequency_to_channel(beacon_chan->center_freq),
1773 wiphy_name(wiphy));
1774#endif
1775 memcpy(&reg_beacon->chan, beacon_chan,
1776 sizeof(struct ieee80211_channel));
1777
1778
1779 /*
1780 * Since we can be called from BH or and non-BH context
1781 * we must use spin_lock_bh()
1782 */
1783 spin_lock_bh(&reg_pending_beacons_lock);
1784 list_add_tail(&reg_beacon->list, &reg_pending_beacons);
1785 spin_unlock_bh(&reg_pending_beacons_lock);
1786
1787 schedule_work(&reg_work);
1788
1789 return 0;
1790}
1791
1590static void print_rd_rules(const struct ieee80211_regdomain *rd) 1792static void print_rd_rules(const struct ieee80211_regdomain *rd)
1591{ 1793{
1592 unsigned int i; 1794 unsigned int i;
@@ -1908,6 +2110,7 @@ int regulatory_init(void)
1908 return PTR_ERR(reg_pdev); 2110 return PTR_ERR(reg_pdev);
1909 2111
1910 spin_lock_init(&reg_requests_lock); 2112 spin_lock_init(&reg_requests_lock);
2113 spin_lock_init(&reg_pending_beacons_lock);
1911 2114
1912#ifdef CONFIG_WIRELESS_OLD_REGULATORY 2115#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1913 cfg80211_regdomain = static_regdom(ieee80211_regdom); 2116 cfg80211_regdomain = static_regdom(ieee80211_regdom);
@@ -1951,6 +2154,7 @@ int regulatory_init(void)
1951void regulatory_exit(void) 2154void regulatory_exit(void)
1952{ 2155{
1953 struct regulatory_request *reg_request, *tmp; 2156 struct regulatory_request *reg_request, *tmp;
2157 struct reg_beacon *reg_beacon, *btmp;
1954 2158
1955 cancel_work_sync(&reg_work); 2159 cancel_work_sync(&reg_work);
1956 2160
@@ -1965,6 +2169,24 @@ void regulatory_exit(void)
1965 2169
1966 platform_device_unregister(reg_pdev); 2170 platform_device_unregister(reg_pdev);
1967 2171
2172 spin_lock_bh(&reg_pending_beacons_lock);
2173 if (!list_empty(&reg_pending_beacons)) {
2174 list_for_each_entry_safe(reg_beacon, btmp,
2175 &reg_pending_beacons, list) {
2176 list_del(&reg_beacon->list);
2177 kfree(reg_beacon);
2178 }
2179 }
2180 spin_unlock_bh(&reg_pending_beacons_lock);
2181
2182 if (!list_empty(&reg_beacon_list)) {
2183 list_for_each_entry_safe(reg_beacon, btmp,
2184 &reg_beacon_list, list) {
2185 list_del(&reg_beacon->list);
2186 kfree(reg_beacon);
2187 }
2188 }
2189
1968 spin_lock(&reg_requests_lock); 2190 spin_lock(&reg_requests_lock);
1969 if (!list_empty(&reg_requests_list)) { 2191 if (!list_empty(&reg_requests_list)) {
1970 list_for_each_entry_safe(reg_request, tmp, 2192 list_for_each_entry_safe(reg_request, tmp,
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 4730def5a69d..65bfd0558ce1 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -38,4 +38,25 @@ extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
38 const char *alpha2, u32 country_ie_checksum, 38 const char *alpha2, u32 country_ie_checksum,
39 enum environment_cap country_ie_env); 39 enum environment_cap country_ie_env);
40 40
41/**
42 * regulatory_hint_found_beacon - hints a beacon was found on a channel
43 * @wiphy: the wireless device where the beacon was found on
44 * @beacon_chan: the channel on which the beacon was found on
45 * @gfp: context flags
46 *
47 * This informs the wireless core that a beacon from an AP was found on
48 * the channel provided. This allows the wireless core to make educated
49 * guesses on regulatory to help with world roaming. This is only used for
50 * world roaming -- when we do not know our current location. This is
51 * only useful on channels 12, 13 and 14 on the 2 GHz band as channels
52 * 1-11 are already enabled by the world regulatory domain; and on
53 * non-radar 5 GHz channels.
54 *
55 * Drivers do not need to call this, cfg80211 will do it for after a scan
56 * on a newly found BSS.
57 */
58int regulatory_hint_found_beacon(struct wiphy *wiphy,
59 struct ieee80211_channel *beacon_chan,
60 gfp_t gfp);
61
41#endif /* __NET_WIRELESS_REG_H */ 62#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 60600657b657..280dbcd02c15 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -430,6 +430,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
430 if (!res) 430 if (!res)
431 return NULL; 431 return NULL;
432 432
433 if (res->pub.capability & WLAN_CAPABILITY_ESS)
434 regulatory_hint_found_beacon(wiphy, channel, gfp);
435
433 /* cfg80211_bss_update gives us a referenced result */ 436 /* cfg80211_bss_update gives us a referenced result */
434 return &res->pub; 437 return &res->pub;
435} 438}