regd.c revision 81b290451122e93b9731bc333c6be2e49fa5bc0c
1/****************************************************************************** 2 * 3 * Copyright(c) 2009-2010 Realtek Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 17 * 18 * The full GNU General Public License is included in this distribution in the 19 * file called LICENSE. 20 * 21 * Contact Information: 22 * wlanfae <wlanfae@realtek.com> 23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, 24 * Hsinchu 300, Taiwan. 25 * 26 * Larry Finger <Larry.Finger@lwfinger.net> 27 * 28 *****************************************************************************/ 29 30#include "wifi.h" 31#include "regd.h" 32 33static struct country_code_to_enum_rd allCountries[] = { 34 {COUNTRY_CODE_FCC, "US"}, 35 {COUNTRY_CODE_IC, "US"}, 36 {COUNTRY_CODE_ETSI, "EC"}, 37 {COUNTRY_CODE_SPAIN, "EC"}, 38 {COUNTRY_CODE_FRANCE, "EC"}, 39 {COUNTRY_CODE_MKK, "JP"}, 40 {COUNTRY_CODE_MKK1, "JP"}, 41 {COUNTRY_CODE_ISRAEL, "EC"}, 42 {COUNTRY_CODE_TELEC, "JP"}, 43 {COUNTRY_CODE_MIC, "JP"}, 44 {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"}, 45 {COUNTRY_CODE_WORLD_WIDE_13, "EC"}, 46 {COUNTRY_CODE_TELEC_NETGEAR, "EC"}, 47}; 48 49/* 50 *Only these channels all allow active 51 *scan on all world regulatory domains 52 */ 53#define RTL819x_2GHZ_CH01_11 \ 54 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) 55 56/* 57 *We enable active scan on these a case 58 *by case basis by regulatory domain 59 */ 60#define RTL819x_2GHZ_CH12_13 \ 61 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ 62 NL80211_RRF_PASSIVE_SCAN) 63 64#define RTL819x_2GHZ_CH14 \ 65 REG_RULE(2484-10, 2484+10, 40, 0, 20, \ 66 NL80211_RRF_PASSIVE_SCAN | \ 67 NL80211_RRF_NO_OFDM) 68 69/* 5G chan 36 - chan 64*/ 70#define RTL819x_5GHZ_5150_5350 \ 71 REG_RULE(5150-10, 5350+10, 40, 0, 30, \ 72 NL80211_RRF_PASSIVE_SCAN | \ 73 NL80211_RRF_NO_IBSS) 74 75/* 5G chan 100 - chan 165*/ 76#define RTL819x_5GHZ_5470_5850 \ 77 REG_RULE(5470-10, 5850+10, 40, 0, 30, \ 78 NL80211_RRF_PASSIVE_SCAN | \ 79 NL80211_RRF_NO_IBSS) 80 81/* 5G chan 149 - chan 165*/ 82#define RTL819x_5GHZ_5725_5850 \ 83 REG_RULE(5725-10, 5850+10, 40, 0, 30, \ 84 NL80211_RRF_PASSIVE_SCAN | \ 85 NL80211_RRF_NO_IBSS) 86 87#define RTL819x_5GHZ_ALL \ 88 (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) 89 90static const struct ieee80211_regdomain rtl_regdom_11 = { 91 .n_reg_rules = 1, 92 .alpha2 = "99", 93 .reg_rules = { 94 RTL819x_2GHZ_CH01_11, 95 } 96}; 97 98static const struct ieee80211_regdomain rtl_regdom_12_13 = { 99 .n_reg_rules = 2, 100 .alpha2 = "99", 101 .reg_rules = { 102 RTL819x_2GHZ_CH01_11, 103 RTL819x_2GHZ_CH12_13, 104 } 105}; 106 107static const struct ieee80211_regdomain rtl_regdom_no_midband = { 108 .n_reg_rules = 3, 109 .alpha2 = "99", 110 .reg_rules = { 111 RTL819x_2GHZ_CH01_11, 112 RTL819x_5GHZ_5150_5350, 113 RTL819x_5GHZ_5725_5850, 114 } 115}; 116 117static const struct ieee80211_regdomain rtl_regdom_60_64 = { 118 .n_reg_rules = 3, 119 .alpha2 = "99", 120 .reg_rules = { 121 RTL819x_2GHZ_CH01_11, 122 RTL819x_2GHZ_CH12_13, 123 RTL819x_5GHZ_5725_5850, 124 } 125}; 126 127static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { 128 .n_reg_rules = 4, 129 .alpha2 = "99", 130 .reg_rules = { 131 RTL819x_2GHZ_CH01_11, 132 RTL819x_2GHZ_CH12_13, 133 RTL819x_2GHZ_CH14, 134 RTL819x_5GHZ_5725_5850, 135 } 136}; 137 138static const struct ieee80211_regdomain rtl_regdom_14 = { 139 .n_reg_rules = 3, 140 .alpha2 = "99", 141 .reg_rules = { 142 RTL819x_2GHZ_CH01_11, 143 RTL819x_2GHZ_CH12_13, 144 RTL819x_2GHZ_CH14, 145 } 146}; 147 148static bool _rtl_is_radar_freq(u16 center_freq) 149{ 150 return (center_freq >= 5260 && center_freq <= 5700); 151} 152 153static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, 154 enum nl80211_reg_initiator initiator) 155{ 156 enum ieee80211_band band; 157 struct ieee80211_supported_band *sband; 158 const struct ieee80211_reg_rule *reg_rule; 159 struct ieee80211_channel *ch; 160 unsigned int i; 161 u32 bandwidth = 0; 162 int r; 163 164 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 165 166 if (!wiphy->bands[band]) 167 continue; 168 169 sband = wiphy->bands[band]; 170 171 for (i = 0; i < sband->n_channels; i++) { 172 ch = &sband->channels[i]; 173 if (_rtl_is_radar_freq(ch->center_freq) || 174 (ch->flags & IEEE80211_CHAN_RADAR)) 175 continue; 176 if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { 177 r = freq_reg_info(wiphy, ch->center_freq, 178 bandwidth, ®_rule); 179 if (r) 180 continue; 181 182 /* 183 *If 11d had a rule for this channel ensure 184 *we enable adhoc/beaconing if it allows us to 185 *use it. Note that we would have disabled it 186 *by applying our static world regdomain by 187 *default during init, prior to calling our 188 *regulatory_hint(). 189 */ 190 191 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) 192 ch->flags &= ~IEEE80211_CHAN_NO_IBSS; 193 if (!(reg_rule-> 194 flags & NL80211_RRF_PASSIVE_SCAN)) 195 ch->flags &= 196 ~IEEE80211_CHAN_PASSIVE_SCAN; 197 } else { 198 if (ch->beacon_found) 199 ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | 200 IEEE80211_CHAN_PASSIVE_SCAN); 201 } 202 } 203 } 204} 205 206/* Allows active scan scan on Ch 12 and 13 */ 207static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, 208 enum nl80211_reg_initiator 209 initiator) 210{ 211 struct ieee80211_supported_band *sband; 212 struct ieee80211_channel *ch; 213 const struct ieee80211_reg_rule *reg_rule; 214 u32 bandwidth = 0; 215 int r; 216 217 if (!wiphy->bands[IEEE80211_BAND_2GHZ]) 218 return; 219 sband = wiphy->bands[IEEE80211_BAND_2GHZ]; 220 221 /* 222 *If no country IE has been received always enable active scan 223 *on these channels. This is only done for specific regulatory SKUs 224 */ 225 if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { 226 ch = &sband->channels[11]; /* CH 12 */ 227 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 228 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 229 ch = &sband->channels[12]; /* CH 13 */ 230 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 231 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 232 return; 233 } 234 235 /* 236 *If a country IE has been recieved check its rule for this 237 *channel first before enabling active scan. The passive scan 238 *would have been enforced by the initial processing of our 239 *custom regulatory domain. 240 */ 241 242 ch = &sband->channels[11]; /* CH 12 */ 243 r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); 244 if (!r) { 245 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) 246 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 247 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 248 } 249 250 ch = &sband->channels[12]; /* CH 13 */ 251 r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); 252 if (!r) { 253 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) 254 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 255 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 256 } 257} 258 259/* 260 *Always apply Radar/DFS rules on 261 *freq range 5260 MHz - 5700 MHz 262 */ 263static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) 264{ 265 struct ieee80211_supported_band *sband; 266 struct ieee80211_channel *ch; 267 unsigned int i; 268 269 if (!wiphy->bands[IEEE80211_BAND_5GHZ]) 270 return; 271 272 sband = wiphy->bands[IEEE80211_BAND_5GHZ]; 273 274 for (i = 0; i < sband->n_channels; i++) { 275 ch = &sband->channels[i]; 276 if (!_rtl_is_radar_freq(ch->center_freq)) 277 continue; 278 279 /* 280 *We always enable radar detection/DFS on this 281 *frequency range. Additionally we also apply on 282 *this frequency range: 283 *- If STA mode does not yet have DFS supports disable 284 * active scanning 285 *- If adhoc mode does not support DFS yet then disable 286 * adhoc in the frequency. 287 *- If AP mode does not yet support radar detection/DFS 288 *do not allow AP mode 289 */ 290 if (!(ch->flags & IEEE80211_CHAN_DISABLED)) 291 ch->flags |= IEEE80211_CHAN_RADAR | 292 IEEE80211_CHAN_NO_IBSS | 293 IEEE80211_CHAN_PASSIVE_SCAN; 294 } 295} 296 297static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, 298 enum nl80211_reg_initiator initiator, 299 struct rtl_regulatory *reg) 300{ 301 _rtl_reg_apply_beaconing_flags(wiphy, initiator); 302 _rtl_reg_apply_active_scan_flags(wiphy, initiator); 303 return; 304} 305 306static void _rtl_dump_channel_map(struct wiphy *wiphy) 307{ 308 enum ieee80211_band band; 309 struct ieee80211_supported_band *sband; 310 struct ieee80211_channel *ch; 311 unsigned int i; 312 313 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 314 if (!wiphy->bands[band]) 315 continue; 316 sband = wiphy->bands[band]; 317 for (i = 0; i < sband->n_channels; i++) 318 ch = &sband->channels[i]; 319 } 320} 321 322static int _rtl_reg_notifier_apply(struct wiphy *wiphy, 323 struct regulatory_request *request, 324 struct rtl_regulatory *reg) 325{ 326 /* We always apply this */ 327 _rtl_reg_apply_radar_flags(wiphy); 328 329 switch (request->initiator) { 330 case NL80211_REGDOM_SET_BY_DRIVER: 331 case NL80211_REGDOM_SET_BY_CORE: 332 case NL80211_REGDOM_SET_BY_USER: 333 break; 334 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 335 _rtl_reg_apply_world_flags(wiphy, request->initiator, reg); 336 break; 337 } 338 339 _rtl_dump_channel_map(wiphy); 340 341 return 0; 342} 343 344static const struct ieee80211_regdomain *_rtl_regdomain_select( 345 struct rtl_regulatory *reg) 346{ 347 switch (reg->country_code) { 348 case COUNTRY_CODE_FCC: 349 return &rtl_regdom_no_midband; 350 case COUNTRY_CODE_IC: 351 return &rtl_regdom_11; 352 case COUNTRY_CODE_ETSI: 353 case COUNTRY_CODE_TELEC_NETGEAR: 354 return &rtl_regdom_60_64; 355 case COUNTRY_CODE_SPAIN: 356 case COUNTRY_CODE_FRANCE: 357 case COUNTRY_CODE_ISRAEL: 358 case COUNTRY_CODE_WORLD_WIDE_13: 359 return &rtl_regdom_12_13; 360 case COUNTRY_CODE_MKK: 361 case COUNTRY_CODE_MKK1: 362 case COUNTRY_CODE_TELEC: 363 case COUNTRY_CODE_MIC: 364 return &rtl_regdom_14_60_64; 365 case COUNTRY_CODE_GLOBAL_DOMAIN: 366 return &rtl_regdom_14; 367 default: 368 return &rtl_regdom_no_midband; 369 } 370} 371 372static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, 373 struct wiphy *wiphy, 374 int (*reg_notifier) (struct wiphy *wiphy, 375 struct regulatory_request * 376 request)) 377{ 378 const struct ieee80211_regdomain *regd; 379 380 wiphy->reg_notifier = reg_notifier; 381 382 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; 383 wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; 384 wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; 385 386 regd = _rtl_regdomain_select(reg); 387 wiphy_apply_custom_regulatory(wiphy, regd); 388 _rtl_reg_apply_radar_flags(wiphy); 389 _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); 390 return 0; 391} 392 393static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) 394{ 395 int i; 396 397 for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 398 if (allCountries[i].countrycode == countrycode) 399 return &allCountries[i]; 400 } 401 return NULL; 402} 403 404int rtl_regd_init(struct ieee80211_hw *hw, 405 int (*reg_notifier) (struct wiphy *wiphy, 406 struct regulatory_request *request)) 407{ 408 struct rtl_priv *rtlpriv = rtl_priv(hw); 409 struct wiphy *wiphy = hw->wiphy; 410 struct country_code_to_enum_rd *country = NULL; 411 412 if (wiphy == NULL || &rtlpriv->regd == NULL) 413 return -EINVAL; 414 415 /* init country_code from efuse channel plan */ 416 rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; 417 418 RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, 419 (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", 420 rtlpriv->regd.country_code)); 421 422 if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { 423 RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG, 424 (KERN_DEBUG "rtl: EEPROM indicates invalid contry code" 425 "world wide 13 should be used\n")); 426 427 rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; 428 } 429 430 country = _rtl_regd_find_country(rtlpriv->regd.country_code); 431 432 if (country) { 433 rtlpriv->regd.alpha2[0] = country->iso_name[0]; 434 rtlpriv->regd.alpha2[1] = country->iso_name[1]; 435 } else { 436 rtlpriv->regd.alpha2[0] = '0'; 437 rtlpriv->regd.alpha2[1] = '0'; 438 } 439 440 RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, 441 (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n", 442 rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1])); 443 444 _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); 445 446 return 0; 447} 448 449int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) 450{ 451 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 452 struct rtl_priv *rtlpriv = rtl_priv(hw); 453 454 RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, ("\n")); 455 456 return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); 457} 458