aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/reg.c104
1 files changed, 92 insertions, 12 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 0f93d4526f37..5a746cd114a6 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -784,6 +784,7 @@ static u32 map_regdom_flags(u32 rd_flags)
784 784
785/** 785/**
786 * freq_reg_info - get regulatory information for the given frequency 786 * freq_reg_info - get regulatory information for the given frequency
787 * @wiphy: the wiphy for which we want to process this rule for
787 * @center_freq: Frequency in KHz for which we want regulatory information for 788 * @center_freq: Frequency in KHz for which we want regulatory information for
788 * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one 789 * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one
789 * you can set this to 0. If this frequency is allowed we then set 790 * you can set this to 0. If this frequency is allowed we then set
@@ -802,22 +803,31 @@ static u32 map_regdom_flags(u32 rd_flags)
802 * freq_in_rule_band() for our current definition of a band -- this is purely 803 * freq_in_rule_band() for our current definition of a band -- this is purely
803 * subjective and right now its 802.11 specific. 804 * subjective and right now its 802.11 specific.
804 */ 805 */
805static int freq_reg_info(u32 center_freq, u32 *bandwidth, 806static int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
806 const struct ieee80211_reg_rule **reg_rule) 807 const struct ieee80211_reg_rule **reg_rule)
807{ 808{
808 int i; 809 int i;
809 bool band_rule_found = false; 810 bool band_rule_found = false;
811 const struct ieee80211_regdomain *regd;
810 u32 max_bandwidth = 0; 812 u32 max_bandwidth = 0;
811 813
812 if (!cfg80211_regdomain) 814 regd = cfg80211_regdomain;
815
816 /* Follow the driver's regulatory domain, if present, unless a country
817 * IE has been processed */
818 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
819 wiphy->regd)
820 regd = wiphy->regd;
821
822 if (!regd)
813 return -EINVAL; 823 return -EINVAL;
814 824
815 for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { 825 for (i = 0; i < regd->n_reg_rules; i++) {
816 const struct ieee80211_reg_rule *rr; 826 const struct ieee80211_reg_rule *rr;
817 const struct ieee80211_freq_range *fr = NULL; 827 const struct ieee80211_freq_range *fr = NULL;
818 const struct ieee80211_power_rule *pr = NULL; 828 const struct ieee80211_power_rule *pr = NULL;
819 829
820 rr = &cfg80211_regdomain->reg_rules[i]; 830 rr = &regd->reg_rules[i];
821 fr = &rr->freq_range; 831 fr = &rr->freq_range;
822 pr = &rr->power_rule; 832 pr = &rr->power_rule;
823 833
@@ -859,7 +869,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
859 869
860 flags = chan->orig_flags; 870 flags = chan->orig_flags;
861 871
862 r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq), 872 r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
863 &max_bandwidth, &reg_rule); 873 &max_bandwidth, &reg_rule);
864 874
865 if (r) { 875 if (r) {
@@ -952,6 +962,30 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
952 wiphy->reg_notifier(wiphy, setby); 962 wiphy->reg_notifier(wiphy, setby);
953} 963}
954 964
965static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
966 const struct ieee80211_regdomain *src_regd)
967{
968 struct ieee80211_regdomain *regd;
969 int size_of_regd = 0;
970 unsigned int i;
971
972 size_of_regd = sizeof(struct ieee80211_regdomain) +
973 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
974
975 regd = kzalloc(size_of_regd, GFP_KERNEL);
976 if (!regd)
977 return -ENOMEM;
978
979 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
980
981 for (i = 0; i < src_regd->n_reg_rules; i++)
982 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
983 sizeof(struct ieee80211_reg_rule));
984
985 *dst_regd = regd;
986 return 0;
987}
988
955/* Return value which can be used by ignore_request() to indicate 989/* Return value which can be used by ignore_request() to indicate
956 * it has been determined we should intersect two regulatory domains */ 990 * it has been determined we should intersect two regulatory domains */
957#define REG_INTERSECT 1 991#define REG_INTERSECT 1
@@ -999,9 +1033,9 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
999 } 1033 }
1000 return REG_INTERSECT; 1034 return REG_INTERSECT;
1001 case REGDOM_SET_BY_DRIVER: 1035 case REGDOM_SET_BY_DRIVER:
1002 if (last_request->initiator == REGDOM_SET_BY_DRIVER) 1036 if (last_request->initiator == REGDOM_SET_BY_CORE)
1003 return -EALREADY; 1037 return 0;
1004 return 0; 1038 return REG_INTERSECT;
1005 case REGDOM_SET_BY_USER: 1039 case REGDOM_SET_BY_USER:
1006 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) 1040 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
1007 return REG_INTERSECT; 1041 return REG_INTERSECT;
@@ -1028,11 +1062,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1028 1062
1029 r = ignore_request(wiphy, set_by, alpha2); 1063 r = ignore_request(wiphy, set_by, alpha2);
1030 1064
1031 if (r == REG_INTERSECT) 1065 if (r == REG_INTERSECT) {
1066 if (set_by == REGDOM_SET_BY_DRIVER) {
1067 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
1068 if (r)
1069 return r;
1070 }
1032 intersect = true; 1071 intersect = true;
1033 else if (r) 1072 } else if (r) {
1073 /* If the regulatory domain being requested by the
1074 * driver has already been set just copy it to the
1075 * wiphy */
1076 if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
1077 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
1078 if (r)
1079 return r;
1080 r = -EALREADY;
1081 goto new_request;
1082 }
1034 return r; 1083 return r;
1084 }
1035 1085
1086new_request:
1036 request = kzalloc(sizeof(struct regulatory_request), 1087 request = kzalloc(sizeof(struct regulatory_request),
1037 GFP_KERNEL); 1088 GFP_KERNEL);
1038 if (!request) 1089 if (!request)
@@ -1048,6 +1099,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1048 1099
1049 kfree(last_request); 1100 kfree(last_request);
1050 last_request = request; 1101 last_request = request;
1102
1103 /* When r == REG_INTERSECT we do need to call CRDA */
1104 if (r < 0)
1105 return r;
1106
1051 /* 1107 /*
1052 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled 1108 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
1053 * AND if CRDA is NOT present nothing will happen, if someone 1109 * AND if CRDA is NOT present nothing will happen, if someone
@@ -1341,6 +1397,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
1341 } 1397 }
1342 1398
1343 if (!last_request->intersect) { 1399 if (!last_request->intersect) {
1400 int r;
1401
1402 if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
1403 reset_regdomains();
1404 cfg80211_regdomain = rd;
1405 return 0;
1406 }
1407
1408 /* For a driver hint, lets copy the regulatory domain the
1409 * driver wanted to the wiphy to deal with conflicts */
1410
1411 BUG_ON(last_request->wiphy->regd);
1412
1413 r = reg_copy_regd(&last_request->wiphy->regd, rd);
1414 if (r)
1415 return r;
1416
1344 reset_regdomains(); 1417 reset_regdomains();
1345 cfg80211_regdomain = rd; 1418 cfg80211_regdomain = rd;
1346 return 0; 1419 return 0;
@@ -1354,8 +1427,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
1354 if (!intersected_rd) 1427 if (!intersected_rd)
1355 return -EINVAL; 1428 return -EINVAL;
1356 1429
1357 /* We can trash what CRDA provided now */ 1430 /* We can trash what CRDA provided now.
1358 kfree(rd); 1431 * However if a driver requested this specific regulatory
1432 * domain we keep it for its private use */
1433 if (last_request->initiator == REGDOM_SET_BY_DRIVER)
1434 last_request->wiphy->regd = rd;
1435 else
1436 kfree(rd);
1437
1359 rd = NULL; 1438 rd = NULL;
1360 1439
1361 reset_regdomains(); 1440 reset_regdomains();
@@ -1439,6 +1518,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
1439/* Caller must hold cfg80211_drv_mutex */ 1518/* Caller must hold cfg80211_drv_mutex */
1440void reg_device_remove(struct wiphy *wiphy) 1519void reg_device_remove(struct wiphy *wiphy)
1441{ 1520{
1521 kfree(wiphy->regd);
1442 if (!last_request || !last_request->wiphy) 1522 if (!last_request || !last_request->wiphy)
1443 return; 1523 return;
1444 if (last_request->wiphy != wiphy) 1524 if (last_request->wiphy != wiphy)