regd.c 13.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (c) 2008 Atheros Communications Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <linux/kernel.h>
#include <linux/slab.h>
S
Sujith 已提交
19
#include "ath9k.h"
20 21
#include "regd_common.h"

22 23 24 25 26 27
/*
 * This is a set of common rules used by our world regulatory domains.
 * We have 12 world regulatory domains. To save space we consolidate
 * the regulatory domains in 5 structures by frequency and change
 * the flags on our reg_notifier() on a case by case basis.
 */
28

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/* Only these channels all allow active scan on all world regulatory domains */
#define ATH9K_2GHZ_CH01_11	REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)

/* We enable active scan on these a case by case basis by regulatory domain */
#define ATH9K_2GHZ_CH12_13	REG_RULE(2467-10, 2472+10, 40, 0, 20,\
					NL80211_RRF_PASSIVE_SCAN)
#define ATH9K_2GHZ_CH14		REG_RULE(2484-10, 2484+10, 40, 0, 20,\
				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)

/* We allow IBSS on these on a case by case basis by regulatory domain */
#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 40, 0, 30,\
				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
#define ATH9K_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 40, 0, 30,\
				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
#define ATH9K_5GHZ_5725_5850	REG_RULE(5725-10, 5850+10, 40, 0, 30,\
				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)

#define ATH9K_2GHZ_ALL		ATH9K_2GHZ_CH01_11, \
				ATH9K_2GHZ_CH12_13, \
				ATH9K_2GHZ_CH14

#define ATH9K_5GHZ_ALL		ATH9K_5GHZ_5150_5350, \
				ATH9K_5GHZ_5470_5850
/* This one skips what we call "mid band" */
#define ATH9K_5GHZ_NO_MIDBAND	ATH9K_5GHZ_5150_5350, \
				ATH9K_5GHZ_5725_5850

/* Can be used for:
 * 0x60, 0x61, 0x62 */
static const struct ieee80211_regdomain ath9k_world_regdom_60_61_62 = {
	.n_reg_rules = 5,
	.alpha2 =  "99",
	.reg_rules = {
		ATH9K_2GHZ_ALL,
		ATH9K_5GHZ_ALL,
	}
};

/* Can be used by 0x63 and 0x65 */
static const struct ieee80211_regdomain ath9k_world_regdom_63_65 = {
	.n_reg_rules = 4,
	.alpha2 =  "99",
	.reg_rules = {
		ATH9K_2GHZ_CH01_11,
		ATH9K_2GHZ_CH12_13,
		ATH9K_5GHZ_NO_MIDBAND,
	}
};

/* Can be used by 0x64 only */
static const struct ieee80211_regdomain ath9k_world_regdom_64 = {
	.n_reg_rules = 3,
	.alpha2 =  "99",
	.reg_rules = {
		ATH9K_2GHZ_CH01_11,
		ATH9K_5GHZ_NO_MIDBAND,
	}
};

/* Can be used by 0x66 and 0x69 */
static const struct ieee80211_regdomain ath9k_world_regdom_66_69 = {
	.n_reg_rules = 3,
	.alpha2 =  "99",
	.reg_rules = {
		ATH9K_2GHZ_CH01_11,
		ATH9K_5GHZ_ALL,
	}
};

/* Can be used by 0x67, 0x6A and 0x68 */
static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
	.n_reg_rules = 4,
	.alpha2 =  "99",
	.reg_rules = {
		ATH9K_2GHZ_CH01_11,
		ATH9K_2GHZ_CH12_13,
		ATH9K_5GHZ_ALL,
	}
};
108

109 110 111 112 113 114
static inline bool is_wwr_sku(u16 regd)
{
	return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
		(regd == WORLD);
}

115
static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
116
{
117
	return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
118 119
}

120
bool ath9k_is_world_regd(struct ath_hw *ah)
121
{
122
	return is_wwr_sku(ath9k_regd_get_eepromRD(ah));
123 124
}

125
const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
126
{
127 128 129
	/* this is the most restrictive */
	return &ath9k_world_regdom_64;
}
130

131
const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah)
132
{
133
	switch (ah->regulatory.regpair->regDmnEnum) {
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	case 0x60:
	case 0x61:
	case 0x62:
		return &ath9k_world_regdom_60_61_62;
	case 0x63:
	case 0x65:
		return &ath9k_world_regdom_63_65;
	case 0x64:
		return &ath9k_world_regdom_64;
	case 0x66:
	case 0x69:
		return &ath9k_world_regdom_66_69;
	case 0x67:
	case 0x68:
	case 0x6A:
		return &ath9k_world_regdom_67_68_6A;
	default:
		WARN_ON(1);
		return ath9k_default_world_regdomain();
153 154 155
	}
}

156 157 158 159 160 161
/* Frequency is one where radar detection is required */
static bool ath9k_is_radar_freq(u16 center_freq)
{
	return (center_freq >= 5260 && center_freq <= 5700);
}

162
/*
163 164 165 166 167 168 169
 * N.B: These exception rules do not apply radar freqs.
 *
 * - We enable adhoc (or beaconing) if allowed by 11d
 * - We enable active scan if the channel is allowed by 11d
 * - If no country IE has been processed and a we determine we have
 *   received a beacon on a channel we can enable active scan and
 *   adhoc (or beaconing).
170
 */
171
static void ath9k_reg_apply_beaconing_flags(struct wiphy *wiphy,
172
					     enum reg_set_by setby)
173
{
174
	enum ieee80211_band band;
175 176 177 178 179 180 181
	struct ieee80211_supported_band *sband;
	const struct ieee80211_reg_rule *reg_rule;
	struct ieee80211_channel *ch;
	unsigned int i;
	u32 bandwidth = 0;
	int r;

182
	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
183

184
		if (!wiphy->bands[band])
185
			continue;
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

		sband = wiphy->bands[band];

		for (i = 0; i < sband->n_channels; i++) {

			ch = &sband->channels[i];

			if (ath9k_is_radar_freq(ch->center_freq) ||
			    (ch->flags & IEEE80211_CHAN_RADAR))
				continue;

			if (setby == REGDOM_SET_BY_COUNTRY_IE) {
				r = freq_reg_info(wiphy, ch->center_freq,
					&bandwidth, &reg_rule);
				if (r)
					continue;
				/*
				 * If 11d had a rule for this channel ensure
				 * we enable adhoc/beaconing if it allows us to
				 * use it. Note that we would have disabled it
				 * by applying our static world regdomain by
				 * default during init, prior to calling our
				 * regulatory_hint().
				 */
				if (!(reg_rule->flags &
				    NL80211_RRF_NO_IBSS))
					ch->flags &=
					  ~IEEE80211_CHAN_NO_IBSS;
				if (!(reg_rule->flags &
				    NL80211_RRF_PASSIVE_SCAN))
					ch->flags &=
					  ~IEEE80211_CHAN_PASSIVE_SCAN;
			} else {
				if (ch->beacon_found)
					ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
					  IEEE80211_CHAN_PASSIVE_SCAN);
			}
		}
224
	}
225

226 227
}

228 229 230
/* Allows active scan scan on Ch 12 and 13 */
static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
					      enum reg_set_by setby)
231
{
232 233 234 235 236 237 238 239
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *ch;
	const struct ieee80211_reg_rule *reg_rule;
	u32 bandwidth = 0;
	int r;

	sband = wiphy->bands[IEEE80211_BAND_2GHZ];

240 241 242 243
	/*
	 * If no country IE has been received always enable active scan
	 * on these channels. This is only done for specific regulatory SKUs
	 */
244 245 246 247 248 249 250 251 252
	if (setby != REGDOM_SET_BY_COUNTRY_IE) {
		ch = &sband->channels[11]; /* CH 12 */
		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
		ch = &sband->channels[12]; /* CH 13 */
		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
		return;
	}
253

254 255
	/*
	 * If a country IE has been recieved check its rule for this
256
	 * channel first before enabling active scan. The passive scan
257 258 259
	 * would have been enforced by the initial processing of our
	 * custom regulatory domain.
	 */
260

261 262 263 264 265 266
	ch = &sband->channels[11]; /* CH 12 */
	r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
	if (!r) {
		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
267 268
	}

269 270 271 272 273 274
	ch = &sband->channels[12]; /* CH 13 */
	r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
	if (!r) {
		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
275 276 277
	}
}

278 279
/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
280
{
281 282 283
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *ch;
	unsigned int i;
284

285 286
	if (!wiphy->bands[IEEE80211_BAND_5GHZ])
		return;
287

288
	sband = wiphy->bands[IEEE80211_BAND_5GHZ];
289

290 291
	for (i = 0; i < sband->n_channels; i++) {
		ch = &sband->channels[i];
292
		if (!ath9k_is_radar_freq(ch->center_freq))
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
			continue;
		/* We always enable radar detection/DFS on this
		 * frequency range. Additionally we also apply on
		 * this frequency range:
		 * - If STA mode does not yet have DFS supports disable
		 *   active scanning
		 * - If adhoc mode does not support DFS yet then
		 *   disable adhoc in the frequency.
		 * - If AP mode does not yet support radar detection/DFS
		 *   do not allow AP mode
		 */
		if (!(ch->flags & IEEE80211_CHAN_DISABLED))
			ch->flags |= IEEE80211_CHAN_RADAR |
				     IEEE80211_CHAN_NO_IBSS |
				     IEEE80211_CHAN_PASSIVE_SCAN;
	}
}
310

311 312 313
void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
{
	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
314 315
	struct ath_wiphy *aphy = hw->priv;
	struct ath_softc *sc = aphy->sc;
316
	struct ath_hw *ah = sc->sc_ah;
317

318
	switch (ah->regulatory.regpair->regDmnEnum) {
319 320 321 322
	case 0x60:
	case 0x63:
	case 0x66:
	case 0x67:
323
		ath9k_reg_apply_beaconing_flags(wiphy, setby);
324 325
		break;
	case 0x68:
326
		ath9k_reg_apply_beaconing_flags(wiphy, setby);
327 328 329 330 331
		ath9k_reg_apply_active_scan_flags(wiphy, setby);
		break;
	}
	return;
}
332

333 334 335
int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
{
	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
336 337
	struct ath_wiphy *aphy = hw->priv;
	struct ath_softc *sc = aphy->sc;
338

339 340
	/* We always apply this */
	ath9k_reg_apply_radar_flags(wiphy);
341

342 343 344 345 346 347 348 349 350 351
	switch (request->initiator) {
	case REGDOM_SET_BY_DRIVER:
	case REGDOM_SET_BY_CORE:
	case REGDOM_SET_BY_USER:
		break;
	case REGDOM_SET_BY_COUNTRY_IE:
		if (ath9k_is_world_regd(sc->sc_ah))
			ath9k_reg_apply_world_flags(wiphy, request->initiator);
		break;
	}
352

353
	return 0;
354 355
}

356
bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah)
357
{
358 359
	u16 rd = ath9k_regd_get_eepromRD(ah);
	int i;
360

361 362 363 364 365 366 367 368 369 370 371
	if (rd & COUNTRY_ERD_FLAG) {
		/* EEPROM value is a country code */
		u16 cc = rd & ~COUNTRY_ERD_FLAG;
		for (i = 0; i < ARRAY_SIZE(allCountries); i++)
			if (allCountries[i].countryCode == cc)
				return true;
	} else {
		/* EEPROM value is a regpair value */
		for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
			if (regDomainPairs[i].regDmnEnum == rd)
				return true;
372
	}
373 374
	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
		 "invalid regulatory domain/country code 0x%x\n", rd);
375 376 377
	return false;
}

378
/* EEPROM country code to regpair mapping */
379 380 381 382 383 384 385 386 387 388 389 390
static struct country_code_to_enum_rd*
ath9k_regd_find_country(u16 countryCode)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
		if (allCountries[i].countryCode == countryCode)
			return &allCountries[i];
	}
	return NULL;
}

391 392 393 394 395 396 397 398 399 400 401 402 403 404
/* EEPROM rd code to regpair mapping */
static struct country_code_to_enum_rd*
ath9k_regd_find_country_by_rd(int regdmn)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
		if (allCountries[i].regDmnEnum == regdmn)
			return &allCountries[i];
	}
	return NULL;
}

/* Returns the map of the EEPROM set RD to a country code */
405
static u16 ath9k_regd_get_default_country(u16 rd)
406 407 408 409 410 411 412 413 414 415 416 417 418
{
	if (rd & COUNTRY_ERD_FLAG) {
		struct country_code_to_enum_rd *country = NULL;
		u16 cc = rd & ~COUNTRY_ERD_FLAG;

		country = ath9k_regd_find_country(cc);
		if (country != NULL)
			return cc;
	}

	return CTRY_DEFAULT;
}

419 420
static struct reg_dmn_pair_mapping*
ath9k_get_regpair(int regdmn)
421 422 423
{
	int i;

424 425
	if (regdmn == NO_ENUMRD)
		return NULL;
426
	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
427 428
		if (regDomainPairs[i].regDmnEnum == regdmn)
			return &regDomainPairs[i];
429
	}
430
	return NULL;
431 432
}

433
int ath9k_regd_init(struct ath_hw *ah)
434 435
{
	struct country_code_to_enum_rd *country = NULL;
436
	u16 regdmn;
437 438 439

	if (!ath9k_regd_is_eeprom_valid(ah)) {
		DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
S
Sujith 已提交
440
			"Invalid EEPROM contents\n");
441
		return -EINVAL;
442 443
	}

444 445
	regdmn = ath9k_regd_get_eepromRD(ah);
	ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);
446

447
	if (ah->regulatory.country_code == CTRY_DEFAULT &&
448
	    regdmn == CTRY_DEFAULT)
449
		ah->regulatory.country_code = CTRY_UNITED_STATES;
450

451
	if (ah->regulatory.country_code == CTRY_DEFAULT) {
452 453
		country = NULL;
	} else {
454
		country = ath9k_regd_find_country(ah->regulatory.country_code);
455 456 457
		if (country == NULL) {
			DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
				"Country is NULL!!!!, cc= %d\n",
458
				ah->regulatory.country_code);
459 460
			return -EINVAL;
		} else
461 462 463
			regdmn = country->regDmnEnum;
	}

464
	ah->regulatory.regpair = ath9k_get_regpair(regdmn);
465

466
	if (!ah->regulatory.regpair) {
467 468 469
		DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
			"No regulatory domain pair found, cannot continue\n");
		return -EINVAL;
470 471
	}

472 473
	if (!country)
		country = ath9k_regd_find_country_by_rd(regdmn);
474

475
	if (country) {
476 477
		ah->regulatory.alpha2[0] = country->isoName[0];
		ah->regulatory.alpha2[1] = country->isoName[1];
478
	} else {
479 480
		ah->regulatory.alpha2[0] = '0';
		ah->regulatory.alpha2[1] = '0';
481 482 483
	}

	DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
484
		"Country alpha2 being used: %c%c\n"
485 486 487
		"Regulatory.Regpair detected: 0x%0x\n",
		ah->regulatory.alpha2[0], ah->regulatory.alpha2[1],
		ah->regulatory.regpair->regDmnEnum);
488

489
	return 0;
490 491
}

492
u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
493 494 495
{
	u32 ctl = NO_CTL;

496
	if (!ah->regulatory.regpair ||
497 498
	    (ah->regulatory.country_code == CTRY_DEFAULT &&
	     is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {
499 500 501 502 503 504
		if (IS_CHAN_B(chan))
			ctl = SD_NO_CTL | CTL_11B;
		else if (IS_CHAN_G(chan))
			ctl = SD_NO_CTL | CTL_11G;
		else
			ctl = SD_NO_CTL | CTL_11A;
505
		return ctl;
506 507
	}

508
	if (IS_CHAN_B(chan))
509
		ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
510
	else if (IS_CHAN_G(chan))
511
		ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;
512
	else
513
		ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
514

515
	return ctl;
516
}