aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-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