aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-02-03 15:41:58 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-03 15:41:58 -0500
commit1725d409caba16ea5fc694bd50e95e79e8ced11a (patch)
tree688fe26dd4ceda5364692f0ce307aadb6f04f331 /net/wireless
parentb3ff29d2ccfe3af065a9b393699a8fbf2abd1b15 (diff)
parentb8abde45d7d6ab9e8ceced9b5990eeb1149d0b97 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/nl80211.c81
-rw-r--r--net/wireless/reg.c285
-rw-r--r--net/wireless/reg.h7
-rw-r--r--net/wireless/sysfs.c30
-rw-r--r--net/wireless/util.c2
6 files changed, 328 insertions, 89 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index b96fc0c3f1c4..125226476089 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -273,10 +273,16 @@ int wiphy_register(struct wiphy *wiphy)
273 273
274 sband->band = band; 274 sband->band = band;
275 275
276 if (!sband->n_channels || !sband->n_bitrates) { 276 if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
277 WARN_ON(1); 277 return -EINVAL;
278
279 /*
280 * Since we use a u32 for rate bitmaps in
281 * ieee80211_get_response_rate, we cannot
282 * have more than 32 legacy rates.
283 */
284 if (WARN_ON(sband->n_bitrates > 32))
278 return -EINVAL; 285 return -EINVAL;
279 }
280 286
281 for (i = 0; i < sband->n_channels; i++) { 287 for (i = 0; i < sband->n_channels; i++) {
282 sband->channels[i].orig_flags = 288 sband->channels[i].orig_flags =
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1e728fff474e..e69da8d20474 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
105 105
106 [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, 106 [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
107 .len = NL80211_HT_CAPABILITY_LEN }, 107 .len = NL80211_HT_CAPABILITY_LEN },
108
109 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
110 [NL80211_ATTR_IE] = { .type = NLA_BINARY,
111 .len = IEEE80211_MAX_DATA_LEN },
108}; 112};
109 113
110/* message building helper */ 114/* message building helper */
@@ -738,7 +742,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
738 if (info->attrs[NL80211_ATTR_KEY_IDX]) 742 if (info->attrs[NL80211_ATTR_KEY_IDX])
739 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 743 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
740 744
741 if (key_idx > 3) 745 if (key_idx > 5)
742 return -EINVAL; 746 return -EINVAL;
743 747
744 if (info->attrs[NL80211_ATTR_MAC]) 748 if (info->attrs[NL80211_ATTR_MAC])
@@ -804,30 +808,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
804 int err; 808 int err;
805 struct net_device *dev; 809 struct net_device *dev;
806 u8 key_idx; 810 u8 key_idx;
811 int (*func)(struct wiphy *wiphy, struct net_device *netdev,
812 u8 key_index);
807 813
808 if (!info->attrs[NL80211_ATTR_KEY_IDX]) 814 if (!info->attrs[NL80211_ATTR_KEY_IDX])
809 return -EINVAL; 815 return -EINVAL;
810 816
811 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 817 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
812 818
813 if (key_idx > 3) 819 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
820 if (key_idx < 4 || key_idx > 5)
821 return -EINVAL;
822 } else if (key_idx > 3)
814 return -EINVAL; 823 return -EINVAL;
815 824
816 /* currently only support setting default key */ 825 /* currently only support setting default key */
817 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) 826 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
827 !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
818 return -EINVAL; 828 return -EINVAL;
819 829
820 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 830 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
821 if (err) 831 if (err)
822 return err; 832 return err;
823 833
824 if (!drv->ops->set_default_key) { 834 if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
835 func = drv->ops->set_default_key;
836 else
837 func = drv->ops->set_default_mgmt_key;
838
839 if (!func) {
825 err = -EOPNOTSUPP; 840 err = -EOPNOTSUPP;
826 goto out; 841 goto out;
827 } 842 }
828 843
829 rtnl_lock(); 844 rtnl_lock();
830 err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); 845 err = func(&drv->wiphy, dev, key_idx);
831 rtnl_unlock(); 846 rtnl_unlock();
832 847
833 out: 848 out:
@@ -863,7 +878,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
863 if (info->attrs[NL80211_ATTR_MAC]) 878 if (info->attrs[NL80211_ATTR_MAC])
864 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 879 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
865 880
866 if (key_idx > 3) 881 if (key_idx > 5)
867 return -EINVAL; 882 return -EINVAL;
868 883
869 /* 884 /*
@@ -894,6 +909,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
894 if (params.key_len != 13) 909 if (params.key_len != 13)
895 return -EINVAL; 910 return -EINVAL;
896 break; 911 break;
912 case WLAN_CIPHER_SUITE_AES_CMAC:
913 if (params.key_len != 16)
914 return -EINVAL;
915 break;
897 default: 916 default:
898 return -EINVAL; 917 return -EINVAL;
899 } 918 }
@@ -928,7 +947,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
928 if (info->attrs[NL80211_ATTR_KEY_IDX]) 947 if (info->attrs[NL80211_ATTR_KEY_IDX])
929 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 948 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
930 949
931 if (key_idx > 3) 950 if (key_idx > 5)
932 return -EINVAL; 951 return -EINVAL;
933 952
934 if (info->attrs[NL80211_ATTR_MAC]) 953 if (info->attrs[NL80211_ATTR_MAC])
@@ -1889,6 +1908,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
1889 mutex_lock(&cfg80211_drv_mutex); 1908 mutex_lock(&cfg80211_drv_mutex);
1890 r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); 1909 r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
1891 mutex_unlock(&cfg80211_drv_mutex); 1910 mutex_unlock(&cfg80211_drv_mutex);
1911 /* This means the regulatory domain was already set, however
1912 * we don't want to confuse userspace with a "successful error"
1913 * message so lets just treat it as a success */
1914 if (r == -EALREADY)
1915 r = 0;
1892 return r; 1916 return r;
1893} 1917}
1894 1918
@@ -2134,6 +2158,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
2134 return -EINVAL; 2158 return -EINVAL;
2135} 2159}
2136 2160
2161static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
2162 struct genl_info *info)
2163{
2164 struct cfg80211_registered_device *drv;
2165 int err;
2166 struct net_device *dev;
2167 struct mgmt_extra_ie_params params;
2168
2169 memset(&params, 0, sizeof(params));
2170
2171 if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE])
2172 return -EINVAL;
2173 params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
2174 if (params.subtype > 15)
2175 return -EINVAL; /* FC Subtype field is 4 bits (0..15) */
2176
2177 if (info->attrs[NL80211_ATTR_IE]) {
2178 params.ies = nla_data(info->attrs[NL80211_ATTR_IE]);
2179 params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2180 }
2181
2182 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2183 if (err)
2184 return err;
2185
2186 if (drv->ops->set_mgmt_extra_ie) {
2187 rtnl_lock();
2188 err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
2189 rtnl_unlock();
2190 } else
2191 err = -EOPNOTSUPP;
2192
2193 cfg80211_put_dev(drv);
2194 dev_put(dev);
2195 return err;
2196}
2197
2137static struct genl_ops nl80211_ops[] = { 2198static struct genl_ops nl80211_ops[] = {
2138 { 2199 {
2139 .cmd = NL80211_CMD_GET_WIPHY, 2200 .cmd = NL80211_CMD_GET_WIPHY,
@@ -2295,6 +2356,12 @@ static struct genl_ops nl80211_ops[] = {
2295 .policy = nl80211_policy, 2356 .policy = nl80211_policy,
2296 .flags = GENL_ADMIN_PERM, 2357 .flags = GENL_ADMIN_PERM,
2297 }, 2358 },
2359 {
2360 .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE,
2361 .doit = nl80211_set_mgmt_extra_ie,
2362 .policy = nl80211_policy,
2363 .flags = GENL_ADMIN_PERM,
2364 },
2298}; 2365};
2299 2366
2300/* multicast groups */ 2367/* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 85c9034c59b2..f643d3981102 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -42,38 +42,6 @@
42#include "core.h" 42#include "core.h"
43#include "reg.h" 43#include "reg.h"
44 44
45/**
46 * struct regulatory_request - receipt of last regulatory request
47 *
48 * @wiphy: this is set if this request's initiator is
49 * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
50 * can be used by the wireless core to deal with conflicts
51 * and potentially inform users of which devices specifically
52 * cased the conflicts.
53 * @initiator: indicates who sent this request, could be any of
54 * of those set in reg_set_by, %REGDOM_SET_BY_*
55 * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
56 * regulatory domain. We have a few special codes:
57 * 00 - World regulatory domain
58 * 99 - built by driver but a specific alpha2 cannot be determined
59 * 98 - result of an intersection between two regulatory domains
60 * @intersect: indicates whether the wireless core should intersect
61 * the requested regulatory domain with the presently set regulatory
62 * domain.
63 * @country_ie_checksum: checksum of the last processed and accepted
64 * country IE
65 * @country_ie_env: lets us know if the AP is telling us we are outdoor,
66 * indoor, or if it doesn't matter
67 */
68struct regulatory_request {
69 struct wiphy *wiphy;
70 enum reg_set_by initiator;
71 char alpha2[2];
72 bool intersect;
73 u32 country_ie_checksum;
74 enum environment_cap country_ie_env;
75};
76
77/* Receipt of information from last regulatory request */ 45/* Receipt of information from last regulatory request */
78static struct regulatory_request *last_request; 46static struct regulatory_request *last_request;
79 47
@@ -790,42 +758,35 @@ static u32 map_regdom_flags(u32 rd_flags)
790 return channel_flags; 758 return channel_flags;
791} 759}
792 760
793/** 761static int freq_reg_info_regd(struct wiphy *wiphy,
794 * freq_reg_info - get regulatory information for the given frequency 762 u32 center_freq,
795 * @center_freq: Frequency in KHz for which we want regulatory information for 763 u32 *bandwidth,
796 * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one 764 const struct ieee80211_reg_rule **reg_rule,
797 * you can set this to 0. If this frequency is allowed we then set 765 const struct ieee80211_regdomain *custom_regd)
798 * this value to the maximum allowed bandwidth.
799 * @reg_rule: the regulatory rule which we have for this frequency
800 *
801 * Use this function to get the regulatory rule for a specific frequency on
802 * a given wireless device. If the device has a specific regulatory domain
803 * it wants to follow we respect that unless a country IE has been received
804 * and processed already.
805 *
806 * Returns 0 if it was able to find a valid regulatory rule which does
807 * apply to the given center_freq otherwise it returns non-zero. It will
808 * also return -ERANGE if we determine the given center_freq does not even have
809 * a regulatory rule for a frequency range in the center_freq's band. See
810 * freq_in_rule_band() for our current definition of a band -- this is purely
811 * subjective and right now its 802.11 specific.
812 */
813static int freq_reg_info(u32 center_freq, u32 *bandwidth,
814 const struct ieee80211_reg_rule **reg_rule)
815{ 766{
816 int i; 767 int i;
817 bool band_rule_found = false; 768 bool band_rule_found = false;
769 const struct ieee80211_regdomain *regd;
818 u32 max_bandwidth = 0; 770 u32 max_bandwidth = 0;
819 771
820 if (!cfg80211_regdomain) 772 regd = custom_regd ? custom_regd : cfg80211_regdomain;
773
774 /* Follow the driver's regulatory domain, if present, unless a country
775 * IE has been processed or a user wants to help complaince further */
776 if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
777 last_request->initiator != REGDOM_SET_BY_USER &&
778 wiphy->regd)
779 regd = wiphy->regd;
780
781 if (!regd)
821 return -EINVAL; 782 return -EINVAL;
822 783
823 for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { 784 for (i = 0; i < regd->n_reg_rules; i++) {
824 const struct ieee80211_reg_rule *rr; 785 const struct ieee80211_reg_rule *rr;
825 const struct ieee80211_freq_range *fr = NULL; 786 const struct ieee80211_freq_range *fr = NULL;
826 const struct ieee80211_power_rule *pr = NULL; 787 const struct ieee80211_power_rule *pr = NULL;
827 788
828 rr = &cfg80211_regdomain->reg_rules[i]; 789 rr = &regd->reg_rules[i];
829 fr = &rr->freq_range; 790 fr = &rr->freq_range;
830 pr = &rr->power_rule; 791 pr = &rr->power_rule;
831 792
@@ -849,6 +810,14 @@ static int freq_reg_info(u32 center_freq, u32 *bandwidth,
849 810
850 return !max_bandwidth; 811 return !max_bandwidth;
851} 812}
813EXPORT_SYMBOL(freq_reg_info);
814
815int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
816 const struct ieee80211_reg_rule **reg_rule)
817{
818 return freq_reg_info_regd(wiphy, center_freq,
819 bandwidth, reg_rule, NULL);
820}
852 821
853static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, 822static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
854 unsigned int chan_idx) 823 unsigned int chan_idx)
@@ -867,7 +836,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
867 836
868 flags = chan->orig_flags; 837 flags = chan->orig_flags;
869 838
870 r = freq_reg_info(MHZ_TO_KHZ(chan->center_freq), 839 r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
871 &max_bandwidth, &reg_rule); 840 &max_bandwidth, &reg_rule);
872 841
873 if (r) { 842 if (r) {
@@ -907,6 +876,22 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
907 876
908 power_rule = &reg_rule->power_rule; 877 power_rule = &reg_rule->power_rule;
909 878
879 if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
880 last_request->wiphy && last_request->wiphy == wiphy &&
881 last_request->wiphy->strict_regulatory) {
882 /* This gaurantees the driver's requested regulatory domain
883 * will always be used as a base for further regulatory
884 * settings */
885 chan->flags = chan->orig_flags =
886 map_regdom_flags(reg_rule->flags);
887 chan->max_antenna_gain = chan->orig_mag =
888 (int) MBI_TO_DBI(power_rule->max_antenna_gain);
889 chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
890 chan->max_power = chan->orig_mpwr =
891 (int) MBM_TO_DBM(power_rule->max_eirp);
892 return;
893 }
894
910 chan->flags = flags | map_regdom_flags(reg_rule->flags); 895 chan->flags = flags | map_regdom_flags(reg_rule->flags);
911 chan->max_antenna_gain = min(chan->orig_mag, 896 chan->max_antenna_gain = min(chan->orig_mag,
912 (int) MBI_TO_DBI(power_rule->max_antenna_gain)); 897 (int) MBI_TO_DBI(power_rule->max_antenna_gain));
@@ -935,7 +920,12 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
935 if (!last_request) 920 if (!last_request)
936 return true; 921 return true;
937 if (setby == REGDOM_SET_BY_CORE && 922 if (setby == REGDOM_SET_BY_CORE &&
938 wiphy->fw_handles_regulatory) 923 wiphy->custom_regulatory)
924 return true;
925 /* wiphy->regd will be set once the device has its own
926 * desired regulatory domain set */
927 if (wiphy->strict_regulatory && !wiphy->regd &&
928 !is_world_regdom(last_request->alpha2))
939 return true; 929 return true;
940 return false; 930 return false;
941} 931}
@@ -945,20 +935,103 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby)
945 struct cfg80211_registered_device *drv; 935 struct cfg80211_registered_device *drv;
946 936
947 list_for_each_entry(drv, &cfg80211_drv_list, list) 937 list_for_each_entry(drv, &cfg80211_drv_list, list)
948 if (!ignore_reg_update(&drv->wiphy, setby)) 938 wiphy_update_regulatory(&drv->wiphy, setby);
949 wiphy_update_regulatory(&drv->wiphy, setby);
950} 939}
951 940
952void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) 941void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
953{ 942{
954 enum ieee80211_band band; 943 enum ieee80211_band band;
944
945 if (ignore_reg_update(wiphy, setby))
946 return;
955 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 947 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
956 if (wiphy->bands[band]) 948 if (wiphy->bands[band])
957 handle_band(wiphy, band); 949 handle_band(wiphy, band);
958 if (wiphy->reg_notifier) 950 }
959 wiphy->reg_notifier(wiphy, setby); 951 if (wiphy->reg_notifier)
952 wiphy->reg_notifier(wiphy, last_request);
953}
954
955static void handle_channel_custom(struct wiphy *wiphy,
956 enum ieee80211_band band,
957 unsigned int chan_idx,
958 const struct ieee80211_regdomain *regd)
959{
960 int r;
961 u32 max_bandwidth = 0;
962 const struct ieee80211_reg_rule *reg_rule = NULL;
963 const struct ieee80211_power_rule *power_rule = NULL;
964 struct ieee80211_supported_band *sband;
965 struct ieee80211_channel *chan;
966
967 sband = wiphy->bands[band];
968 BUG_ON(chan_idx >= sband->n_channels);
969 chan = &sband->channels[chan_idx];
970
971 r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
972 &max_bandwidth, &reg_rule, regd);
973
974 if (r) {
975 chan->flags = IEEE80211_CHAN_DISABLED;
976 return;
977 }
978
979 power_rule = &reg_rule->power_rule;
980
981 chan->flags |= map_regdom_flags(reg_rule->flags);
982 chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
983 chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
984 chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
985}
986
987static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
988 const struct ieee80211_regdomain *regd)
989{
990 unsigned int i;
991 struct ieee80211_supported_band *sband;
992
993 BUG_ON(!wiphy->bands[band]);
994 sband = wiphy->bands[band];
995
996 for (i = 0; i < sband->n_channels; i++)
997 handle_channel_custom(wiphy, band, i, regd);
998}
999
1000/* Used by drivers prior to wiphy registration */
1001void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
1002 const struct ieee80211_regdomain *regd)
1003{
1004 enum ieee80211_band band;
1005 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1006 if (wiphy->bands[band])
1007 handle_band_custom(wiphy, band, regd);
960 } 1008 }
961} 1009}
1010EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
1011
1012static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
1013 const struct ieee80211_regdomain *src_regd)
1014{
1015 struct ieee80211_regdomain *regd;
1016 int size_of_regd = 0;
1017 unsigned int i;
1018
1019 size_of_regd = sizeof(struct ieee80211_regdomain) +
1020 ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
1021
1022 regd = kzalloc(size_of_regd, GFP_KERNEL);
1023 if (!regd)
1024 return -ENOMEM;
1025
1026 memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
1027
1028 for (i = 0; i < src_regd->n_reg_rules; i++)
1029 memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
1030 sizeof(struct ieee80211_reg_rule));
1031
1032 *dst_regd = regd;
1033 return 0;
1034}
962 1035
963/* Return value which can be used by ignore_request() to indicate 1036/* Return value which can be used by ignore_request() to indicate
964 * it has been determined we should intersect two regulatory domains */ 1037 * it has been determined we should intersect two regulatory domains */
@@ -1007,9 +1080,14 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
1007 } 1080 }
1008 return REG_INTERSECT; 1081 return REG_INTERSECT;
1009 case REGDOM_SET_BY_DRIVER: 1082 case REGDOM_SET_BY_DRIVER:
1010 if (last_request->initiator == REGDOM_SET_BY_DRIVER) 1083 if (last_request->initiator == REGDOM_SET_BY_CORE) {
1084 if (is_old_static_regdom(cfg80211_regdomain))
1085 return 0;
1086 if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
1087 return 0;
1011 return -EALREADY; 1088 return -EALREADY;
1012 return 0; 1089 }
1090 return REG_INTERSECT;
1013 case REGDOM_SET_BY_USER: 1091 case REGDOM_SET_BY_USER:
1014 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) 1092 if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
1015 return REG_INTERSECT; 1093 return REG_INTERSECT;
@@ -1018,6 +1096,20 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
1018 if (last_request->initiator == REGDOM_SET_BY_USER && 1096 if (last_request->initiator == REGDOM_SET_BY_USER &&
1019 last_request->intersect) 1097 last_request->intersect)
1020 return -EOPNOTSUPP; 1098 return -EOPNOTSUPP;
1099 /* Process user requests only after previous user/driver/core
1100 * requests have been processed */
1101 if (last_request->initiator == REGDOM_SET_BY_CORE ||
1102 last_request->initiator == REGDOM_SET_BY_DRIVER ||
1103 last_request->initiator == REGDOM_SET_BY_USER) {
1104 if (!alpha2_equal(last_request->alpha2,
1105 cfg80211_regdomain->alpha2))
1106 return -EAGAIN;
1107 }
1108
1109 if (!is_old_static_regdom(cfg80211_regdomain) &&
1110 alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
1111 return -EALREADY;
1112
1021 return 0; 1113 return 0;
1022 } 1114 }
1023 1115
@@ -1036,11 +1128,28 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1036 1128
1037 r = ignore_request(wiphy, set_by, alpha2); 1129 r = ignore_request(wiphy, set_by, alpha2);
1038 1130
1039 if (r == REG_INTERSECT) 1131 if (r == REG_INTERSECT) {
1132 if (set_by == REGDOM_SET_BY_DRIVER) {
1133 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
1134 if (r)
1135 return r;
1136 }
1040 intersect = true; 1137 intersect = true;
1041 else if (r) 1138 } else if (r) {
1139 /* If the regulatory domain being requested by the
1140 * driver has already been set just copy it to the
1141 * wiphy */
1142 if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
1143 r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
1144 if (r)
1145 return r;
1146 r = -EALREADY;
1147 goto new_request;
1148 }
1042 return r; 1149 return r;
1150 }
1043 1151
1152new_request:
1044 request = kzalloc(sizeof(struct regulatory_request), 1153 request = kzalloc(sizeof(struct regulatory_request),
1045 GFP_KERNEL); 1154 GFP_KERNEL);
1046 if (!request) 1155 if (!request)
@@ -1056,6 +1165,11 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1056 1165
1057 kfree(last_request); 1166 kfree(last_request);
1058 last_request = request; 1167 last_request = request;
1168
1169 /* When r == REG_INTERSECT we do need to call CRDA */
1170 if (r < 0)
1171 return r;
1172
1059 /* 1173 /*
1060 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled 1174 * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
1061 * AND if CRDA is NOT present nothing will happen, if someone 1175 * AND if CRDA is NOT present nothing will happen, if someone
@@ -1071,10 +1185,15 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1071 1185
1072void regulatory_hint(struct wiphy *wiphy, const char *alpha2) 1186void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
1073{ 1187{
1188 int r;
1074 BUG_ON(!alpha2); 1189 BUG_ON(!alpha2);
1075 1190
1076 mutex_lock(&cfg80211_drv_mutex); 1191 mutex_lock(&cfg80211_drv_mutex);
1077 __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY); 1192 r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,
1193 alpha2, 0, ENVIRON_ANY);
1194 /* This is required so that the orig_* parameters are saved */
1195 if (r == -EALREADY && wiphy->strict_regulatory)
1196 wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);
1078 mutex_unlock(&cfg80211_drv_mutex); 1197 mutex_unlock(&cfg80211_drv_mutex);
1079} 1198}
1080EXPORT_SYMBOL(regulatory_hint); 1199EXPORT_SYMBOL(regulatory_hint);
@@ -1247,7 +1366,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
1247 "domain intersected: \n"); 1366 "domain intersected: \n");
1248 } else 1367 } else
1249 printk(KERN_INFO "cfg80211: Current regulatory " 1368 printk(KERN_INFO "cfg80211: Current regulatory "
1250 "intersected: \n"); 1369 "domain intersected: \n");
1251 } else if (is_world_regdom(rd->alpha2)) 1370 } else if (is_world_regdom(rd->alpha2))
1252 printk(KERN_INFO "cfg80211: World regulatory " 1371 printk(KERN_INFO "cfg80211: World regulatory "
1253 "domain updated:\n"); 1372 "domain updated:\n");
@@ -1349,6 +1468,23 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
1349 } 1468 }
1350 1469
1351 if (!last_request->intersect) { 1470 if (!last_request->intersect) {
1471 int r;
1472
1473 if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
1474 reset_regdomains();
1475 cfg80211_regdomain = rd;
1476 return 0;
1477 }
1478
1479 /* For a driver hint, lets copy the regulatory domain the
1480 * driver wanted to the wiphy to deal with conflicts */
1481
1482 BUG_ON(last_request->wiphy->regd);
1483
1484 r = reg_copy_regd(&last_request->wiphy->regd, rd);
1485 if (r)
1486 return r;
1487
1352 reset_regdomains(); 1488 reset_regdomains();
1353 cfg80211_regdomain = rd; 1489 cfg80211_regdomain = rd;
1354 return 0; 1490 return 0;
@@ -1362,8 +1498,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
1362 if (!intersected_rd) 1498 if (!intersected_rd)
1363 return -EINVAL; 1499 return -EINVAL;
1364 1500
1365 /* We can trash what CRDA provided now */ 1501 /* We can trash what CRDA provided now.
1366 kfree(rd); 1502 * However if a driver requested this specific regulatory
1503 * domain we keep it for its private use */
1504 if (last_request->initiator == REGDOM_SET_BY_DRIVER)
1505 last_request->wiphy->regd = rd;
1506 else
1507 kfree(rd);
1508
1367 rd = NULL; 1509 rd = NULL;
1368 1510
1369 reset_regdomains(); 1511 reset_regdomains();
@@ -1447,6 +1589,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
1447/* Caller must hold cfg80211_drv_mutex */ 1589/* Caller must hold cfg80211_drv_mutex */
1448void reg_device_remove(struct wiphy *wiphy) 1590void reg_device_remove(struct wiphy *wiphy)
1449{ 1591{
1592 kfree(wiphy->regd);
1450 if (!last_request || !last_request->wiphy) 1593 if (!last_request || !last_request->wiphy)
1451 return; 1594 return;
1452 if (last_request->wiphy != wiphy) 1595 if (last_request->wiphy != wiphy)
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index a76ea3ff7cd6..eb1dd5bc9b27 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -11,13 +11,6 @@ void regulatory_exit(void);
11 11
12int set_regdom(const struct ieee80211_regdomain *rd); 12int set_regdom(const struct ieee80211_regdomain *rd);
13 13
14enum environment_cap {
15 ENVIRON_ANY,
16 ENVIRON_INDOOR,
17 ENVIRON_OUTDOOR,
18};
19
20
21/** 14/**
22 * __regulatory_hint - hint to the wireless core a regulatory domain 15 * __regulatory_hint - hint to the wireless core a regulatory domain
23 * @wiphy: if the hint comes from country information from an AP, this 16 * @wiphy: if the hint comes from country information from an AP, this
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 79a382877641..26a72b0797a0 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -55,6 +55,34 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
55} 55}
56#endif 56#endif
57 57
58static int wiphy_suspend(struct device *dev, pm_message_t state)
59{
60 struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
61 int ret = 0;
62
63 if (rdev->ops->suspend) {
64 rtnl_lock();
65 ret = rdev->ops->suspend(&rdev->wiphy);
66 rtnl_unlock();
67 }
68
69 return ret;
70}
71
72static int wiphy_resume(struct device *dev)
73{
74 struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
75 int ret = 0;
76
77 if (rdev->ops->resume) {
78 rtnl_lock();
79 ret = rdev->ops->resume(&rdev->wiphy);
80 rtnl_unlock();
81 }
82
83 return ret;
84}
85
58struct class ieee80211_class = { 86struct class ieee80211_class = {
59 .name = "ieee80211", 87 .name = "ieee80211",
60 .owner = THIS_MODULE, 88 .owner = THIS_MODULE,
@@ -63,6 +91,8 @@ struct class ieee80211_class = {
63#ifdef CONFIG_HOTPLUG 91#ifdef CONFIG_HOTPLUG
64 .dev_uevent = wiphy_uevent, 92 .dev_uevent = wiphy_uevent,
65#endif 93#endif
94 .suspend = wiphy_suspend,
95 .resume = wiphy_resume,
66}; 96};
67 97
68int wiphy_sysfs_init(void) 98int wiphy_sysfs_init(void)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index e76cc28b0345..487cdd9bcffc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -9,7 +9,7 @@
9 9
10struct ieee80211_rate * 10struct ieee80211_rate *
11ieee80211_get_response_rate(struct ieee80211_supported_band *sband, 11ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
12 u64 basic_rates, int bitrate) 12 u32 basic_rates, int bitrate)
13{ 13{
14 struct ieee80211_rate *result = &sband->bitrates[0]; 14 struct ieee80211_rate *result = &sband->bitrates[0];
15 int i; 15 int i;