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