xref: /openbmc/linux/drivers/net/wireless/ath/regd.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
13a702e49SBob Copeland /*
23a702e49SBob Copeland  * Copyright (c) 2008-2009 Atheros Communications Inc.
33a702e49SBob Copeland  *
43a702e49SBob Copeland  * Permission to use, copy, modify, and/or distribute this software for any
53a702e49SBob Copeland  * purpose with or without fee is hereby granted, provided that the above
63a702e49SBob Copeland  * copyright notice and this permission notice appear in all copies.
73a702e49SBob Copeland  *
83a702e49SBob Copeland  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
93a702e49SBob Copeland  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
103a702e49SBob Copeland  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
113a702e49SBob Copeland  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
123a702e49SBob Copeland  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
133a702e49SBob Copeland  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
143a702e49SBob Copeland  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
153a702e49SBob Copeland  */
163a702e49SBob Copeland 
17516304b0SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18516304b0SJoe Perches 
193a702e49SBob Copeland #include <linux/kernel.h>
20ee40fa06SPaul Gortmaker #include <linux/export.h>
213a702e49SBob Copeland #include <net/cfg80211.h>
223a702e49SBob Copeland #include <net/mac80211.h>
233a702e49SBob Copeland #include "regd.h"
243a702e49SBob Copeland #include "regd_common.h"
253a702e49SBob Copeland 
26de1c732bSLuis R. Rodriguez static int __ath_regd_init(struct ath_regulatory *reg);
27de1c732bSLuis R. Rodriguez 
283a702e49SBob Copeland /*
293a702e49SBob Copeland  * This is a set of common rules used by our world regulatory domains.
303a702e49SBob Copeland  * We have 12 world regulatory domains. To save space we consolidate
313a702e49SBob Copeland  * the regulatory domains in 5 structures by frequency and change
323a702e49SBob Copeland  * the flags on our reg_notifier() on a case by case basis.
333a702e49SBob Copeland  */
343a702e49SBob Copeland 
353a702e49SBob Copeland /* Only these channels all allow active scan on all world regulatory domains */
36f433abfcSTomislav Požega #define ATH_2GHZ_CH01_11	REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
373a702e49SBob Copeland 
383a702e49SBob Copeland /* We enable active scan on these a case by case basis by regulatory domain */
39f433abfcSTomislav Požega #define ATH_2GHZ_CH12_13	REG_RULE(2467-10, 2472+10, 40, 0, 20,\
408fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_IR)
41f433abfcSTomislav Požega #define ATH_2GHZ_CH14		REG_RULE(2484-10, 2484+10, 40, 0, 20,\
428fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_IR | \
438fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_OFDM)
443a702e49SBob Copeland 
453a702e49SBob Copeland /* We allow IBSS on these on a case by case basis by regulatory domain */
46f433abfcSTomislav Požega #define ATH_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 80, 0, 30,\
478fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_IR)
48f433abfcSTomislav Požega #define ATH_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 80, 0, 30,\
498fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_IR)
50f433abfcSTomislav Požega #define ATH_5GHZ_5725_5850	REG_RULE(5725-10, 5850+10, 80, 0, 30,\
518fe02e16SLuis R. Rodriguez 					 NL80211_RRF_NO_IR)
523a702e49SBob Copeland 
53f433abfcSTomislav Požega #define ATH_2GHZ_ALL		ATH_2GHZ_CH01_11, \
54f433abfcSTomislav Požega 				ATH_2GHZ_CH12_13, \
55f433abfcSTomislav Požega 				ATH_2GHZ_CH14
563a702e49SBob Copeland 
57f433abfcSTomislav Požega #define ATH_5GHZ_ALL		ATH_5GHZ_5150_5350, \
58f433abfcSTomislav Požega 				ATH_5GHZ_5470_5850
59cfcfe446SLuis de Bethencourt 
603a702e49SBob Copeland /* This one skips what we call "mid band" */
61f433abfcSTomislav Požega #define ATH_5GHZ_NO_MIDBAND	ATH_5GHZ_5150_5350, \
62f433abfcSTomislav Požega 				ATH_5GHZ_5725_5850
633a702e49SBob Copeland 
643a702e49SBob Copeland /* Can be used for:
653a702e49SBob Copeland  * 0x60, 0x61, 0x62 */
663a702e49SBob Copeland static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
673a702e49SBob Copeland 	.n_reg_rules = 5,
683a702e49SBob Copeland 	.alpha2 =  "99",
693a702e49SBob Copeland 	.reg_rules = {
70f433abfcSTomislav Požega 		ATH_2GHZ_ALL,
71f433abfcSTomislav Požega 		ATH_5GHZ_ALL,
723a702e49SBob Copeland 	}
733a702e49SBob Copeland };
743a702e49SBob Copeland 
753a702e49SBob Copeland /* Can be used by 0x63 and 0x65 */
763a702e49SBob Copeland static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
773a702e49SBob Copeland 	.n_reg_rules = 4,
783a702e49SBob Copeland 	.alpha2 =  "99",
793a702e49SBob Copeland 	.reg_rules = {
80f433abfcSTomislav Požega 		ATH_2GHZ_CH01_11,
81f433abfcSTomislav Požega 		ATH_2GHZ_CH12_13,
82f433abfcSTomislav Požega 		ATH_5GHZ_NO_MIDBAND,
833a702e49SBob Copeland 	}
843a702e49SBob Copeland };
853a702e49SBob Copeland 
863a702e49SBob Copeland /* Can be used by 0x64 only */
873a702e49SBob Copeland static const struct ieee80211_regdomain ath_world_regdom_64 = {
883a702e49SBob Copeland 	.n_reg_rules = 3,
893a702e49SBob Copeland 	.alpha2 =  "99",
903a702e49SBob Copeland 	.reg_rules = {
91f433abfcSTomislav Požega 		ATH_2GHZ_CH01_11,
92f433abfcSTomislav Požega 		ATH_5GHZ_NO_MIDBAND,
933a702e49SBob Copeland 	}
943a702e49SBob Copeland };
953a702e49SBob Copeland 
963a702e49SBob Copeland /* Can be used by 0x66 and 0x69 */
973a702e49SBob Copeland static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
983a702e49SBob Copeland 	.n_reg_rules = 3,
993a702e49SBob Copeland 	.alpha2 =  "99",
1003a702e49SBob Copeland 	.reg_rules = {
101f433abfcSTomislav Požega 		ATH_2GHZ_CH01_11,
102f433abfcSTomislav Požega 		ATH_5GHZ_ALL,
1033a702e49SBob Copeland 	}
1043a702e49SBob Copeland };
1053a702e49SBob Copeland 
10634a0a202SSenthil Balasubramanian /* Can be used by 0x67, 0x68, 0x6A and 0x6C */
10734a0a202SSenthil Balasubramanian static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
1083a702e49SBob Copeland 	.n_reg_rules = 4,
1093a702e49SBob Copeland 	.alpha2 =  "99",
1103a702e49SBob Copeland 	.reg_rules = {
111f433abfcSTomislav Požega 		ATH_2GHZ_CH01_11,
112f433abfcSTomislav Požega 		ATH_2GHZ_CH12_13,
113f433abfcSTomislav Požega 		ATH_5GHZ_ALL,
1143a702e49SBob Copeland 	}
1153a702e49SBob Copeland };
1163a702e49SBob Copeland 
dynamic_country_user_possible(struct ath_regulatory * reg)117a44ea6ffSLuis R. Rodriguez static bool dynamic_country_user_possible(struct ath_regulatory *reg)
118a44ea6ffSLuis R. Rodriguez {
11997f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
120a44ea6ffSLuis R. Rodriguez 		return true;
121a44ea6ffSLuis R. Rodriguez 
122a44ea6ffSLuis R. Rodriguez 	switch (reg->country_code) {
123a44ea6ffSLuis R. Rodriguez 	case CTRY_UNITED_STATES:
124a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN1:
125a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN2:
126a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN3:
127a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN4:
128a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN5:
129a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN6:
130a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN7:
131a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN8:
132a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN9:
133a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN10:
134a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN11:
135a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN12:
136a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN13:
137a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN14:
138a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN15:
139a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN16:
140a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN17:
141a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN18:
142a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN19:
143a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN20:
144a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN21:
145a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN22:
146a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN23:
147a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN24:
148a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN25:
149a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN26:
150a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN27:
151a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN28:
152a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN29:
153a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN30:
154a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN31:
155a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN32:
156a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN33:
157a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN34:
158a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN35:
159a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN36:
160a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN37:
161a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN38:
162a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN39:
163a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN40:
164a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN41:
165a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN42:
166a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN43:
167a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN44:
168a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN45:
169a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN46:
170a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN47:
171a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN48:
172a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN49:
173a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN50:
174a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN51:
175a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN52:
176a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN53:
177a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN54:
178a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN55:
179a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN56:
180a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN57:
181a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN58:
182a44ea6ffSLuis R. Rodriguez 	case CTRY_JAPAN59:
183a44ea6ffSLuis R. Rodriguez 		return false;
184a44ea6ffSLuis R. Rodriguez 	}
185a44ea6ffSLuis R. Rodriguez 
186a44ea6ffSLuis R. Rodriguez 	return true;
187a44ea6ffSLuis R. Rodriguez }
188a44ea6ffSLuis R. Rodriguez 
ath_reg_dyn_country_user_allow(struct ath_regulatory * reg)189ba94c049SLuis R. Rodriguez static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
190ba94c049SLuis R. Rodriguez {
19197f2645fSMasahiro Yamada 	if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
192ba94c049SLuis R. Rodriguez 		return false;
193ba94c049SLuis R. Rodriguez 	if (!dynamic_country_user_possible(reg))
194ba94c049SLuis R. Rodriguez 		return false;
195ba94c049SLuis R. Rodriguez 	return true;
196ba94c049SLuis R. Rodriguez }
197ba94c049SLuis R. Rodriguez 
is_wwr_sku(u16 regd)1983a702e49SBob Copeland static inline bool is_wwr_sku(u16 regd)
1993a702e49SBob Copeland {
200641eabb0SChristian Lamparter 	return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
201641eabb0SChristian Lamparter 		(((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
202641eabb0SChristian Lamparter 		(regd == WORLD));
2033a702e49SBob Copeland }
2043a702e49SBob Copeland 
ath_regd_get_eepromRD(struct ath_regulatory * reg)2053a702e49SBob Copeland static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
2063a702e49SBob Copeland {
2073a702e49SBob Copeland 	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
2083a702e49SBob Copeland }
2093a702e49SBob Copeland 
ath_is_world_regd(struct ath_regulatory * reg)2103a702e49SBob Copeland bool ath_is_world_regd(struct ath_regulatory *reg)
2113a702e49SBob Copeland {
2123a702e49SBob Copeland 	return is_wwr_sku(ath_regd_get_eepromRD(reg));
2133a702e49SBob Copeland }
2143a702e49SBob Copeland EXPORT_SYMBOL(ath_is_world_regd);
2153a702e49SBob Copeland 
ath_default_world_regdomain(void)216e3bb249bSBob Copeland static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
2173a702e49SBob Copeland {
2183a702e49SBob Copeland 	/* this is the most restrictive */
2193a702e49SBob Copeland 	return &ath_world_regdom_64;
2203a702e49SBob Copeland }
2213a702e49SBob Copeland 
222e3bb249bSBob Copeland static const struct
ath_world_regdomain(struct ath_regulatory * reg)2233a702e49SBob Copeland ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
2243a702e49SBob Copeland {
225ef8c0017SKalle Valo 	switch (reg->regpair->reg_domain) {
2263a702e49SBob Copeland 	case 0x60:
2273a702e49SBob Copeland 	case 0x61:
2283a702e49SBob Copeland 	case 0x62:
2293a702e49SBob Copeland 		return &ath_world_regdom_60_61_62;
2303a702e49SBob Copeland 	case 0x63:
2313a702e49SBob Copeland 	case 0x65:
2323a702e49SBob Copeland 		return &ath_world_regdom_63_65;
2333a702e49SBob Copeland 	case 0x64:
2343a702e49SBob Copeland 		return &ath_world_regdom_64;
2353a702e49SBob Copeland 	case 0x66:
2363a702e49SBob Copeland 	case 0x69:
2373a702e49SBob Copeland 		return &ath_world_regdom_66_69;
2383a702e49SBob Copeland 	case 0x67:
2393a702e49SBob Copeland 	case 0x68:
2403a702e49SBob Copeland 	case 0x6A:
24134a0a202SSenthil Balasubramanian 	case 0x6C:
24234a0a202SSenthil Balasubramanian 		return &ath_world_regdom_67_68_6A_6C;
2433a702e49SBob Copeland 	default:
2443a702e49SBob Copeland 		WARN_ON(1);
2453a702e49SBob Copeland 		return ath_default_world_regdomain();
2463a702e49SBob Copeland 	}
2473a702e49SBob Copeland }
2483a702e49SBob Copeland 
ath_is_49ghz_allowed(u16 regdomain)2495719efddSBruno Randolf bool ath_is_49ghz_allowed(u16 regdomain)
2505719efddSBruno Randolf {
2515719efddSBruno Randolf 	/* possibly more */
2525719efddSBruno Randolf 	return regdomain == MKK9_MKKC;
2535719efddSBruno Randolf }
2545719efddSBruno Randolf EXPORT_SYMBOL(ath_is_49ghz_allowed);
2555719efddSBruno Randolf 
2563a702e49SBob Copeland /* Frequency is one where radar detection is required */
ath_is_radar_freq(u16 center_freq,struct ath_regulatory * reg)257c0c345d4SMohammed Shafi Shajakhan static bool ath_is_radar_freq(u16 center_freq,
258c0c345d4SMohammed Shafi Shajakhan 			      struct ath_regulatory *reg)
259c0c345d4SMohammed Shafi Shajakhan 
2603a702e49SBob Copeland {
261c0c345d4SMohammed Shafi Shajakhan 	if (reg->country_code == CTRY_INDIA)
262c0c345d4SMohammed Shafi Shajakhan 		return (center_freq >= 5500 && center_freq <= 5700);
2633a702e49SBob Copeland 	return (center_freq >= 5260 && center_freq <= 5700);
2643a702e49SBob Copeland }
2653a702e49SBob Copeland 
ath_force_clear_no_ir_chan(struct wiphy * wiphy,struct ieee80211_channel * ch)266bc0aa069SLuis R. Rodriguez static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
267bc0aa069SLuis R. Rodriguez 				       struct ieee80211_channel *ch)
268bc0aa069SLuis R. Rodriguez {
269bc0aa069SLuis R. Rodriguez 	const struct ieee80211_reg_rule *reg_rule;
270bc0aa069SLuis R. Rodriguez 
27162452a99SLuis R. Rodriguez 	reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
272bc0aa069SLuis R. Rodriguez 	if (IS_ERR(reg_rule))
273bc0aa069SLuis R. Rodriguez 		return;
274bc0aa069SLuis R. Rodriguez 
275bc0aa069SLuis R. Rodriguez 	if (!(reg_rule->flags & NL80211_RRF_NO_IR))
276bc0aa069SLuis R. Rodriguez 		if (ch->flags & IEEE80211_CHAN_NO_IR)
277bc0aa069SLuis R. Rodriguez 			ch->flags &= ~IEEE80211_CHAN_NO_IR;
278bc0aa069SLuis R. Rodriguez }
279bc0aa069SLuis R. Rodriguez 
ath_force_clear_no_ir_freq(struct wiphy * wiphy,u16 center_freq)280bc0aa069SLuis R. Rodriguez static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
281bc0aa069SLuis R. Rodriguez {
282bc0aa069SLuis R. Rodriguez 	struct ieee80211_channel *ch;
283bc0aa069SLuis R. Rodriguez 
284bc0aa069SLuis R. Rodriguez 	ch = ieee80211_get_channel(wiphy, center_freq);
285bc0aa069SLuis R. Rodriguez 	if (!ch)
286bc0aa069SLuis R. Rodriguez 		return;
287bc0aa069SLuis R. Rodriguez 
288bc0aa069SLuis R. Rodriguez 	ath_force_clear_no_ir_chan(wiphy, ch);
289bc0aa069SLuis R. Rodriguez }
290bc0aa069SLuis R. Rodriguez 
ath_force_no_ir_chan(struct ieee80211_channel * ch)291bc0aa069SLuis R. Rodriguez static void ath_force_no_ir_chan(struct ieee80211_channel *ch)
292bc0aa069SLuis R. Rodriguez {
293bc0aa069SLuis R. Rodriguez 	ch->flags |= IEEE80211_CHAN_NO_IR;
294bc0aa069SLuis R. Rodriguez }
295bc0aa069SLuis R. Rodriguez 
ath_force_no_ir_freq(struct wiphy * wiphy,u16 center_freq)296bc0aa069SLuis R. Rodriguez static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq)
297bc0aa069SLuis R. Rodriguez {
298bc0aa069SLuis R. Rodriguez 	struct ieee80211_channel *ch;
299bc0aa069SLuis R. Rodriguez 
300bc0aa069SLuis R. Rodriguez 	ch = ieee80211_get_channel(wiphy, center_freq);
301bc0aa069SLuis R. Rodriguez 	if (!ch)
302bc0aa069SLuis R. Rodriguez 		return;
303bc0aa069SLuis R. Rodriguez 
304bc0aa069SLuis R. Rodriguez 	ath_force_no_ir_chan(ch);
305bc0aa069SLuis R. Rodriguez }
306bc0aa069SLuis R. Rodriguez 
30707782d94SLuis R. Rodriguez static void
__ath_reg_apply_beaconing_flags(struct wiphy * wiphy,struct ath_regulatory * reg,enum nl80211_reg_initiator initiator,struct ieee80211_channel * ch)30807782d94SLuis R. Rodriguez __ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
309251c9ba1SLuis R. Rodriguez 				struct ath_regulatory *reg,
31007782d94SLuis R. Rodriguez 				enum nl80211_reg_initiator initiator,
31107782d94SLuis R. Rodriguez 				struct ieee80211_channel *ch)
31207782d94SLuis R. Rodriguez {
313c0c345d4SMohammed Shafi Shajakhan 	if (ath_is_radar_freq(ch->center_freq, reg) ||
31407782d94SLuis R. Rodriguez 	    (ch->flags & IEEE80211_CHAN_RADAR))
31507782d94SLuis R. Rodriguez 		return;
31607782d94SLuis R. Rodriguez 
31707782d94SLuis R. Rodriguez 	switch (initiator) {
31807782d94SLuis R. Rodriguez 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
31907782d94SLuis R. Rodriguez 		ath_force_clear_no_ir_chan(wiphy, ch);
32007782d94SLuis R. Rodriguez 		break;
321251c9ba1SLuis R. Rodriguez 	case NL80211_REGDOM_SET_BY_USER:
322251c9ba1SLuis R. Rodriguez 		if (ath_reg_dyn_country_user_allow(reg))
323251c9ba1SLuis R. Rodriguez 			ath_force_clear_no_ir_chan(wiphy, ch);
324251c9ba1SLuis R. Rodriguez 		break;
32507782d94SLuis R. Rodriguez 	default:
32607782d94SLuis R. Rodriguez 		if (ch->beacon_found)
32707782d94SLuis R. Rodriguez 			ch->flags &= ~IEEE80211_CHAN_NO_IR;
32807782d94SLuis R. Rodriguez 	}
32907782d94SLuis R. Rodriguez }
33007782d94SLuis R. Rodriguez 
3313a702e49SBob Copeland /*
3326c3af588SLuis R. Rodriguez  * These exception rules do not apply radar frequencies.
3333a702e49SBob Copeland  *
3346c3af588SLuis R. Rodriguez  * - We enable initiating radiation if the country IE says its fine:
3353a702e49SBob Copeland  * - If no country IE has been processed and a we determine we have
3366c3af588SLuis R. Rodriguez  *   received a beacon on a channel we can enable initiating radiation.
3373a702e49SBob Copeland  */
3386b2b2ffbSLuis R. Rodriguez static void
ath_reg_apply_beaconing_flags(struct wiphy * wiphy,struct ath_regulatory * reg,enum nl80211_reg_initiator initiator)3396b2b2ffbSLuis R. Rodriguez ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
340251c9ba1SLuis R. Rodriguez 			      struct ath_regulatory *reg,
3413a702e49SBob Copeland 			      enum nl80211_reg_initiator initiator)
3423a702e49SBob Copeland {
34357fbcce3SJohannes Berg 	enum nl80211_band band;
3443a702e49SBob Copeland 	struct ieee80211_supported_band *sband;
3453a702e49SBob Copeland 	struct ieee80211_channel *ch;
3463a702e49SBob Copeland 	unsigned int i;
3473a702e49SBob Copeland 
34857fbcce3SJohannes Berg 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
3493a702e49SBob Copeland 		if (!wiphy->bands[band])
3503a702e49SBob Copeland 			continue;
3513a702e49SBob Copeland 		sband = wiphy->bands[band];
3523a702e49SBob Copeland 		for (i = 0; i < sband->n_channels; i++) {
3533a702e49SBob Copeland 			ch = &sband->channels[i];
354251c9ba1SLuis R. Rodriguez 			__ath_reg_apply_beaconing_flags(wiphy, reg,
355251c9ba1SLuis R. Rodriguez 							initiator, ch);
3563a702e49SBob Copeland 		}
3573a702e49SBob Copeland 	}
3583a702e49SBob Copeland }
3593a702e49SBob Copeland 
360bc0aa069SLuis R. Rodriguez /**
361f33cbc4fSLuis R. Rodriguez  * ath_reg_apply_ir_flags()
362bc0aa069SLuis R. Rodriguez  * @wiphy: the wiphy to use
363aed7ee04SLee Jones  * @reg: regulatory structure - used for country selection
364bc0aa069SLuis R. Rodriguez  * @initiator: the regulatory hint initiator
365bc0aa069SLuis R. Rodriguez  *
366d44040deSLuis R. Rodriguez  * If no country IE has been received always enable passive scan
367d44040deSLuis R. Rodriguez  * and no-ibss on these channels. This is only done for specific
368d44040deSLuis R. Rodriguez  * regulatory SKUs.
369bc0aa069SLuis R. Rodriguez  *
37025985edcSLucas De Marchi  * If a country IE has been received check its rule for this
3713a702e49SBob Copeland  * channel first before enabling active scan. The passive scan
3723a702e49SBob Copeland  * would have been enforced by the initial processing of our
3733a702e49SBob Copeland  * custom regulatory domain.
3743a702e49SBob Copeland  */
375bc0aa069SLuis R. Rodriguez static void
ath_reg_apply_ir_flags(struct wiphy * wiphy,struct ath_regulatory * reg,enum nl80211_reg_initiator initiator)376f33cbc4fSLuis R. Rodriguez ath_reg_apply_ir_flags(struct wiphy *wiphy,
377251c9ba1SLuis R. Rodriguez 		       struct ath_regulatory *reg,
378bc0aa069SLuis R. Rodriguez 		       enum nl80211_reg_initiator initiator)
379bc0aa069SLuis R. Rodriguez {
380bc0aa069SLuis R. Rodriguez 	struct ieee80211_supported_band *sband;
3813a702e49SBob Copeland 
38257fbcce3SJohannes Berg 	sband = wiphy->bands[NL80211_BAND_2GHZ];
383bc0aa069SLuis R. Rodriguez 	if (!sband)
384bc0aa069SLuis R. Rodriguez 		return;
3853a702e49SBob Copeland 
386bc0aa069SLuis R. Rodriguez 	switch(initiator) {
387bc0aa069SLuis R. Rodriguez 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
388bc0aa069SLuis R. Rodriguez 		ath_force_clear_no_ir_freq(wiphy, 2467);
389bc0aa069SLuis R. Rodriguez 		ath_force_clear_no_ir_freq(wiphy, 2472);
390bc0aa069SLuis R. Rodriguez 		break;
391251c9ba1SLuis R. Rodriguez 	case NL80211_REGDOM_SET_BY_USER:
392251c9ba1SLuis R. Rodriguez 		if (!ath_reg_dyn_country_user_allow(reg))
393251c9ba1SLuis R. Rodriguez 			break;
394251c9ba1SLuis R. Rodriguez 		ath_force_clear_no_ir_freq(wiphy, 2467);
395251c9ba1SLuis R. Rodriguez 		ath_force_clear_no_ir_freq(wiphy, 2472);
396251c9ba1SLuis R. Rodriguez 		break;
397bc0aa069SLuis R. Rodriguez 	default:
398bc0aa069SLuis R. Rodriguez 		ath_force_no_ir_freq(wiphy, 2467);
399bc0aa069SLuis R. Rodriguez 		ath_force_no_ir_freq(wiphy, 2472);
4003a702e49SBob Copeland 	}
4013a702e49SBob Copeland }
4023a702e49SBob Copeland 
403c0c345d4SMohammed Shafi Shajakhan /* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */
ath_reg_apply_radar_flags(struct wiphy * wiphy,struct ath_regulatory * reg)404c0c345d4SMohammed Shafi Shajakhan static void ath_reg_apply_radar_flags(struct wiphy *wiphy,
405c0c345d4SMohammed Shafi Shajakhan 				      struct ath_regulatory *reg)
4063a702e49SBob Copeland {
4073a702e49SBob Copeland 	struct ieee80211_supported_band *sband;
4083a702e49SBob Copeland 	struct ieee80211_channel *ch;
4093a702e49SBob Copeland 	unsigned int i;
4103a702e49SBob Copeland 
41157fbcce3SJohannes Berg 	if (!wiphy->bands[NL80211_BAND_5GHZ])
4123a702e49SBob Copeland 		return;
4133a702e49SBob Copeland 
41457fbcce3SJohannes Berg 	sband = wiphy->bands[NL80211_BAND_5GHZ];
4153a702e49SBob Copeland 
4163a702e49SBob Copeland 	for (i = 0; i < sband->n_channels; i++) {
4173a702e49SBob Copeland 		ch = &sband->channels[i];
418c0c345d4SMohammed Shafi Shajakhan 		if (!ath_is_radar_freq(ch->center_freq, reg))
4193a702e49SBob Copeland 			continue;
4203a702e49SBob Copeland 		/* We always enable radar detection/DFS on this
4213a702e49SBob Copeland 		 * frequency range. Additionally we also apply on
4223a702e49SBob Copeland 		 * this frequency range:
4233a702e49SBob Copeland 		 * - If STA mode does not yet have DFS supports disable
4243a702e49SBob Copeland 		 *   active scanning
4253a702e49SBob Copeland 		 * - If adhoc mode does not support DFS yet then
4263a702e49SBob Copeland 		 *   disable adhoc in the frequency.
4273a702e49SBob Copeland 		 * - If AP mode does not yet support radar detection/DFS
4283a702e49SBob Copeland 		 *   do not allow AP mode
4293a702e49SBob Copeland 		 */
4303a702e49SBob Copeland 		if (!(ch->flags & IEEE80211_CHAN_DISABLED))
4313a702e49SBob Copeland 			ch->flags |= IEEE80211_CHAN_RADAR |
4328fe02e16SLuis R. Rodriguez 				     IEEE80211_CHAN_NO_IR;
4333a702e49SBob Copeland 	}
4343a702e49SBob Copeland }
4353a702e49SBob Copeland 
ath_reg_apply_world_flags(struct wiphy * wiphy,enum nl80211_reg_initiator initiator,struct ath_regulatory * reg)436e3bb249bSBob Copeland static void ath_reg_apply_world_flags(struct wiphy *wiphy,
4373a702e49SBob Copeland 				      enum nl80211_reg_initiator initiator,
4383a702e49SBob Copeland 				      struct ath_regulatory *reg)
4393a702e49SBob Copeland {
440ef8c0017SKalle Valo 	switch (reg->regpair->reg_domain) {
4413a702e49SBob Copeland 	case 0x60:
4423a702e49SBob Copeland 	case 0x63:
4433a702e49SBob Copeland 	case 0x66:
4443a702e49SBob Copeland 	case 0x67:
4452290a9c3SLuis R. Rodriguez 	case 0x6C:
446251c9ba1SLuis R. Rodriguez 		ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
4473a702e49SBob Copeland 		break;
4483a702e49SBob Copeland 	case 0x68:
449251c9ba1SLuis R. Rodriguez 		ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
450251c9ba1SLuis R. Rodriguez 		ath_reg_apply_ir_flags(wiphy, reg, initiator);
4513a702e49SBob Copeland 		break;
452251c9ba1SLuis R. Rodriguez 	default:
453251c9ba1SLuis R. Rodriguez 		if (ath_reg_dyn_country_user_allow(reg))
454251c9ba1SLuis R. Rodriguez 			ath_reg_apply_beaconing_flags(wiphy, reg, initiator);
4553a702e49SBob Copeland 	}
4563a702e49SBob Copeland }
4573a702e49SBob Copeland 
ath_regd_find_country_by_name(char * alpha2)458d291d8e0SMichal Kazior u16 ath_regd_find_country_by_name(char *alpha2)
459de1c732bSLuis R. Rodriguez {
460de1c732bSLuis R. Rodriguez 	unsigned int i;
461de1c732bSLuis R. Rodriguez 
462de1c732bSLuis R. Rodriguez 	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
463de1c732bSLuis R. Rodriguez 		if (!memcmp(allCountries[i].isoName, alpha2, 2))
464de1c732bSLuis R. Rodriguez 			return allCountries[i].countryCode;
465de1c732bSLuis R. Rodriguez 	}
466de1c732bSLuis R. Rodriguez 
467de1c732bSLuis R. Rodriguez 	return -1;
468de1c732bSLuis R. Rodriguez }
469d291d8e0SMichal Kazior EXPORT_SYMBOL(ath_regd_find_country_by_name);
470de1c732bSLuis R. Rodriguez 
__ath_reg_dyn_country(struct wiphy * wiphy,struct ath_regulatory * reg,struct regulatory_request * request)4718a3b6c80SLuis R. Rodriguez static int __ath_reg_dyn_country(struct wiphy *wiphy,
4728a3b6c80SLuis R. Rodriguez 				 struct ath_regulatory *reg,
4738a3b6c80SLuis R. Rodriguez 				 struct regulatory_request *request)
4748a3b6c80SLuis R. Rodriguez {
4758a3b6c80SLuis R. Rodriguez 	u16 country_code;
4768a3b6c80SLuis R. Rodriguez 
4773e850eddSLuis R. Rodriguez 	if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
4783e850eddSLuis R. Rodriguez 	    !ath_is_world_regd(reg))
4798a3b6c80SLuis R. Rodriguez 		return -EINVAL;
4808a3b6c80SLuis R. Rodriguez 
4818a3b6c80SLuis R. Rodriguez 	country_code = ath_regd_find_country_by_name(request->alpha2);
4828a3b6c80SLuis R. Rodriguez 	if (country_code == (u16) -1)
4838a3b6c80SLuis R. Rodriguez 		return -EINVAL;
4848a3b6c80SLuis R. Rodriguez 
4858a3b6c80SLuis R. Rodriguez 	reg->current_rd = COUNTRY_ERD_FLAG;
4868a3b6c80SLuis R. Rodriguez 	reg->current_rd |= country_code;
4878a3b6c80SLuis R. Rodriguez 
4888a3b6c80SLuis R. Rodriguez 	__ath_regd_init(reg);
4898a3b6c80SLuis R. Rodriguez 
4908a3b6c80SLuis R. Rodriguez 	ath_reg_apply_world_flags(wiphy, request->initiator, reg);
4918a3b6c80SLuis R. Rodriguez 
4928a3b6c80SLuis R. Rodriguez 	return 0;
4938a3b6c80SLuis R. Rodriguez }
4948a3b6c80SLuis R. Rodriguez 
ath_reg_dyn_country(struct wiphy * wiphy,struct ath_regulatory * reg,struct regulatory_request * request)4958a3b6c80SLuis R. Rodriguez static void ath_reg_dyn_country(struct wiphy *wiphy,
4968a3b6c80SLuis R. Rodriguez 				struct ath_regulatory *reg,
4978a3b6c80SLuis R. Rodriguez 				struct regulatory_request *request)
4988a3b6c80SLuis R. Rodriguez {
4998a3b6c80SLuis R. Rodriguez 	if (__ath_reg_dyn_country(wiphy, reg, request))
5008a3b6c80SLuis R. Rodriguez 		return;
5018a3b6c80SLuis R. Rodriguez 
5028a3b6c80SLuis R. Rodriguez 	printk(KERN_DEBUG "ath: regdomain 0x%0x "
5038a3b6c80SLuis R. Rodriguez 			  "dynamically updated by %s\n",
5048a3b6c80SLuis R. Rodriguez 	       reg->current_rd,
5058a3b6c80SLuis R. Rodriguez 	       reg_initiator_name(request->initiator));
5068a3b6c80SLuis R. Rodriguez }
5078a3b6c80SLuis R. Rodriguez 
ath_reg_notifier_apply(struct wiphy * wiphy,struct regulatory_request * request,struct ath_regulatory * reg)5080c0280bdSLuis R. Rodriguez void ath_reg_notifier_apply(struct wiphy *wiphy,
5096b2b2ffbSLuis R. Rodriguez 			    struct regulatory_request *request,
5106b2b2ffbSLuis R. Rodriguez 			    struct ath_regulatory *reg)
5113a702e49SBob Copeland {
512de1c732bSLuis R. Rodriguez 	struct ath_common *common = container_of(reg, struct ath_common,
513de1c732bSLuis R. Rodriguez 						 regulatory);
5143a702e49SBob Copeland 	/* We always apply this */
515c0c345d4SMohammed Shafi Shajakhan 	ath_reg_apply_radar_flags(wiphy, reg);
5163a702e49SBob Copeland 
517931299cfSLuis R. Rodriguez 	/*
518931299cfSLuis R. Rodriguez 	 * This would happen when we have sent a custom regulatory request
519931299cfSLuis R. Rodriguez 	 * a world regulatory domain and the scheduler hasn't yet processed
520931299cfSLuis R. Rodriguez 	 * any pending requests in the queue.
521931299cfSLuis R. Rodriguez 	 */
522931299cfSLuis R. Rodriguez 	if (!request)
5230c0280bdSLuis R. Rodriguez 		return;
524931299cfSLuis R. Rodriguez 
52594e05900SFelix Fietkau 	reg->region = request->dfs_region;
5263a702e49SBob Copeland 	switch (request->initiator) {
5273a702e49SBob Copeland 	case NL80211_REGDOM_SET_BY_CORE:
528de1c732bSLuis R. Rodriguez 		/*
529de1c732bSLuis R. Rodriguez 		 * If common->reg_world_copy is world roaming it means we *were*
530de1c732bSLuis R. Rodriguez 		 * world roaming... so we now have to restore that data.
531de1c732bSLuis R. Rodriguez 		 */
532de1c732bSLuis R. Rodriguez 		if (!ath_is_world_regd(&common->reg_world_copy))
533de1c732bSLuis R. Rodriguez 			break;
534de1c732bSLuis R. Rodriguez 
535de1c732bSLuis R. Rodriguez 		memcpy(reg, &common->reg_world_copy,
536de1c732bSLuis R. Rodriguez 		       sizeof(struct ath_regulatory));
537de1c732bSLuis R. Rodriguez 		break;
538de1c732bSLuis R. Rodriguez 	case NL80211_REGDOM_SET_BY_DRIVER:
5394da225bbSLuis R. Rodriguez 		break;
5403a702e49SBob Copeland 	case NL80211_REGDOM_SET_BY_USER:
541ba94c049SLuis R. Rodriguez 		if (ath_reg_dyn_country_user_allow(reg))
542ba94c049SLuis R. Rodriguez 			ath_reg_dyn_country(wiphy, reg, request);
5433a702e49SBob Copeland 		break;
5443a702e49SBob Copeland 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
5458a3b6c80SLuis R. Rodriguez 		ath_reg_dyn_country(wiphy, reg, request);
5463a702e49SBob Copeland 		break;
5473a702e49SBob Copeland 	}
5483a702e49SBob Copeland }
5493a702e49SBob Copeland EXPORT_SYMBOL(ath_reg_notifier_apply);
5503a702e49SBob Copeland 
ath_regd_is_eeprom_valid(struct ath_regulatory * reg)551e3bb249bSBob Copeland static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
5523a702e49SBob Copeland {
5533a702e49SBob Copeland 	u16 rd = ath_regd_get_eepromRD(reg);
5543a702e49SBob Copeland 	int i;
5553a702e49SBob Copeland 
5563a702e49SBob Copeland 	if (rd & COUNTRY_ERD_FLAG) {
5573a702e49SBob Copeland 		/* EEPROM value is a country code */
5583a702e49SBob Copeland 		u16 cc = rd & ~COUNTRY_ERD_FLAG;
559e03e5ffdSLuis R. Rodriguez 		printk(KERN_DEBUG
560e03e5ffdSLuis R. Rodriguez 		       "ath: EEPROM indicates we should expect "
561e03e5ffdSLuis R. Rodriguez 			"a country code\n");
5623a702e49SBob Copeland 		for (i = 0; i < ARRAY_SIZE(allCountries); i++)
5633a702e49SBob Copeland 			if (allCountries[i].countryCode == cc)
5643a702e49SBob Copeland 				return true;
5653a702e49SBob Copeland 	} else {
5663a702e49SBob Copeland 		/* EEPROM value is a regpair value */
567e03e5ffdSLuis R. Rodriguez 		if (rd != CTRY_DEFAULT)
568e03e5ffdSLuis R. Rodriguez 			printk(KERN_DEBUG "ath: EEPROM indicates we "
569e03e5ffdSLuis R. Rodriguez 			       "should expect a direct regpair map\n");
5703a702e49SBob Copeland 		for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
571ef8c0017SKalle Valo 			if (regDomainPairs[i].reg_domain == rd)
5723a702e49SBob Copeland 				return true;
5733a702e49SBob Copeland 	}
5743a702e49SBob Copeland 	printk(KERN_DEBUG
5753a702e49SBob Copeland 		 "ath: invalid regulatory domain/country code 0x%x\n", rd);
5763a702e49SBob Copeland 	return false;
5773a702e49SBob Copeland }
5783a702e49SBob Copeland 
5793a702e49SBob Copeland /* EEPROM country code to regpair mapping */
5803a702e49SBob Copeland static struct country_code_to_enum_rd*
ath_regd_find_country(u16 countryCode)5813a702e49SBob Copeland ath_regd_find_country(u16 countryCode)
5823a702e49SBob Copeland {
5833a702e49SBob Copeland 	int i;
5843a702e49SBob Copeland 
5853a702e49SBob Copeland 	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
5863a702e49SBob Copeland 		if (allCountries[i].countryCode == countryCode)
5873a702e49SBob Copeland 			return &allCountries[i];
5883a702e49SBob Copeland 	}
5893a702e49SBob Copeland 	return NULL;
5903a702e49SBob Copeland }
5913a702e49SBob Copeland 
5923a702e49SBob Copeland /* EEPROM rd code to regpair mapping */
5933a702e49SBob Copeland static struct country_code_to_enum_rd*
ath_regd_find_country_by_rd(int regdmn)5943a702e49SBob Copeland ath_regd_find_country_by_rd(int regdmn)
5953a702e49SBob Copeland {
5963a702e49SBob Copeland 	int i;
5973a702e49SBob Copeland 
5983a702e49SBob Copeland 	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
5993a702e49SBob Copeland 		if (allCountries[i].regDmnEnum == regdmn)
6003a702e49SBob Copeland 			return &allCountries[i];
6013a702e49SBob Copeland 	}
6023a702e49SBob Copeland 	return NULL;
6033a702e49SBob Copeland }
6043a702e49SBob Copeland 
6053a702e49SBob Copeland /* Returns the map of the EEPROM set RD to a country code */
ath_regd_get_default_country(u16 rd)6063a702e49SBob Copeland static u16 ath_regd_get_default_country(u16 rd)
6073a702e49SBob Copeland {
6083a702e49SBob Copeland 	if (rd & COUNTRY_ERD_FLAG) {
6093a702e49SBob Copeland 		struct country_code_to_enum_rd *country = NULL;
6103a702e49SBob Copeland 		u16 cc = rd & ~COUNTRY_ERD_FLAG;
6113a702e49SBob Copeland 
6123a702e49SBob Copeland 		country = ath_regd_find_country(cc);
6133a702e49SBob Copeland 		if (country != NULL)
6143a702e49SBob Copeland 			return cc;
6153a702e49SBob Copeland 	}
6163a702e49SBob Copeland 
6173a702e49SBob Copeland 	return CTRY_DEFAULT;
6183a702e49SBob Copeland }
6193a702e49SBob Copeland 
6203a702e49SBob Copeland static struct reg_dmn_pair_mapping*
ath_get_regpair(int regdmn)6213a702e49SBob Copeland ath_get_regpair(int regdmn)
6223a702e49SBob Copeland {
6233a702e49SBob Copeland 	int i;
6243a702e49SBob Copeland 
6253a702e49SBob Copeland 	if (regdmn == NO_ENUMRD)
6263a702e49SBob Copeland 		return NULL;
6273a702e49SBob Copeland 	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
628ef8c0017SKalle Valo 		if (regDomainPairs[i].reg_domain == regdmn)
6293a702e49SBob Copeland 			return &regDomainPairs[i];
6303a702e49SBob Copeland 	}
6313a702e49SBob Copeland 	return NULL;
6323a702e49SBob Copeland }
6333a702e49SBob Copeland 
6346b2b2ffbSLuis R. Rodriguez static int
ath_regd_init_wiphy(struct ath_regulatory * reg,struct wiphy * wiphy,void (* reg_notifier)(struct wiphy * wiphy,struct regulatory_request * request))6356b2b2ffbSLuis R. Rodriguez ath_regd_init_wiphy(struct ath_regulatory *reg,
6366b2b2ffbSLuis R. Rodriguez 		    struct wiphy *wiphy,
6370c0280bdSLuis R. Rodriguez 		    void (*reg_notifier)(struct wiphy *wiphy,
638e3bb249bSBob Copeland 					 struct regulatory_request *request))
639e3bb249bSBob Copeland {
640e3bb249bSBob Copeland 	const struct ieee80211_regdomain *regd;
641e3bb249bSBob Copeland 
642e3bb249bSBob Copeland 	wiphy->reg_notifier = reg_notifier;
6438fc68580SLuis R. Rodriguez 	wiphy->regulatory_flags |= REGULATORY_STRICT_REG |
6448fc68580SLuis R. Rodriguez 				   REGULATORY_CUSTOM_REG;
645e3bb249bSBob Copeland 
646e3bb249bSBob Copeland 	if (ath_is_world_regd(reg)) {
647e3bb249bSBob Copeland 		/*
648e3bb249bSBob Copeland 		 * Anything applied here (prior to wiphy registration) gets
649e3bb249bSBob Copeland 		 * saved on the wiphy orig_* parameters
650e3bb249bSBob Copeland 		 */
651e3bb249bSBob Copeland 		regd = ath_world_regdomain(reg);
6528fc68580SLuis R. Rodriguez 		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER;
653e3bb249bSBob Copeland 	} else {
654e3bb249bSBob Copeland 		/*
65525985edcSLucas De Marchi 		 * This gets applied in the case of the absence of CRDA,
656e3bb249bSBob Copeland 		 * it's our own custom world regulatory domain, similar to
657e3bb249bSBob Copeland 		 * cfg80211's but we enable passive scanning.
658e3bb249bSBob Copeland 		 */
659e3bb249bSBob Copeland 		regd = ath_default_world_regdomain();
660e3bb249bSBob Copeland 	}
6618fc68580SLuis R. Rodriguez 
662e3bb249bSBob Copeland 	wiphy_apply_custom_regulatory(wiphy, regd);
663c0c345d4SMohammed Shafi Shajakhan 	ath_reg_apply_radar_flags(wiphy, reg);
664e3bb249bSBob Copeland 	ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
665e3bb249bSBob Copeland 	return 0;
666e3bb249bSBob Copeland }
667e3bb249bSBob Copeland 
6685d2214acSLuis R. Rodriguez /*
6695d2214acSLuis R. Rodriguez  * Some users have reported their EEPROM programmed with
670*1ec7ed51SBrian Norris  * 0x8000 set, this is not a supported regulatory domain
671*1ec7ed51SBrian Norris  * but since we have more than one user with it we need
672*1ec7ed51SBrian Norris  * a solution for them. We default to 0x64, which is the
673*1ec7ed51SBrian Norris  * default Atheros world regulatory domain.
6745d2214acSLuis R. Rodriguez  */
ath_regd_sanitize(struct ath_regulatory * reg)6755d2214acSLuis R. Rodriguez static void ath_regd_sanitize(struct ath_regulatory *reg)
6765d2214acSLuis R. Rodriguez {
677*1ec7ed51SBrian Norris 	if (reg->current_rd != COUNTRY_ERD_FLAG)
6785d2214acSLuis R. Rodriguez 		return;
6795d2214acSLuis R. Rodriguez 	printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n");
6805d2214acSLuis R. Rodriguez 	reg->current_rd = 0x64;
6815d2214acSLuis R. Rodriguez }
6825d2214acSLuis R. Rodriguez 
__ath_regd_init(struct ath_regulatory * reg)68343fcb430SLuis R. Rodriguez static int __ath_regd_init(struct ath_regulatory *reg)
6843a702e49SBob Copeland {
6853a702e49SBob Copeland 	struct country_code_to_enum_rd *country = NULL;
6863a702e49SBob Copeland 	u16 regdmn;
6873a702e49SBob Copeland 
688e03e5ffdSLuis R. Rodriguez 	if (!reg)
689e03e5ffdSLuis R. Rodriguez 		return -EINVAL;
690e03e5ffdSLuis R. Rodriguez 
6915d2214acSLuis R. Rodriguez 	ath_regd_sanitize(reg);
6925d2214acSLuis R. Rodriguez 
693e03e5ffdSLuis R. Rodriguez 	printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
694e03e5ffdSLuis R. Rodriguez 
6953a702e49SBob Copeland 	if (!ath_regd_is_eeprom_valid(reg)) {
696516304b0SJoe Perches 		pr_err("Invalid EEPROM contents\n");
6973a702e49SBob Copeland 		return -EINVAL;
6983a702e49SBob Copeland 	}
6993a702e49SBob Copeland 
7003a702e49SBob Copeland 	regdmn = ath_regd_get_eepromRD(reg);
7013a702e49SBob Copeland 	reg->country_code = ath_regd_get_default_country(regdmn);
7023a702e49SBob Copeland 
7033a702e49SBob Copeland 	if (reg->country_code == CTRY_DEFAULT &&
704e03e5ffdSLuis R. Rodriguez 	    regdmn == CTRY_DEFAULT) {
705e03e5ffdSLuis R. Rodriguez 		printk(KERN_DEBUG "ath: EEPROM indicates default "
706e03e5ffdSLuis R. Rodriguez 		       "country code should be used\n");
7073a702e49SBob Copeland 		reg->country_code = CTRY_UNITED_STATES;
708e03e5ffdSLuis R. Rodriguez 	}
7093a702e49SBob Copeland 
7103a702e49SBob Copeland 	if (reg->country_code == CTRY_DEFAULT) {
7113a702e49SBob Copeland 		country = NULL;
7123a702e49SBob Copeland 	} else {
713e03e5ffdSLuis R. Rodriguez 		printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
714e03e5ffdSLuis R. Rodriguez 		       "map search\n");
7153a702e49SBob Copeland 		country = ath_regd_find_country(reg->country_code);
7163a702e49SBob Copeland 		if (country == NULL) {
7173a702e49SBob Copeland 			printk(KERN_DEBUG
718e03e5ffdSLuis R. Rodriguez 				"ath: no valid country maps found for "
719e03e5ffdSLuis R. Rodriguez 				"country code: 0x%0x\n",
7203a702e49SBob Copeland 				reg->country_code);
7213a702e49SBob Copeland 			return -EINVAL;
722e03e5ffdSLuis R. Rodriguez 		} else {
7233a702e49SBob Copeland 			regdmn = country->regDmnEnum;
724e03e5ffdSLuis R. Rodriguez 			printk(KERN_DEBUG "ath: country maps to "
725e03e5ffdSLuis R. Rodriguez 			       "regdmn code: 0x%0x\n",
726e03e5ffdSLuis R. Rodriguez 			       regdmn);
727e03e5ffdSLuis R. Rodriguez 		}
7283a702e49SBob Copeland 	}
7293a702e49SBob Copeland 
7303a702e49SBob Copeland 	reg->regpair = ath_get_regpair(regdmn);
7313a702e49SBob Copeland 
7323a702e49SBob Copeland 	if (!reg->regpair) {
7333a702e49SBob Copeland 		printk(KERN_DEBUG "ath: "
7343a702e49SBob Copeland 			"No regulatory domain pair found, cannot continue\n");
7353a702e49SBob Copeland 		return -EINVAL;
7363a702e49SBob Copeland 	}
7373a702e49SBob Copeland 
7383a702e49SBob Copeland 	if (!country)
7393a702e49SBob Copeland 		country = ath_regd_find_country_by_rd(regdmn);
7403a702e49SBob Copeland 
7413a702e49SBob Copeland 	if (country) {
7423a702e49SBob Copeland 		reg->alpha2[0] = country->isoName[0];
7433a702e49SBob Copeland 		reg->alpha2[1] = country->isoName[1];
7443a702e49SBob Copeland 	} else {
7453a702e49SBob Copeland 		reg->alpha2[0] = '0';
7463a702e49SBob Copeland 		reg->alpha2[1] = '0';
7473a702e49SBob Copeland 	}
7483a702e49SBob Copeland 
7493a702e49SBob Copeland 	printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
7503a702e49SBob Copeland 		reg->alpha2[0], reg->alpha2[1]);
751e03e5ffdSLuis R. Rodriguez 	printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
752ef8c0017SKalle Valo 		reg->regpair->reg_domain);
7533a702e49SBob Copeland 
75443fcb430SLuis R. Rodriguez 	return 0;
75543fcb430SLuis R. Rodriguez }
75643fcb430SLuis R. Rodriguez 
75743fcb430SLuis R. Rodriguez int
ath_regd_init(struct ath_regulatory * reg,struct wiphy * wiphy,void (* reg_notifier)(struct wiphy * wiphy,struct regulatory_request * request))75843fcb430SLuis R. Rodriguez ath_regd_init(struct ath_regulatory *reg,
75943fcb430SLuis R. Rodriguez 	      struct wiphy *wiphy,
7600c0280bdSLuis R. Rodriguez 	      void (*reg_notifier)(struct wiphy *wiphy,
76143fcb430SLuis R. Rodriguez 				   struct regulatory_request *request))
76243fcb430SLuis R. Rodriguez {
763de1c732bSLuis R. Rodriguez 	struct ath_common *common = container_of(reg, struct ath_common,
764de1c732bSLuis R. Rodriguez 						 regulatory);
76543fcb430SLuis R. Rodriguez 	int r;
76643fcb430SLuis R. Rodriguez 
76743fcb430SLuis R. Rodriguez 	r = __ath_regd_init(reg);
76843fcb430SLuis R. Rodriguez 	if (r)
76943fcb430SLuis R. Rodriguez 		return r;
77043fcb430SLuis R. Rodriguez 
771de1c732bSLuis R. Rodriguez 	if (ath_is_world_regd(reg))
772de1c732bSLuis R. Rodriguez 		memcpy(&common->reg_world_copy, reg,
773de1c732bSLuis R. Rodriguez 		       sizeof(struct ath_regulatory));
774de1c732bSLuis R. Rodriguez 
775e3bb249bSBob Copeland 	ath_regd_init_wiphy(reg, wiphy, reg_notifier);
77643fcb430SLuis R. Rodriguez 
7773a702e49SBob Copeland 	return 0;
7783a702e49SBob Copeland }
7793a702e49SBob Copeland EXPORT_SYMBOL(ath_regd_init);
7803a702e49SBob Copeland 
ath_regd_get_band_ctl(struct ath_regulatory * reg,enum nl80211_band band)7813a702e49SBob Copeland u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
78257fbcce3SJohannes Berg 			  enum nl80211_band band)
7833a702e49SBob Copeland {
7843a702e49SBob Copeland 	if (!reg->regpair ||
7853a702e49SBob Copeland 	    (reg->country_code == CTRY_DEFAULT &&
7863a702e49SBob Copeland 	     is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
7873a702e49SBob Copeland 		return SD_NO_CTL;
7883a702e49SBob Copeland 	}
7893a702e49SBob Copeland 
79094e05900SFelix Fietkau 	if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) {
79194e05900SFelix Fietkau 		switch (reg->region) {
79294e05900SFelix Fietkau 		case NL80211_DFS_FCC:
79394e05900SFelix Fietkau 			return CTL_FCC;
79494e05900SFelix Fietkau 		case NL80211_DFS_ETSI:
79594e05900SFelix Fietkau 			return CTL_ETSI;
79694e05900SFelix Fietkau 		case NL80211_DFS_JP:
79794e05900SFelix Fietkau 			return CTL_MKK;
79894e05900SFelix Fietkau 		default:
79994e05900SFelix Fietkau 			break;
80094e05900SFelix Fietkau 		}
80194e05900SFelix Fietkau 	}
80294e05900SFelix Fietkau 
8033a702e49SBob Copeland 	switch (band) {
80457fbcce3SJohannes Berg 	case NL80211_BAND_2GHZ:
8053a702e49SBob Copeland 		return reg->regpair->reg_2ghz_ctl;
80657fbcce3SJohannes Berg 	case NL80211_BAND_5GHZ:
8073a702e49SBob Copeland 		return reg->regpair->reg_5ghz_ctl;
8083a702e49SBob Copeland 	default:
8093a702e49SBob Copeland 		return NO_CTL;
8103a702e49SBob Copeland 	}
8113a702e49SBob Copeland }
8123a702e49SBob Copeland EXPORT_SYMBOL(ath_regd_get_band_ctl);
813