regd.c revision 25985edcedea6396277003854657b5f3cb31a628
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 69static const struct ieee80211_regdomain rtl_regdom_11 = { 70 .n_reg_rules = 1, 71 .alpha2 = "99", 72 .reg_rules = { 73 RTL819x_2GHZ_CH01_11, 74 } 75}; 76 77static const struct ieee80211_regdomain rtl_regdom_global = { 78 .n_reg_rules = 3, 79 .alpha2 = "99", 80 .reg_rules = { 81 RTL819x_2GHZ_CH01_11, 82 RTL819x_2GHZ_CH12_13, 83 RTL819x_2GHZ_CH14, 84 } 85}; 86 87static const struct ieee80211_regdomain rtl_regdom_world = { 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 bool _rtl_is_radar_freq(u16 center_freq) 97{ 98 return (center_freq >= 5260 && center_freq <= 5700); 99} 100 101static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, 102 enum nl80211_reg_initiator initiator) 103{ 104 enum ieee80211_band band; 105 struct ieee80211_supported_band *sband; 106 const struct ieee80211_reg_rule *reg_rule; 107 struct ieee80211_channel *ch; 108 unsigned int i; 109 u32 bandwidth = 0; 110 int r; 111 112 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 113 114 if (!wiphy->bands[band]) 115 continue; 116 117 sband = wiphy->bands[band]; 118 119 for (i = 0; i < sband->n_channels; i++) { 120 ch = &sband->channels[i]; 121 if (_rtl_is_radar_freq(ch->center_freq) || 122 (ch->flags & IEEE80211_CHAN_RADAR)) 123 continue; 124 if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { 125 r = freq_reg_info(wiphy, ch->center_freq, 126 bandwidth, ®_rule); 127 if (r) 128 continue; 129 130 /* 131 *If 11d had a rule for this channel ensure 132 *we enable adhoc/beaconing if it allows us to 133 *use it. Note that we would have disabled it 134 *by applying our static world regdomain by 135 *default during init, prior to calling our 136 *regulatory_hint(). 137 */ 138 139 if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) 140 ch->flags &= ~IEEE80211_CHAN_NO_IBSS; 141 if (!(reg_rule-> 142 flags & NL80211_RRF_PASSIVE_SCAN)) 143 ch->flags &= 144 ~IEEE80211_CHAN_PASSIVE_SCAN; 145 } else { 146 if (ch->beacon_found) 147 ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | 148 IEEE80211_CHAN_PASSIVE_SCAN); 149 } 150 } 151 } 152} 153 154/* Allows active scan scan on Ch 12 and 13 */ 155static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, 156 enum nl80211_reg_initiator 157 initiator) 158{ 159 struct ieee80211_supported_band *sband; 160 struct ieee80211_channel *ch; 161 const struct ieee80211_reg_rule *reg_rule; 162 u32 bandwidth = 0; 163 int r; 164 165 sband = wiphy->bands[IEEE80211_BAND_2GHZ]; 166 167 /* 168 *If no country IE has been received always enable active scan 169 *on these channels. This is only done for specific regulatory SKUs 170 */ 171 if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { 172 ch = &sband->channels[11]; /* CH 12 */ 173 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 174 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 175 ch = &sband->channels[12]; /* CH 13 */ 176 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 177 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 178 return; 179 } 180 181 /* 182 *If a country IE has been received check its rule for this 183 *channel first before enabling active scan. The passive scan 184 *would have been enforced by the initial processing of our 185 *custom regulatory domain. 186 */ 187 188 ch = &sband->channels[11]; /* CH 12 */ 189 r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); 190 if (!r) { 191 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) 192 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 193 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 194 } 195 196 ch = &sband->channels[12]; /* CH 13 */ 197 r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); 198 if (!r) { 199 if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) 200 if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) 201 ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; 202 } 203} 204 205/* 206 *Always apply Radar/DFS rules on 207 *freq range 5260 MHz - 5700 MHz 208 */ 209static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) 210{ 211 struct ieee80211_supported_band *sband; 212 struct ieee80211_channel *ch; 213 unsigned int i; 214 215 if (!wiphy->bands[IEEE80211_BAND_5GHZ]) 216 return; 217 218 sband = wiphy->bands[IEEE80211_BAND_5GHZ]; 219 220 for (i = 0; i < sband->n_channels; i++) { 221 ch = &sband->channels[i]; 222 if (!_rtl_is_radar_freq(ch->center_freq)) 223 continue; 224 225 /* 226 *We always enable radar detection/DFS on this 227 *frequency range. Additionally we also apply on 228 *this frequency range: 229 *- If STA mode does not yet have DFS supports disable 230 * active scanning 231 *- If adhoc mode does not support DFS yet then disable 232 * adhoc in the frequency. 233 *- If AP mode does not yet support radar detection/DFS 234 *do not allow AP mode 235 */ 236 if (!(ch->flags & IEEE80211_CHAN_DISABLED)) 237 ch->flags |= IEEE80211_CHAN_RADAR | 238 IEEE80211_CHAN_NO_IBSS | 239 IEEE80211_CHAN_PASSIVE_SCAN; 240 } 241} 242 243static void _rtl_reg_apply_world_flags(struct wiphy *wiphy, 244 enum nl80211_reg_initiator initiator, 245 struct rtl_regulatory *reg) 246{ 247 _rtl_reg_apply_beaconing_flags(wiphy, initiator); 248 _rtl_reg_apply_active_scan_flags(wiphy, initiator); 249 return; 250} 251 252static void _rtl_dump_channel_map(struct wiphy *wiphy) 253{ 254 enum ieee80211_band band; 255 struct ieee80211_supported_band *sband; 256 struct ieee80211_channel *ch; 257 unsigned int i; 258 259 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 260 if (!wiphy->bands[band]) 261 continue; 262 sband = wiphy->bands[band]; 263 for (i = 0; i < sband->n_channels; i++) 264 ch = &sband->channels[i]; 265 } 266} 267 268static int _rtl_reg_notifier_apply(struct wiphy *wiphy, 269 struct regulatory_request *request, 270 struct rtl_regulatory *reg) 271{ 272 /* We always apply this */ 273 _rtl_reg_apply_radar_flags(wiphy); 274 275 switch (request->initiator) { 276 case NL80211_REGDOM_SET_BY_DRIVER: 277 case NL80211_REGDOM_SET_BY_CORE: 278 case NL80211_REGDOM_SET_BY_USER: 279 break; 280 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 281 _rtl_reg_apply_world_flags(wiphy, request->initiator, reg); 282 break; 283 } 284 285 _rtl_dump_channel_map(wiphy); 286 287 return 0; 288} 289 290static const struct ieee80211_regdomain *_rtl_regdomain_select( 291 struct rtl_regulatory *reg) 292{ 293 switch (reg->country_code) { 294 case COUNTRY_CODE_FCC: 295 case COUNTRY_CODE_IC: 296 return &rtl_regdom_11; 297 case COUNTRY_CODE_ETSI: 298 case COUNTRY_CODE_SPAIN: 299 case COUNTRY_CODE_FRANCE: 300 case COUNTRY_CODE_ISRAEL: 301 case COUNTRY_CODE_TELEC_NETGEAR: 302 return &rtl_regdom_world; 303 case COUNTRY_CODE_MKK: 304 case COUNTRY_CODE_MKK1: 305 case COUNTRY_CODE_TELEC: 306 case COUNTRY_CODE_MIC: 307 return &rtl_regdom_global; 308 case COUNTRY_CODE_GLOBAL_DOMAIN: 309 return &rtl_regdom_global; 310 case COUNTRY_CODE_WORLD_WIDE_13: 311 return &rtl_regdom_world; 312 default: 313 return &rtl_regdom_world; 314 } 315} 316 317static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, 318 struct wiphy *wiphy, 319 int (*reg_notifier) (struct wiphy *wiphy, 320 struct regulatory_request * 321 request)) 322{ 323 const struct ieee80211_regdomain *regd; 324 325 wiphy->reg_notifier = reg_notifier; 326 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; 327 wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; 328 wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; 329 regd = _rtl_regdomain_select(reg); 330 wiphy_apply_custom_regulatory(wiphy, regd); 331 _rtl_reg_apply_radar_flags(wiphy); 332 _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); 333 return 0; 334} 335 336static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode) 337{ 338 int i; 339 340 for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 341 if (allCountries[i].countrycode == countrycode) 342 return &allCountries[i]; 343 } 344 return NULL; 345} 346 347int rtl_regd_init(struct ieee80211_hw *hw, 348 int (*reg_notifier) (struct wiphy *wiphy, 349 struct regulatory_request *request)) 350{ 351 struct rtl_priv *rtlpriv = rtl_priv(hw); 352 struct wiphy *wiphy = hw->wiphy; 353 struct country_code_to_enum_rd *country = NULL; 354 355 if (wiphy == NULL || &rtlpriv->regd == NULL) 356 return -EINVAL; 357 358 /* force the channel plan to world wide 13 */ 359 rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; 360 361 RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, 362 (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", 363 rtlpriv->regd.country_code)); 364 365 if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { 366 RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG, 367 (KERN_DEBUG "rtl: EEPROM indicates invalid contry code" 368 "world wide 13 should be used\n")); 369 370 rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; 371 } 372 373 country = _rtl_regd_find_country(rtlpriv->regd.country_code); 374 375 if (country) { 376 rtlpriv->regd.alpha2[0] = country->isoName[0]; 377 rtlpriv->regd.alpha2[1] = country->isoName[1]; 378 } else { 379 rtlpriv->regd.alpha2[0] = '0'; 380 rtlpriv->regd.alpha2[1] = '0'; 381 } 382 383 RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, 384 (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n", 385 rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1])); 386 387 _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); 388 389 return 0; 390} 391 392int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) 393{ 394 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 395 struct rtl_priv *rtlpriv = rtl_priv(hw); 396 397 RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, ("\n")); 398 399 return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); 400} 401