diff options
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r-- | net/wireless/reg.c | 254 |
1 files changed, 201 insertions, 53 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 592b2e391d42..5fbeab50996f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -42,6 +42,18 @@ | |||
42 | #include "core.h" | 42 | #include "core.h" |
43 | #include "reg.h" | 43 | #include "reg.h" |
44 | 44 | ||
45 | /* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ | ||
46 | struct regulatory_request { | ||
47 | struct list_head list; | ||
48 | struct wiphy *wiphy; | ||
49 | int granted; | ||
50 | enum reg_set_by initiator; | ||
51 | char alpha2[2]; | ||
52 | }; | ||
53 | |||
54 | static LIST_HEAD(regulatory_requests); | ||
55 | DEFINE_MUTEX(cfg80211_reg_mutex); | ||
56 | |||
45 | /* To trigger userspace events */ | 57 | /* To trigger userspace events */ |
46 | static struct platform_device *reg_pdev; | 58 | static struct platform_device *reg_pdev; |
47 | 59 | ||
@@ -51,6 +63,161 @@ static u32 supported_bandwidths[] = { | |||
51 | MHZ_TO_KHZ(20), | 63 | MHZ_TO_KHZ(20), |
52 | }; | 64 | }; |
53 | 65 | ||
66 | static struct list_head regulatory_requests; | ||
67 | |||
68 | /* Central wireless core regulatory domains, we only need two, | ||
69 | * the current one and a world regulatory domain in case we have no | ||
70 | * information to give us an alpha2 */ | ||
71 | static struct ieee80211_regdomain *cfg80211_regdomain; | ||
72 | |||
73 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | ||
74 | static const struct ieee80211_regdomain world_regdom = { | ||
75 | .n_reg_rules = 1, | ||
76 | .alpha2 = "00", | ||
77 | .reg_rules = { | ||
78 | REG_RULE(2412-10, 2462+10, 40, 6, 20, | ||
79 | NL80211_RRF_PASSIVE_SCAN | | ||
80 | NL80211_RRF_NO_IBSS), | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | static struct ieee80211_regdomain *cfg80211_world_regdom = | ||
85 | (struct ieee80211_regdomain *) &world_regdom; | ||
86 | |||
87 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
88 | static char *ieee80211_regdom = "US"; | ||
89 | module_param(ieee80211_regdom, charp, 0444); | ||
90 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | ||
91 | |||
92 | /* We assume 40 MHz bandwidth for the old regulatory work. | ||
93 | * We make emphasis we are using the exact same frequencies | ||
94 | * as before */ | ||
95 | |||
96 | static const struct ieee80211_regdomain us_regdom = { | ||
97 | .n_reg_rules = 6, | ||
98 | .alpha2 = "US", | ||
99 | .reg_rules = { | ||
100 | /* IEEE 802.11b/g, channels 1..11 */ | ||
101 | REG_RULE(2412-10, 2462+10, 40, 6, 27, 0), | ||
102 | /* IEEE 802.11a, channel 36 */ | ||
103 | REG_RULE(5180-10, 5180+10, 40, 6, 23, 0), | ||
104 | /* IEEE 802.11a, channel 40 */ | ||
105 | REG_RULE(5200-10, 5200+10, 40, 6, 23, 0), | ||
106 | /* IEEE 802.11a, channel 44 */ | ||
107 | REG_RULE(5220-10, 5220+10, 40, 6, 23, 0), | ||
108 | /* IEEE 802.11a, channels 48..64 */ | ||
109 | REG_RULE(5240-10, 5320+10, 40, 6, 23, 0), | ||
110 | /* IEEE 802.11a, channels 149..165, outdoor */ | ||
111 | REG_RULE(5745-10, 5825+10, 40, 6, 30, 0), | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | static const struct ieee80211_regdomain jp_regdom = { | ||
116 | .n_reg_rules = 3, | ||
117 | .alpha2 = "JP", | ||
118 | .reg_rules = { | ||
119 | /* IEEE 802.11b/g, channels 1..14 */ | ||
120 | REG_RULE(2412-10, 2484+10, 40, 6, 20, 0), | ||
121 | /* IEEE 802.11a, channels 34..48 */ | ||
122 | REG_RULE(5170-10, 5240+10, 40, 6, 20, | ||
123 | NL80211_RRF_PASSIVE_SCAN), | ||
124 | /* IEEE 802.11a, channels 52..64 */ | ||
125 | REG_RULE(5260-10, 5320+10, 40, 6, 20, | ||
126 | NL80211_RRF_NO_IBSS | | ||
127 | NL80211_RRF_DFS), | ||
128 | } | ||
129 | }; | ||
130 | |||
131 | static const struct ieee80211_regdomain eu_regdom = { | ||
132 | .n_reg_rules = 6, | ||
133 | /* This alpha2 is bogus, we leave it here just for stupid | ||
134 | * backward compatibility */ | ||
135 | .alpha2 = "EU", | ||
136 | .reg_rules = { | ||
137 | /* IEEE 802.11b/g, channels 1..13 */ | ||
138 | REG_RULE(2412-10, 2472+10, 40, 6, 20, 0), | ||
139 | /* IEEE 802.11a, channel 36 */ | ||
140 | REG_RULE(5180-10, 5180+10, 40, 6, 23, | ||
141 | NL80211_RRF_PASSIVE_SCAN), | ||
142 | /* IEEE 802.11a, channel 40 */ | ||
143 | REG_RULE(5200-10, 5200+10, 40, 6, 23, | ||
144 | NL80211_RRF_PASSIVE_SCAN), | ||
145 | /* IEEE 802.11a, channel 44 */ | ||
146 | REG_RULE(5220-10, 5220+10, 40, 6, 23, | ||
147 | NL80211_RRF_PASSIVE_SCAN), | ||
148 | /* IEEE 802.11a, channels 48..64 */ | ||
149 | REG_RULE(5240-10, 5320+10, 40, 6, 20, | ||
150 | NL80211_RRF_NO_IBSS | | ||
151 | NL80211_RRF_DFS), | ||
152 | /* IEEE 802.11a, channels 100..140 */ | ||
153 | REG_RULE(5500-10, 5700+10, 40, 6, 30, | ||
154 | NL80211_RRF_NO_IBSS | | ||
155 | NL80211_RRF_DFS), | ||
156 | } | ||
157 | }; | ||
158 | |||
159 | static const struct ieee80211_regdomain *static_regdom(char *alpha2) | ||
160 | { | ||
161 | if (alpha2[0] == 'U' && alpha2[1] == 'S') | ||
162 | return &us_regdom; | ||
163 | if (alpha2[0] == 'J' && alpha2[1] == 'P') | ||
164 | return &jp_regdom; | ||
165 | if (alpha2[0] == 'E' && alpha2[1] == 'U') | ||
166 | return &eu_regdom; | ||
167 | /* Default, as per the old rules */ | ||
168 | return &us_regdom; | ||
169 | } | ||
170 | |||
171 | static bool is_old_static_regdom(struct ieee80211_regdomain *rd) | ||
172 | { | ||
173 | if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom) | ||
174 | return true; | ||
175 | return false; | ||
176 | } | ||
177 | |||
178 | /* The old crap never deals with a world regulatory domain, it only | ||
179 | * deals with the static regulatory domain passed and if possible | ||
180 | * an updated "US" or "JP" regulatory domain. We do however store the | ||
181 | * old static regulatory domain in cfg80211_world_regdom for convenience | ||
182 | * of use here */ | ||
183 | static void reset_regdomains_static(void) | ||
184 | { | ||
185 | if (!is_old_static_regdom(cfg80211_regdomain)) | ||
186 | kfree(cfg80211_regdomain); | ||
187 | /* This is setting the regdom to the old static regdom */ | ||
188 | cfg80211_regdomain = | ||
189 | (struct ieee80211_regdomain *) cfg80211_world_regdom; | ||
190 | } | ||
191 | #else | ||
192 | static void reset_regdomains(void) | ||
193 | { | ||
194 | if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) { | ||
195 | if (cfg80211_world_regdom == cfg80211_regdomain) { | ||
196 | kfree(cfg80211_regdomain); | ||
197 | } else { | ||
198 | kfree(cfg80211_world_regdom); | ||
199 | kfree(cfg80211_regdomain); | ||
200 | } | ||
201 | } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom) | ||
202 | kfree(cfg80211_regdomain); | ||
203 | |||
204 | cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom; | ||
205 | cfg80211_regdomain = NULL; | ||
206 | } | ||
207 | |||
208 | /* Dynamic world regulatory domain requested by the wireless | ||
209 | * core upon initialization */ | ||
210 | static void update_world_regdomain(struct ieee80211_regdomain *rd) | ||
211 | { | ||
212 | BUG_ON(list_empty(®ulatory_requests)); | ||
213 | |||
214 | reset_regdomains(); | ||
215 | |||
216 | cfg80211_world_regdom = rd; | ||
217 | cfg80211_regdomain = rd; | ||
218 | } | ||
219 | #endif | ||
220 | |||
54 | bool is_world_regdom(char *alpha2) | 221 | bool is_world_regdom(char *alpha2) |
55 | { | 222 | { |
56 | if (!alpha2) | 223 | if (!alpha2) |
@@ -555,58 +722,6 @@ void print_regdomain_info(struct ieee80211_regdomain *rd) | |||
555 | print_rd_rules(rd); | 722 | print_rd_rules(rd); |
556 | } | 723 | } |
557 | 724 | ||
558 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
559 | |||
560 | static bool is_old_static_regdom(struct ieee80211_regdomain *rd) | ||
561 | { | ||
562 | if (rd == &us_regdom || rd == &jp_regdom || rd == &eu_regdom) | ||
563 | return true; | ||
564 | return false; | ||
565 | } | ||
566 | |||
567 | /* The old crap never deals with a world regulatory domain, it only | ||
568 | * deals with the static regulatory domain passed and if possible | ||
569 | * an updated "US" or "JP" regulatory domain. We do however store the | ||
570 | * old static regulatory domain in cfg80211_world_regdom for convenience | ||
571 | * of use here */ | ||
572 | static void reset_regdomains_static(void) | ||
573 | { | ||
574 | if (!is_old_static_regdom(cfg80211_regdomain)) | ||
575 | kfree(cfg80211_regdomain); | ||
576 | /* This is setting the regdom to the old static regdom */ | ||
577 | cfg80211_regdomain = | ||
578 | (struct ieee80211_regdomain *) cfg80211_world_regdom; | ||
579 | } | ||
580 | #else | ||
581 | static void reset_regdomains(void) | ||
582 | { | ||
583 | if (cfg80211_world_regdom && cfg80211_world_regdom != &world_regdom) { | ||
584 | if (cfg80211_world_regdom == cfg80211_regdomain) { | ||
585 | kfree(cfg80211_regdomain); | ||
586 | } else { | ||
587 | kfree(cfg80211_world_regdom); | ||
588 | kfree(cfg80211_regdomain); | ||
589 | } | ||
590 | } else if (cfg80211_regdomain && cfg80211_regdomain != &world_regdom) | ||
591 | kfree(cfg80211_regdomain); | ||
592 | |||
593 | cfg80211_world_regdom = (struct ieee80211_regdomain *) &world_regdom; | ||
594 | cfg80211_regdomain = NULL; | ||
595 | } | ||
596 | |||
597 | /* Dynamic world regulatory domain requested by the wireless | ||
598 | * core upon initialization */ | ||
599 | static void update_world_regdomain(struct ieee80211_regdomain *rd) | ||
600 | { | ||
601 | BUG_ON(list_empty(®ulatory_requests)); | ||
602 | |||
603 | reset_regdomains(); | ||
604 | |||
605 | cfg80211_world_regdom = rd; | ||
606 | cfg80211_regdomain = rd; | ||
607 | } | ||
608 | #endif | ||
609 | |||
610 | static int __set_regdom(struct ieee80211_regdomain *rd) | 725 | static int __set_regdom(struct ieee80211_regdomain *rd) |
611 | { | 726 | { |
612 | struct regulatory_request *request = NULL; | 727 | struct regulatory_request *request = NULL; |
@@ -615,7 +730,7 @@ static int __set_regdom(struct ieee80211_regdomain *rd) | |||
615 | 730 | ||
616 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 731 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
617 | /* We ignore the world regdom with the old static regdomains setup | 732 | /* We ignore the world regdom with the old static regdomains setup |
618 | * as there is no point to it with satic regulatory definitions :( | 733 | * as there is no point to it with static regulatory definitions :( |
619 | * Don't worry this shit will be removed soon... */ | 734 | * Don't worry this shit will be removed soon... */ |
620 | if (is_world_regdom(rd->alpha2)) | 735 | if (is_world_regdom(rd->alpha2)) |
621 | return -EINVAL; | 736 | return -EINVAL; |
@@ -735,25 +850,58 @@ int set_regdom(struct ieee80211_regdomain *rd) | |||
735 | 850 | ||
736 | int regulatory_init(void) | 851 | int regulatory_init(void) |
737 | { | 852 | { |
853 | int err; | ||
854 | |||
738 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); | 855 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); |
739 | if (IS_ERR(reg_pdev)) | 856 | if (IS_ERR(reg_pdev)) |
740 | return PTR_ERR(reg_pdev); | 857 | return PTR_ERR(reg_pdev); |
858 | |||
859 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
860 | cfg80211_regdomain = | ||
861 | (struct ieee80211_regdomain *) static_regdom(ieee80211_regdom); | ||
862 | /* Used during reset_regdomains_static() */ | ||
863 | cfg80211_world_regdom = cfg80211_regdomain; | ||
864 | |||
865 | printk(KERN_INFO "cfg80211: Using old static regulatory domain:\n"); | ||
866 | print_regdomain_info(cfg80211_regdomain); | ||
867 | /* The old code still requests for a new regdomain and if | ||
868 | * you have CRDA you get it updated, otherwise you get | ||
869 | * stuck with the static values. We ignore "EU" code as | ||
870 | * that is not a valid ISO / IEC 3166 alpha2 */ | ||
871 | if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U') | ||
872 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, | ||
873 | ieee80211_regdom, NULL); | ||
874 | #else | ||
875 | cfg80211_regdomain = | ||
876 | (struct ieee80211_regdomain *) cfg80211_world_regdom; | ||
877 | |||
878 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL); | ||
879 | if (err) | ||
880 | printk(KERN_ERR "cfg80211: calling CRDA failed - " | ||
881 | "unable to update world regulatory domain, " | ||
882 | "using static definition\n"); | ||
883 | #endif | ||
884 | |||
741 | return 0; | 885 | return 0; |
742 | } | 886 | } |
743 | 887 | ||
744 | void regulatory_exit(void) | 888 | void regulatory_exit(void) |
745 | { | 889 | { |
746 | struct regulatory_request *req, *req_tmp; | 890 | struct regulatory_request *req, *req_tmp; |
891 | |||
747 | mutex_lock(&cfg80211_drv_mutex); | 892 | mutex_lock(&cfg80211_drv_mutex); |
893 | |||
748 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 894 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
749 | reset_regdomains_static(); | 895 | reset_regdomains_static(); |
750 | #else | 896 | #else |
751 | reset_regdomains(); | 897 | reset_regdomains(); |
752 | #endif | 898 | #endif |
899 | |||
753 | list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) { | 900 | list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) { |
754 | list_del(&req->list); | 901 | list_del(&req->list); |
755 | kfree(req); | 902 | kfree(req); |
756 | } | 903 | } |
757 | platform_device_unregister(reg_pdev); | 904 | platform_device_unregister(reg_pdev); |
905 | |||
758 | mutex_unlock(&cfg80211_drv_mutex); | 906 | mutex_unlock(&cfg80211_drv_mutex); |
759 | } | 907 | } |