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