aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-05-02 00:37:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-20 14:46:22 -0400
commit038659e7c6b385065cb223872771ac437ef70b62 (patch)
treedf9e86adcc611d10ed5f98672421bffe1f43989f /net/wireless/reg.c
parent97bc54152e3a91dd2dc297e8a084c05e93527e60 (diff)
cfg80211: Process regulatory max bandwidth checks for HT40
We are not correctly listening to the regulatory max bandwidth settings. To actually make use of it we need to redesign things a bit. This patch does the work for that. We do this to so we can obey to regulatory rules accordingly for use of HT40. We end up dealing with HT40 by having two passes for each channel. The first check will see if a 20 MHz channel fits into the channel's center freq on a given frequency range. We check for a 20 MHz banwidth channel as that is the maximum an individual channel will use, at least for now. The first pass will go ahead and check if the regulatory rule for that given center of frequency allows 40 MHz bandwidths and we use this to determine whether or not the channel supports HT40 or not. So to support HT40 you'll need at a regulatory rule that allows you to use 40 MHz channels but you're channel must also be enabled and support 20 MHz by itself. The second pass is done after we do the regulatory checks over an device's supported channel list. On each channel we'll check if the control channel and the extension both: o exist o are enabled o regulatory allows 40 MHz bandwidth on its frequency range This work allows allows us to idependently check for HT40- and HT40+. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c201
1 files changed, 159 insertions, 42 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 537af62ec42b..d897528ee7fc 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -48,12 +48,6 @@ static struct regulatory_request *last_request;
48/* To trigger userspace events */ 48/* To trigger userspace events */
49static struct platform_device *reg_pdev; 49static struct platform_device *reg_pdev;
50 50
51/* Keep the ordering from large to small */
52static u32 supported_bandwidths[] = {
53 MHZ_TO_KHZ(40),
54 MHZ_TO_KHZ(20),
55};
56
57/* 51/*
58 * Central wireless core regulatory domains, we only need two, 52 * Central wireless core regulatory domains, we only need two,
59 * the current one and a world regulatory domain in case we have no 53 * the current one and a world regulatory domain in case we have no
@@ -435,19 +429,20 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
435 return true; 429 return true;
436} 430}
437 431
438/* Returns value in KHz */ 432static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
439static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, 433 u32 center_freq_khz,
440 u32 freq) 434 u32 bw_khz)
441{ 435{
442 unsigned int i; 436 u32 start_freq_khz, end_freq_khz;
443 for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) { 437
444 u32 start_freq_khz = freq - supported_bandwidths[i]/2; 438 start_freq_khz = center_freq_khz - (bw_khz/2);
445 u32 end_freq_khz = freq + supported_bandwidths[i]/2; 439 end_freq_khz = center_freq_khz + (bw_khz/2);
446 if (start_freq_khz >= freq_range->start_freq_khz && 440
447 end_freq_khz <= freq_range->end_freq_khz) 441 if (start_freq_khz >= freq_range->start_freq_khz &&
448 return supported_bandwidths[i]; 442 end_freq_khz <= freq_range->end_freq_khz)
449 } 443 return true;
450 return 0; 444
445 return false;
451} 446}
452 447
453/** 448/**
@@ -847,14 +842,17 @@ static u32 map_regdom_flags(u32 rd_flags)
847 842
848static int freq_reg_info_regd(struct wiphy *wiphy, 843static int freq_reg_info_regd(struct wiphy *wiphy,
849 u32 center_freq, 844 u32 center_freq,
850 u32 *bandwidth, 845 u32 desired_bw_khz,
851 const struct ieee80211_reg_rule **reg_rule, 846 const struct ieee80211_reg_rule **reg_rule,
852 const struct ieee80211_regdomain *custom_regd) 847 const struct ieee80211_regdomain *custom_regd)
853{ 848{
854 int i; 849 int i;
855 bool band_rule_found = false; 850 bool band_rule_found = false;
856 const struct ieee80211_regdomain *regd; 851 const struct ieee80211_regdomain *regd;
857 u32 max_bandwidth = 0; 852 bool bw_fits = false;
853
854 if (!desired_bw_khz)
855 desired_bw_khz = MHZ_TO_KHZ(20);
858 856
859 regd = custom_regd ? custom_regd : cfg80211_regdomain; 857 regd = custom_regd ? custom_regd : cfg80211_regdomain;
860 858
@@ -887,38 +885,54 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
887 if (!band_rule_found) 885 if (!band_rule_found)
888 band_rule_found = freq_in_rule_band(fr, center_freq); 886 band_rule_found = freq_in_rule_band(fr, center_freq);
889 887
890 max_bandwidth = freq_max_bandwidth(fr, center_freq); 888 bw_fits = reg_does_bw_fit(fr,
889 center_freq,
890 desired_bw_khz);
891 891
892 if (max_bandwidth && *bandwidth <= max_bandwidth) { 892 if (band_rule_found && bw_fits) {
893 *reg_rule = rr; 893 *reg_rule = rr;
894 *bandwidth = max_bandwidth; 894 return 0;
895 break;
896 } 895 }
897 } 896 }
898 897
899 if (!band_rule_found) 898 if (!band_rule_found)
900 return -ERANGE; 899 return -ERANGE;
901 900
902 return !max_bandwidth; 901 return -EINVAL;
903} 902}
904EXPORT_SYMBOL(freq_reg_info); 903EXPORT_SYMBOL(freq_reg_info);
905 904
906int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, 905int freq_reg_info(struct wiphy *wiphy,
907 const struct ieee80211_reg_rule **reg_rule) 906 u32 center_freq,
907 u32 desired_bw_khz,
908 const struct ieee80211_reg_rule **reg_rule)
908{ 909{
909 assert_cfg80211_lock(); 910 assert_cfg80211_lock();
910 return freq_reg_info_regd(wiphy, center_freq, 911 return freq_reg_info_regd(wiphy,
911 bandwidth, reg_rule, NULL); 912 center_freq,
913 desired_bw_khz,
914 reg_rule,
915 NULL);
912} 916}
913 917
918/*
919 * Note that right now we assume the desired channel bandwidth
920 * is always 20 MHz for each individual channel (HT40 uses 20 MHz
921 * per channel, the primary and the extension channel). To support
922 * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a
923 * new ieee80211_channel.target_bw and re run the regulatory check
924 * on the wiphy with the target_bw specified. Then we can simply use
925 * that below for the desired_bw_khz below.
926 */
914static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, 927static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
915 unsigned int chan_idx) 928 unsigned int chan_idx)
916{ 929{
917 int r; 930 int r;
918 u32 flags; 931 u32 flags, bw_flags = 0;
919 u32 max_bandwidth = 0; 932 u32 desired_bw_khz = MHZ_TO_KHZ(20);
920 const struct ieee80211_reg_rule *reg_rule = NULL; 933 const struct ieee80211_reg_rule *reg_rule = NULL;
921 const struct ieee80211_power_rule *power_rule = NULL; 934 const struct ieee80211_power_rule *power_rule = NULL;
935 const struct ieee80211_freq_range *freq_range = NULL;
922 struct ieee80211_supported_band *sband; 936 struct ieee80211_supported_band *sband;
923 struct ieee80211_channel *chan; 937 struct ieee80211_channel *chan;
924 struct wiphy *request_wiphy = NULL; 938 struct wiphy *request_wiphy = NULL;
@@ -933,8 +947,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
933 947
934 flags = chan->orig_flags; 948 flags = chan->orig_flags;
935 949
936 r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), 950 r = freq_reg_info(wiphy,
937 &max_bandwidth, &reg_rule); 951 MHZ_TO_KHZ(chan->center_freq),
952 desired_bw_khz,
953 &reg_rule);
938 954
939 if (r) { 955 if (r) {
940 /* 956 /*
@@ -977,6 +993,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
977 } 993 }
978 994
979 power_rule = &reg_rule->power_rule; 995 power_rule = &reg_rule->power_rule;
996 freq_range = &reg_rule->freq_range;
997
998 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
999 bw_flags = IEEE80211_CHAN_NO_HT40;
980 1000
981 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && 1001 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
982 request_wiphy && request_wiphy == wiphy && 1002 request_wiphy && request_wiphy == wiphy &&
@@ -987,19 +1007,19 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
987 * settings 1007 * settings
988 */ 1008 */
989 chan->flags = chan->orig_flags = 1009 chan->flags = chan->orig_flags =
990 map_regdom_flags(reg_rule->flags); 1010 map_regdom_flags(reg_rule->flags) | bw_flags;
991 chan->max_antenna_gain = chan->orig_mag = 1011 chan->max_antenna_gain = chan->orig_mag =
992 (int) MBI_TO_DBI(power_rule->max_antenna_gain); 1012 (int) MBI_TO_DBI(power_rule->max_antenna_gain);
993 chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); 1013 chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
994 chan->max_power = chan->orig_mpwr = 1014 chan->max_power = chan->orig_mpwr =
995 (int) MBM_TO_DBM(power_rule->max_eirp); 1015 (int) MBM_TO_DBM(power_rule->max_eirp);
996 return; 1016 return;
997 } 1017 }
998 1018
999 chan->flags = flags | map_regdom_flags(reg_rule->flags); 1019 chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
1000 chan->max_antenna_gain = min(chan->orig_mag, 1020 chan->max_antenna_gain = min(chan->orig_mag,
1001 (int) MBI_TO_DBI(power_rule->max_antenna_gain)); 1021 (int) MBI_TO_DBI(power_rule->max_antenna_gain));
1002 chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); 1022 chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
1003 if (chan->orig_mpwr) 1023 if (chan->orig_mpwr)
1004 chan->max_power = min(chan->orig_mpwr, 1024 chan->max_power = min(chan->orig_mpwr,
1005 (int) MBM_TO_DBM(power_rule->max_eirp)); 1025 (int) MBM_TO_DBM(power_rule->max_eirp));
@@ -1156,6 +1176,93 @@ static void reg_process_beacons(struct wiphy *wiphy)
1156 wiphy_update_beacon_reg(wiphy); 1176 wiphy_update_beacon_reg(wiphy);
1157} 1177}
1158 1178
1179static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
1180{
1181 if (!chan)
1182 return true;
1183 if (chan->flags & IEEE80211_CHAN_DISABLED)
1184 return true;
1185 /* This would happen when regulatory rules disallow HT40 completely */
1186 if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40)))
1187 return true;
1188 return false;
1189}
1190
1191static void reg_process_ht_flags_channel(struct wiphy *wiphy,
1192 enum ieee80211_band band,
1193 unsigned int chan_idx)
1194{
1195 struct ieee80211_supported_band *sband;
1196 struct ieee80211_channel *channel;
1197 struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
1198 unsigned int i;
1199
1200 assert_cfg80211_lock();
1201
1202 sband = wiphy->bands[band];
1203 BUG_ON(chan_idx >= sband->n_channels);
1204 channel = &sband->channels[chan_idx];
1205
1206 if (is_ht40_not_allowed(channel)) {
1207 channel->flags |= IEEE80211_CHAN_NO_HT40;
1208 return;
1209 }
1210
1211 /*
1212 * We need to ensure the extension channels exist to
1213 * be able to use HT40- or HT40+, this finds them (or not)
1214 */
1215 for (i = 0; i < sband->n_channels; i++) {
1216 struct ieee80211_channel *c = &sband->channels[i];
1217 if (c->center_freq == (channel->center_freq - 20))
1218 channel_before = c;
1219 if (c->center_freq == (channel->center_freq + 20))
1220 channel_after = c;
1221 }
1222
1223 /*
1224 * Please note that this assumes target bandwidth is 20 MHz,
1225 * if that ever changes we also need to change the below logic
1226 * to include that as well.
1227 */
1228 if (is_ht40_not_allowed(channel_before))
1229 channel->flags |= IEEE80211_CHAN_NO_FAT_BELOW;
1230 else
1231 channel->flags &= ~IEEE80211_CHAN_NO_FAT_BELOW;
1232
1233 if (is_ht40_not_allowed(channel_after))
1234 channel->flags |= IEEE80211_CHAN_NO_FAT_ABOVE;
1235 else
1236 channel->flags &= ~IEEE80211_CHAN_NO_FAT_ABOVE;
1237}
1238
1239static void reg_process_ht_flags_band(struct wiphy *wiphy,
1240 enum ieee80211_band band)
1241{
1242 unsigned int i;
1243 struct ieee80211_supported_band *sband;
1244
1245 BUG_ON(!wiphy->bands[band]);
1246 sband = wiphy->bands[band];
1247
1248 for (i = 0; i < sband->n_channels; i++)
1249 reg_process_ht_flags_channel(wiphy, band, i);
1250}
1251
1252static void reg_process_ht_flags(struct wiphy *wiphy)
1253{
1254 enum ieee80211_band band;
1255
1256 if (!wiphy)
1257 return;
1258
1259 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1260 if (wiphy->bands[band])
1261 reg_process_ht_flags_band(wiphy, band);
1262 }
1263
1264}
1265
1159void wiphy_update_regulatory(struct wiphy *wiphy, 1266void wiphy_update_regulatory(struct wiphy *wiphy,
1160 enum nl80211_reg_initiator initiator) 1267 enum nl80211_reg_initiator initiator)
1161{ 1268{
@@ -1169,6 +1276,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
1169 } 1276 }
1170out: 1277out:
1171 reg_process_beacons(wiphy); 1278 reg_process_beacons(wiphy);
1279 reg_process_ht_flags(wiphy);
1172 if (wiphy->reg_notifier) 1280 if (wiphy->reg_notifier)
1173 wiphy->reg_notifier(wiphy, last_request); 1281 wiphy->reg_notifier(wiphy, last_request);
1174} 1282}
@@ -1179,9 +1287,11 @@ static void handle_channel_custom(struct wiphy *wiphy,
1179 const struct ieee80211_regdomain *regd) 1287 const struct ieee80211_regdomain *regd)
1180{ 1288{
1181 int r; 1289 int r;
1182 u32 max_bandwidth = 0; 1290 u32 desired_bw_khz = MHZ_TO_KHZ(20);
1291 u32 bw_flags = 0;
1183 const struct ieee80211_reg_rule *reg_rule = NULL; 1292 const struct ieee80211_reg_rule *reg_rule = NULL;
1184 const struct ieee80211_power_rule *power_rule = NULL; 1293 const struct ieee80211_power_rule *power_rule = NULL;
1294 const struct ieee80211_freq_range *freq_range = NULL;
1185 struct ieee80211_supported_band *sband; 1295 struct ieee80211_supported_band *sband;
1186 struct ieee80211_channel *chan; 1296 struct ieee80211_channel *chan;
1187 1297
@@ -1191,8 +1301,11 @@ static void handle_channel_custom(struct wiphy *wiphy,
1191 BUG_ON(chan_idx >= sband->n_channels); 1301 BUG_ON(chan_idx >= sband->n_channels);
1192 chan = &sband->channels[chan_idx]; 1302 chan = &sband->channels[chan_idx];
1193 1303
1194 r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), 1304 r = freq_reg_info_regd(wiphy,
1195 &max_bandwidth, &reg_rule, regd); 1305 MHZ_TO_KHZ(chan->center_freq),
1306 desired_bw_khz,
1307 &reg_rule,
1308 regd);
1196 1309
1197 if (r) { 1310 if (r) {
1198 chan->flags = IEEE80211_CHAN_DISABLED; 1311 chan->flags = IEEE80211_CHAN_DISABLED;
@@ -1200,10 +1313,14 @@ static void handle_channel_custom(struct wiphy *wiphy,
1200 } 1313 }
1201 1314
1202 power_rule = &reg_rule->power_rule; 1315 power_rule = &reg_rule->power_rule;
1316 freq_range = &reg_rule->freq_range;
1317
1318 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
1319 bw_flags = IEEE80211_CHAN_NO_HT40;
1203 1320
1204 chan->flags |= map_regdom_flags(reg_rule->flags); 1321 chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
1205 chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); 1322 chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
1206 chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); 1323 chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
1207 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); 1324 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
1208} 1325}
1209 1326